Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to replace firestore geofire with h3? #167

Open
mailinger-mate opened this issue Jan 7, 2023 · 3 comments
Open

How to replace firestore geofire with h3? #167

mailinger-mate opened this issue Jan 7, 2023 · 3 comments

Comments

@mailinger-mate
Copy link

Hello!

I am using the recommended Geofire library with the Firestore to save documents and query collections using Geohash:
https://firebase.google.com/docs/firestore/solutions/geoqueries

I have read through the issues of #100 and uber/h3#410 on using H3 with Firestore and the H3 Index structure but I still need your help with replacing the Geohash solution with H3 indexes.

I think my use case is simpler than the issues above, because I simply would like to save H3 indexes at resolution 9 on my documents, like this

setDoc(doc(db, 'stores'), { h3: '8965812cb23ffff' }); 

and just run queries to get a collection of documents that are within a hexagon at various higher resolutions:

db.collection('stores').orderBy('h3').startAt('8365aafffffffff').endAt('?');

This way I can aggregate the document count with Firestore and display the number per hexagon on a map depending on the selected location and resolution.

Could you please help me understand how could I derive the correct startAt and endAt values from a location and resolution to use them in aggregate Firestore queries?

Thank you,
Mate

@mailinger-mate
Copy link
Author

I would think the solution probably relies on the indexing order, however I need help with understanding how that is represented in the indexes between resolutions, if the lowest resolution set is continuous between startAt and endAt of higher resolutions...
https://observablehq.com/@nrabinowitz/h3-indexing-order

@mailinger-mate
Copy link
Author

mailinger-mate commented Jan 9, 2023

I have read a few more responses from @nrabinowitz Stack Overflow as well and now I think I understand that the child indexes of any hexagon are not continuous alphanumerically, and cannot be used to range queries in NoSQL databases:
https://stackoverflow.com/questions/53911322/is-the-h3index-ordered#comment95750613_53915447

Using the referenced h3 indexing order visualization I am able to extract that for the San Fransisco 8428309ffffffff hexagon the children h3 indexes at lower resolution cannot be described in continuous ranges:

["*807*","*80f*","*817*","*81f*","*827*","*82f*","*837*","*847*",...]

To give more context, for now using the Geofire library I am mapping the h3 hexagons to their nearest geohash [start, end] range pairs (rectangles), and then calculate and exclude for each range the geohashes that are outside the radius of the hexagon (red rectangles), specifically:

{
  "h3Index": "8665812cfffffff",
  "geohashRanges": ["w60gh","w60gk"],["w60g4","w60g6"],["w60fu","w60fw"],["w60ff","w60fh"],
  "geohashesExcluded: [["w60g5zz8ku","w60g5zz8kv"],["w60g5zz8mh","w60g5zz8mj"],["w60g5zz8kv"],["w60g5zz8mj"],["w60g5zz8kg"],["w60g5zz8m5"]]
}

rollo-h3-geohash-map

Unfortunately this results in several parallel aggregate queries, and because the rectangles will never fit the hexagons, displaying aggregate numbers of the rectangles mapped to the hexagon will always be redundant and inaccurate. Of course I could just display the geohash rectangles on the map, but the benefits of h3 indexing are more appealing both visually and computationally.

This is why I am looking for any solution where I can use h3 indexes in the database objects and query them at various resolutions in a way that are less expensive and less inaccurate relative to the current solution.

@nrabinowitz
Copy link
Collaborator

If i understand your use case correctly, I believe H3 can do what you're trying to do. While k-rings (also called grid disks, the set of cells within k steps of some origin) are not ordered sequentially, children at a given resolution are. You can request the range of children at some res with the lower bound as cellToCenterChild(res); the upper bound is a little tricker until we release childPosToCell but you can construct it. This is harder in JS, because we can't use 64-bit ints, but essentially you apply a bitmask of all 1s to the bottom N bits of the index, where N is 3 * (15 - parentRes) (I think, I haven't tested this). The bit layout diagrams here might help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants