Absolut kannst du. Und es kann ziemlich schnell gehen. (Die intensiven Rechenbits können AUCH verteilt werden)
Es gibt mehrere Möglichkeiten, aber eine Möglichkeit, mit der ich gearbeitet habe, besteht darin, eine geordnete Liste ganzzahliger Geohashes zu verwenden und alle nächsten Geohash-Bereiche für eine bestimmte Geohash-Auflösung zu ermitteln (die Auflösung entspricht in etwa Ihren distance
Kriterien) Abfragen dieser Geohash-Bereiche, um eine Liste von Punkten in der Nähe zu erhalten. Ich benutze dafür Redis und Nodejs (zB Javascript). Redis ist superschnell und kann geordnete Bereiche sehr schnell abrufen, kann jedoch nicht viele der Aufgaben zur Bearbeitung von Indexabfragen ausführen, die SQL-Datenbanken ausführen können.
Die Methode wird hier beschrieben: https://github.com/yinqiwen/ardb/wiki/Spatial-Index
Aber der Kern davon ist (um den Link zu paraphrasieren):
- Sie speichern alle Ihre geohashten Punkte in der bestmöglichen Auflösung (in der Regel 64-Bit-Ganzzahl, falls verfügbar, oder bei Javascript 52 Bit) in einem geordneten Satz (zset in redis). In den meisten Geohash-Bibliotheken sind heutzutage Geohash-Integer-Funktionen integriert, und Sie müssen diese anstelle der allgemeineren Base32-Geohashes verwenden.
- Basierend auf dem Radius, in dem Sie suchen möchten, müssen Sie dann eine Bittiefe / Auflösung finden, die Ihrem Suchbereich entspricht und die kleiner oder gleich Ihrer gespeicherten Geohash-Bittiefe sein muss. Die verknüpfte Site verfügt über eine Tabelle, die die Bittiefe einer Geohash mit der Begrenzungsrahmenfläche in Metern korreliert.
- Dann wärmen Sie Ihre ursprüngliche Koordinate mit dieser niedrigeren Auflösung auf.
- Bei dieser niedrigeren Auflösung finden Sie auch die 8 benachbarten (n, ne, e, se, s, sw, w, nw) Geohash-Bereiche. Der Grund, warum Sie die Nachbarmethode ausführen müssen, besteht darin, dass zwei Koordinaten, die nahezu nebeneinander liegen, völlig unterschiedliche Geohashes aufweisen können. Daher müssen Sie eine Mittelung des von der Suche abgedeckten Bereichs vornehmen.
- Wenn Sie alle Geohashes der Nachbarn mit dieser niedrigeren Auflösung erhalten haben, fügen Sie der Liste die Geohashes Ihrer Koordinaten aus Schritt 3 hinzu.
- Dann müssen Sie eine Reihe von Geohash-Werten für die Suche erstellen, die diese 9 Bereiche abdecken. Die Werte aus Schritt 5 sind Ihr unteres Bereichslimit. Wenn Sie zu jedem Wert 1 hinzufügen, erhalten Sie Ihr oberes Bereichslimit. Sie sollten also ein Array von 9 Bereichen mit jeweils einer unteren Grenze und einer oberen Geohash-Grenze (insgesamt 18 Geohashes) haben. Diese Geohashes befinden sich noch in der niedrigeren Auflösung von Schritt 2.
- Dann konvertieren Sie alle 18 dieser Geohashes in die Bittiefe / Auflösung, in der Sie alle Ihre Geohashes in Ihrer Datenbank gespeichert haben. Im Allgemeinen tun Sie dies, indem Sie sie auf die gewünschte Bittiefe verschieben.
- Jetzt können Sie eine Bereichsabfrage für Punkte innerhalb dieser 9 Bereiche durchführen, und Sie erhalten alle Punkte ungefähr in der Entfernung Ihres ursprünglichen Punkts. Es wird keine Überlappung geben, sodass Sie keine Schnittmengen, sondern nur reine Bereichsabfragen, sehr schnell ausführen müssen. (dh in redis: ZRANGEBYSCORE zsetname lowerLimit upperLimit, über die in diesem Schritt erzeugten 9 Bereiche)
Sie können dies weiter optimieren (in Bezug auf die Geschwindigkeit), indem Sie:
- Das Aufnehmen dieser 9 reicht von Schritt 6 bis zum Finden, wo sie ineinander führen. Normalerweise können Sie 9 separate Bereiche auf 4 oder 5 reduzieren, je nachdem, wo sich Ihre Koordinate befindet. Dies kann Ihre Abfragezeit um die Hälfte reduzieren.
- Sobald Sie Ihre endgültigen Bereiche haben, sollten Sie sie zur Wiederverwendung bereithalten. Die Berechnung dieser Bereiche kann den größten Teil der Verarbeitungszeit in Anspruch nehmen. Wenn sich Ihre ursprüngliche Koordinate also nicht wesentlich ändert, Sie jedoch dieselbe Entfernungsabfrage erneut durchführen müssen, sollten Sie diese bereithalten, anstatt sie jedes Mal zu berechnen.
- Wenn Sie Redis verwenden, versuchen Sie, die Abfragen in einer MULTI / EXEC-Datei zu kombinieren, damit sie für eine etwas bessere Leistung per Pipeline übertragen werden.
- Der BESTE Teil: Sie können die Schritte 2 bis 7 auf die Clients verteilen, anstatt diese Berechnung an einem Ort durchführen zu lassen. Dadurch wird die CPU-Auslastung in Situationen, in denen Millionen von Anforderungen eingehen würden, erheblich reduziert.
Sie können die Genauigkeit weiter verbessern, indem Sie für die zurückgegebenen Ergebnisse eine Kreisentfernungs- / Haversinusfunktion verwenden, wenn Sie viel Wert auf Präzision legen.
Hier ist eine ähnliche Technik, bei der normale Base32-Geohashes und eine SQL-Abfrage anstelle von Redis verwendet werden: https://github.com/davetroy/geohash-js
Ich möchte nicht mein eigenes Ding einstecken, aber ich habe ein Modul für nodejs & redis geschrieben, das die Implementierung wirklich einfach macht. Schauen Sie sich den Code an, wenn Sie möchten: https://github.com/arjunmehta/node-georedis