Reputation: 1174
I am looking at a pythonic implementation of this top rated accepted answer on GIS SE - Using geohash for proximity searches? and I am unable to retrieve any matches for my geohash query. Here is the approach I have tried so far.
To run this Minimum Verifiable Complete Example(MVCE) you need to download the following files - geohash int and sortedlist python and install the python sortedlist via pip. You also need to have the latest version of Cython installed on your machine so as to wrap the C functionality of geohash-int(Note I am only wrapping what is necessary for this MVCE).
geohash_test.py
# GeoHash is my Cython wrapper of geohash-int C package
from geo import GeoHash
from sortedcontainers import SortedList
import numpy as np
def main():
# Bounding coordinates of my grid.
minLat = 27.401436
maxLat = 62.54858
minLo = -180.0
maxLo = 179.95000000000002
latGrid = np.arange(minLat,maxLat,0.05)
lonGrid = np.arange(minLo,maxLo,0.05)
geoHash = GeoHash()
# Create my own data set of points with a resolution of
# 0.05 in the latitude and longitude direction.
gridLon,gridLat = np.meshgrid(lonGrid,latGrid)
grid_points = np.c_[gridLon.ravel(),gridLat.ravel()]
sl = SortedList()
#Store my grid points in the best resolution possible i.e. 52(First step in accepted answer)
for grid_point in grid_points:
lon = grid_point[0]
lat = grid_point[1]
geohash = geoHash.encode(lat,lon,52)
bitsOriginal = geohash["bits"]
sl.add(bitsOriginal)
#Derive the minimum and maximum value for the range query from method below
minValue,maxValue = getMinMaxForQueryGeoHash(geoHash)
# Do the actual range query with a sorted list
it = sl.irange(minValue,maxValue,inclusive=(False,False))
print(len(list(it)))
def getMinMaxForQueryGeoHash(geoHash):
lonTest = 172.76843
latTest = 61.560745
#Query geohash encoded at resolution 26 because my search area
# is around 10 kms.(Step 2 and 3 in accepted answer)
queryGeoHash = geoHash.encode(latTest,lonTest,26)
# Step 4 is getting the neighbors for query geohash
neighbors = geoHash.get_neighbors(queryGeoHash)
bitsList = []
for key,value in neighbors.items():
bitsList.append(value["bits"])
#Step 5 from accepted answer
bitsList.append(queryGeoHash["bits"])
# Step 6 We need 1 to all the neighbors
newList = [x+1 for x in bitsList]
joinedList = bitsList + newList
#Step 7 Left bit shift this to 52
newList2 = [x <<26 for x in joinedList]
#Return min and max value to main method
minValue = min(newList2)
maxValue = max(newList2)
return minValue,maxValue
main()
If one were to write this out as a pseudocode here is what I am doing
Given my bounding box which is a grid I store it in the highest resolution possible by computing the geohash for each latitude and longitude(this happens to be bit depth 52)
I add the geohash to a sorted list
Then I would like to do a range query by specifying a search radius of 10 kms for a specific query coordinate
From the accepted answer to do this you need the min and max value for a query geohash
I calculate the min and max value in the method getMinMaxForQueryGeoHash
Calculate the query geohash at bit depth 26(this is the radius of 10 kms)
Calculate the neighbors of the query geohash and create the 18 member array
The 18 members are the 8 neighbors returned from the C method plus the original query geohash and the remaining 9 are obtained by adding 1 to this array
Then left bit shift this array by 26 and return the min and max value to the irange query of sorted list.
Bit shift = 52(maximum resolution) - query geohash precision(26) = 26
But that query returns me a NULL
. Could somebody explain where I am going wrong ?
Upvotes: 1
Views: 6883
Reputation: 13930
using your jargon: for a MVCE, you not need a complex two-languages implementations. There are a lot of simple good implementations of Geohash, some in 100% Python (example). All them use the Morton Curve (example).
Conclusion: try to plug-and-play a pure-Python implementation, first test encode/decode, them test the use of neighbors(geohash)
function.
Upvotes: 3