The same 5,595 Google product categories, laid out three ways.Each panel shows the distance it actually returns.Reproducing Nickel & Kiela (2017) on a real product taxonomy, after The Geometry Mistake.
Pick a category and its chain of parent categories gets drawn and labeled in all three panels. In the hyperbolic disk that chain runs straight out from the center. In the other two it scatters, because those spaces have run out of room to keep the levels apart. Hover any dot for its name, scroll to zoom, drag to pan. The Test Results tab carries the numbers, including the two approaches we tried that lost.
The dots are only positioned in 2D so you can look at them. Every distance in the table comes from the full vector, 5 dimensions for the two trained spaces and 384 for the text model, never from where a dot happens to sit.
These are runs against the Google Product Taxonomy, which is 5,595 categories, 7 levels deep, and about 6.4 children per node.
Both geometries got the same data and the same training, and we swept the learning rate separately for each one so neither got a handicap. The only thing that changed was the geometry.
| Dimensions | Flat | Hyperbolic |
|---|---|---|
| 2 | 0.140 | 0.501 |
| 5 | 0.239 | 0.905 |
| 10 | 0.354 | 0.925 |
| 20 | 0.551 | 0.932 |
| 50 | 0.658 | 0.934 |
Hyperbolic is basically done at 5 dimensions. Everything after that is rounding. Flat keeps climbing all the way to 50 and still doesn't get there.
| Representation | Dims | MAP |
|---|---|---|
| Hyperbolic | 5 | 0.905 |
| BGE-small, full path in the text | 384 | 0.308 |
| BGE-small, name only | 384 | 0.115 |
Five numbers beat 384. The middle row is the one we didn't expect: we wrote the whole category path into the string, so the model was handed the hierarchy in plain English, and it still only got to 0.308.
| Siblings per node | 1 to 2 | 3 to 7 | 8 to 20 | 21+ |
|---|---|---|---|---|
| Hyperbolic 5d | 0.932 | 0.909 | 0.901 | 0.944 |
| Flat 5d | 0.494 | 0.440 | 0.368 | 0.195 |
| Flat 50d | 0.593 | 0.543 | 0.458 | 0.464 |
| Text 384d | 0.320 | 0.247 | 0.182 | 0.134 |
This is the table that actually explains the rest of them. Flat space gets worse the wider the tree gets, and the text embedding gets worse faster. Hyperbolic sits around 0.9 whether a category has two siblings or fifty.
| Dimensions | Flat | Hyperbolic |
|---|---|---|
| 5 | 0.457 | 0.539 |
| 10 | 0.627 | 0.532 |
| 20 | 0.806 | 0.540 |
| 50 | 0.855 | 0.541 |
Ask for the one direct parent rather than the whole ancestor set and flat wins from 10 dimensions up. Hyperbolic keeps the entire family line close together, so the real parent is nearly always in the top ten, but it's rarely first. The same thing happened on WordNet, so it's a property of the representation and not of this dataset.
Two named vectors per category, the 384d text embedding and a
5d hyperbolic one. The hyperbolic vector is small enough to keep in the
payload, which means acosh can work out the exact geodesic
inside the query itself. Prefetch on meaning, rescore on structure, one
request, nothing reranked in your application.
| Pipeline | Mean hops | Within 3 hops | Semantic kept |
|---|---|---|---|
| Text only | 44.0 | 0.347 | 0.795 |
| Hybrid | 15.2 | 0.599 | 0.752 |
| Hyperbolic only | 6.5 | 0.713 | 0.655 |
You get about 69% of the structural improvement and give up roughly 5% of the semantic relevance. Hyperbolic on its own is better structurally but drops 17%, so the blend is the one worth shipping.
| Prefetch | Mean hops | Within 3 hops | Semantic | ms |
|---|---|---|---|---|
| 10 | 43.0 | 0.357 | 0.797 | 11.6 |
| 25 | 23.1 | 0.507 | 0.771 | 15.5 |
| 50 | 16.8 | 0.573 | 0.751 | 22.2 |
| 100 | 13.2 | 0.618 | 0.735 | 34.7 |
| 200 | 13.3 | 0.635 | 0.720 | 61.2 |
| 400 | 13.6 | 0.651 | 0.706 | 113.2 |
Prefetch 100 is the sweet spot. Go deeper and you're paying double the latency for almost nothing, and mean hops stops improving anyway.
| Learning rate | MAP | Norm spread | Recall at prefetch 50 |
|---|---|---|---|
| 1 | 0.301 | 139x | 0.965 |
| 3 | 0.724 | 2,010x | 0.789 |
| 10 | 0.905 | 14,400x | 0.498 |
| 30 | 0.762 | 6,700x | 0.383 |
Turning the learning rate up pushes points towards the edge of the ball. That's what makes the hierarchy come out well, and it's also what breaks prefetch, because the term that blows up lives right there at the boundary. So the setting that wins on the benchmark is the one you'd least want to serve. We only noticed because we trained the thing and then had to index it.
| WordNet mammals | Hyperbolic got 0.949 at 5 dimensions against flat at 0.231. Flat needed 100 dimensions to reach 0.805. This is roughly what the paper reports, so the setup checks out. |
| WordNet nouns, 82k | Flat matched the paper. Our hyperbolic side came out under-trained because we used a bigger batch to fit it on a laptop, so we stopped the run rather than quote it. |
| The d+2 transform | It converts hyperbolic ranking into plain dot product, exactly. Brute force scores 0.984, and the same vectors through HNSW score 0.020. The transform leaves some vectors 600x bigger than others and the graph walk has nothing to follow. |
| Rescue attempts | Magnitude buckets got to 0.767 and clipping to 0.638. Both worked, and both still lost to plain rescoring at 0.868. |
| Geodesic comparator | 0.894 against 0.745, at lower latency. The gap got wider as the data grew rather than narrower: +3, +6, +9, +15. |
| A trap | The comparator has to be symmetric. The obvious shortcut isn't, and it drops recall from 0.92 to 0.62 without any error at all. Cost us an hour. |