OpenStreetMap User's Diaries
Forgotten Gems in Geospatial Indexing
How an algorithm from the 80s sets the new standard for modern spatial indices
Geospatial indices are all around us. They allow us to search through millions of points in an instant answering questions such as “find me the closest bike repair shop” efficiently.
And yet there are still forgotten gems in the archives of computational geometry: Space-filling curve based spatial indi
How an algorithm from the 80s sets the new standard for modern spatial indices
Geospatial indices are all around us. They allow us to search through millions of points in an instant answering questions such as “find me the closest bike repair shop” efficiently.
And yet there are still forgotten gems in the archives of computational geometry: Space-filling curve based spatial indices. With an optimization going back to the year 1981 this spatial index delivers surprising efficiency; and yet it is rarely discussed in the geospatial community.
Let’s go back in time and rediscover how we can build a spatial index on top of a space-filling curve to accelerate geospatial queries and simplify geospatial indexing for location-based applications.
Small note based on reader feedback: If you know about Z-Order Curves or Hilbert Curves already I still recommend you reading this as the post below will show you how use Z-Order Curves efficiently as a spatial index and that is something you probably don’t know yet.
The Z-Order Curve
The Z-Order Curve is one of many space-filling curves transforming multi-dimensional data into a single dimension while preserving locality. In the geospatial domain it allows us for example to transform longitude and latitude into a single number while preserving geographic proximity.
For spatial queries such as “find me the closest bike repair shop” we want to find points within a rectangular area. To search a rectangular area on the Z-Order Curve (highlighted in gray below) we start at the top left Z value of the rectangular area and walk the curve until we’re at the bottom right.
Unfortunately the Z-Order Curve exhibits discontinuities between each Z block. If we walk the curve we might accidentally come across such a discontinuity and include irrelevant ranges:
In the example above when we walk the curve we exit the rectangular area (in blue) on its right and after scanning a vast amount of irrelevant data (in red) we enter it again on the left. In practice this means for some queries our spatial index is orders of magnitudes slower having to walk through vasts amounts of irrelevant ranges.
Fortunately there is an optimization from the ’80s pruning the search space from those irrelevant ranges.
BIGMIN, Tropf and Herzog, 1981
The year is 1981 and there’s still eight years until the release of Belgian techno anthem “Pump Up the Jam”.
In 1981 Tropf and Herzog show how to immediately jump back into a rectangular area on the Z-Order Curve:
Multidimensional Range Search in Dynamically Balanced Trees, H. Tropf, H. Herzog
I won’t go into the implementation details here (see references at the end) but the next Z value that jums back into the rectangular area can be computed efficiently based on the Z-Order Curve and the query rectangular area’s top left and bottom right Z values: It’s a function of those three numbers.
This optimization, called “BIGMIN”, or in later years by others also called GetNextZ-Address, or jumpNextIn, allows us to prune the search space and turn any spatial query into a few very efficient linear memory scans.
Spatial Index: Z-Order Curve + BIGMIN
Equipped with a Z-Order Curve and the BIGMIN optimization, a spatial point index can now be implemented as follows
- Sort points by their value on the Z-Order Curve
- For a nearest neighbor query within a rectangular area
- Find the top left Z value (zmin) and bottom right Z value (zmax) e.g. with two binary searches on the sorted points (highlighted in gray below)
- Start the linear scan through the range [zmin, zmax] as all nearest neighbors are within this range by design (highlighted in blue below)
- Whenever we leave the rectangular area compute BIGMIN and immediately jump to it, skipping over irrelevant ranges (highlighted in red below)
In the example the query turns into scanning eight points in memory, then computing BIGMIN to skip over an irrelevant range, and then scanning another eight points in memory.
Building the spatial index is a simple sort. Querying the spatial index is two binary searches followed by linear memory scans and potentially binary searches when having to jump back in.
Incredibly efficient in 1981, incredibly efficient in 2025.
Summary
We’ve gone back in time and rediscovered how we can build a spatial index on top of a space-filling curve using an optimization technique from the ’80s.
The geospatial community has mostly overlooked this historical algorithm. Revisiting the Z-Order Curve based spatial index reveals its potential; and we’re only touching the surface with point queries.
There is more work to do: The Z-Order Curve and the BIGMIN optimization generalize to arbitrary dimensions. Can we make use of this e.g. to index line segments? If we index a line segment’s mid point, angle, and distance on a four dimensional Z-Order Curve we could use the very same technique to accelerate geospatial queries such as “find nearby roads pointing south-west”.
An an example while working through this I have implemented the Z-Order Curve based spatial point index in tinygraph to power a graph routing engine’s location lookups.
I encourage the geospatial community to revive this forgotton gem together.
References
On spatial search algorithms
On Z-Order Curve and its relationship to space-partitioning trees
- https://en.wikipedia.org/wiki/Z-order_curve
- https://en.wikipedia.org/wiki/Quadtree
- https://en.wikipedia.org/wiki/Quadtree#Compressed_quadtrees
Implementation in the tinygraph project
- https://github.com/tinygraph/tinygraph/pull/68
- https://github.com/tinygraph/tinygraph/issues/22
- https://github.com/tinygraph/tinygraph/issues/70
Z-Order Curves for Amazon DynamoDB
Going deeper on space-filling curve based indices
- Using a Space Filling Curve for the Management of Dynamic Point Cloud Data in a Relational DBMS 1 2 3
- Z-ordered Range Refinement for Multi-dimensional Range Queries
- Towards a general-purpose, multidimensional index: Integration, Optimization, and Enhancement of UB-Trees
Interactive Z-Order Curve visualization, the screen grabs above are from here
Implementation: BIGMIN, GetNextZ-Address, jumpNextIn in the wild