Geospatial indexing on Hilbert curves
blog.zen.ly
blog.zen.ly
That's a super cool detail! I once implemented a 2D index using a Z-Order curve that directly translated lat/lon coordinates to a linear ordering. It works well enough because nobody really lives at the poles--the search regions with a single projection get really obtuse there. Projecting the earth onto a 6-sided die is a really elegant solution to that problem! Go go Google engineering!
That said, using a cube projection has its own set of limitations and issues for advanced geospatial analytics even though it is well-behaved for sharding. Current best practice representations embed a spheroid in a synthetic 3-space and shard the 3-space, which has few edge cases to worry about and is very efficient in time and space.
Why is that?
On a more practical level, non-homeomorphic representations also create a large number of additional edge cases that need to be handled to ensure correctness, many of which are obscure and non-obvious. In most implementations (including open source), developers tend to ignore many of these defects because they rarely affect simple mapping applications -- the reason they used a projection based representation in the first place is because it was easy. For complex, massive-scale geospatial analytics, customers have an uncanny ability to find these edge cases almost immediately.
A good example is a simple algorithm I did to draw circles on a map by turning them into polygons: https://github.com/jillesvangurp/geogeometry/blob/master/src...
This works perfectly fine if you stay away from the poles but if you get close enough the circles become a bit irregular. The algorithm tries to work around some of the issues but the results don't look pretty.
Other issues I encountered were several datasources with invalid degrees due to rounding errors. This is an issue along the dateline (180 degrees longitude). E.g. 180.0000001 degrees is invalid.
Another fun edgecase in geo is null Island, a fictional island of the coast of Africa at (0,0) that has become a fun little easter egg in many datasources. A friend of mine dedicated this website to it: https://www.vicchi.org/2014/04/05/welcome-to-the-republic-of...
That's exactly the sort of thing that works well until one day it just breaks your code because you forgot to make sure never to to do a computation on a thing that includes on of the poles. And it won't happen because someone starts living there rather it will happen because of a complicated logical chain of reasons that make perfect sense, but only in hindsight.
Part 2 of Tinder post is still in my bookmarks to read, but already I am loving Zenly's in-depth analysis of their findings!
It seems that using Google's S2 library is pretty much standard for this problem, I'm curious if other companies are doing this too?
[1]https://tech.gotinder.com/geosharded-recommendations-part-1-...
Of course, it helped that most of the queries we did could be phrased like "Find all things within a fixed (and known ahead of time) radius of this point." R-trees are much more versatile, but much slower to query and much much slower to construct/maintain.
I mean, any Quad/Octree/N-dimensional equivalent can have its cells numbered by giving each quadrant/octant/each of the 2^N sub-cells a certain bit combination and then chaining those together as you descend the tree. The Hilbert curve version is just a special case of this with complicated rules for the "sub cell" <-> "bit sequence" mapping. If you were to use a Z curve, the resulting data format and querying algorithm would be exactly identical to the one in the article, just a lot less complicated in the (not presented) details of "where is this child" than the Hilbert version...
Follow up questions: How do the number of ranges compare with the different orderings? How much does having fewer range segments affect database query performance? Does it make up for the added computational complexity of Hilbert curves? I've not answers, but these can be answered by science.
I believe Microsoft SQL server uses Hilbert curves: https://docs.microsoft.com/en-us/sql/relational-databases/sp...
A hex grid is the most efficient way to pack circles and is therefore the best "pixel" type to approximate radii, so simply choosing a hex size best matching the desired query radius can give you a very fast nearest-neighbor approximation.
And H3 retains all of S2's good features like hexagons following a curve (not the Hilbert curve, though) so hexagon IDs of similar value will more than likely be near each other, making range queries from a database still useful.