Wie implementiere ich die Suche nach dem nächsten Nachbarn am besten in MySQL?

10

Kurz gesagt,

  1. Was sollte der Datentyp für Längen- und Breitengrad sein?
  2. Welchen SQL-Befehl sollte ich aufrufen, um beispielsweise die ersten 100 nächstgelegenen Restaurants abzurufen?

Detail:

Ich habe jeweils 100.000 Geschäftsaufzeichnungen mit Längen- und Breitengraden. Ich sehe, dass MySQL tatsächlich einen Datentyp namens point unterstützt. Soll ich das stattdessen verwenden?

Unterstützt MySQL das KDTree-Speichersystem http://en.wikipedia.org/wiki/File:KDTree-animation.gif

Ist es am besten, den Punktdatentyp anstelle des regulären Float-Datentyps zum Speichern von Latitutude und Longitude zu verwenden?

Schließlich möchte ich Dinge wie die ersten 100 Restaurants finden, die zum Beispiel den Punkten 105,6 am nächsten liegen, und meine Datenbanken enthalten viele Geschäfte und Punkte. Offensichtlich wäre die Berechnung der Entfernung nacheinander für jeden Datensatz und für jeden Punkt O (n) und daher schlecht.

Beachten Sie, dass mir eine einfachere Lösung bekannt ist, die unter Anwendung wie Yelp beschrieben wird. Entfernungsinformationen effizient aus der Datenbank abrufen und diese zunächst auch selbst implementieren. Das ist eine gute Antwort.

Ich denke jedoch, dass es eine Creme der Ernteantwort gibt, die das übertreffen sollte, oder? Tatsächlich ist das Speichern von Standorten basierend auf Breiten- und Längengraden und das Finden von Materialien in der Nähe ein sehr häufiges Problem. Ich erwarte, dass MySQL ein spezielles Entwurfsmuster dafür hat. Hat es das?

Wo kann ich mehr darüber erfahren? Vielen Dank.

user4951
quelle
Hast du diese SO Frage gesehen ?
Jack sagt, versuchen Sie es mit topanswers.xyz
Es sieht so aus, als ob die Lösung hier dba.stackexchange.com/questions/4210/… die beste Lösung ist. Ich meine, es gibt dieses Ding namens MYSQL räumlich. Sie können jedoch keine Dinge wie where (distance (x) <20) herausziehen. Es ist noch nicht implementiert.
user4951

Antworten:

11

In Bezug auf Designmuster ist die Yelp-Frage ziemlich normal.

Für eine komplexere Antwort benötigen Sie wahrscheinlich die räumliche Entfernung. Hier ist ein faszinierender Powerpoint zu diesem Thema (und hier ist auch eine PDF-Version davon). Die Mathematik ist jedoch ziemlich hässlich.

Von ihrer Folie:

set @orig_lat=122.4058; set @orig_lon=37.7907;
set @dist=10;

SELECT *, 3956 * 2 * ASIN(SQRT(
POWER(SIN((@orig_lat - abs(dest.lat)) * pi()/180 / 2), 2) +  COS(@orig_lat * pi()/180 ) * COS(abs(dest.lat) * pi()/180) *  POWER(SIN((@orig_lon  dest.lon) * pi()/180 / 2), 2) )) as  distance
FROM hotels dest 
having distance < @dist
ORDER BY distance limit 10

Bei Stack Overflow gibt es eine längere und ausführlichere Antwort zur räumlichen Entfernung .

Sie möchten die Ergebnisse jedoch nach Längen- und Breitengrad begrenzen.

Letztendlich würde ich den Datentyp POINT vermeiden und mit Längen- / Breitengrad gehen. Derzeit gibt es keine Möglichkeit, den Abstand zwischen zwei PUNKTEN zu bestimmen. Daher müssen Sie für diese Berechnung ohnehin Breiten- und Längengrade speichern.

Ein letzter Link: Möglicherweise möchten Sie auch diesen SO-Thread lesen, um die Abfragen mithilfe von räumlichen Indizes zu beschleunigen.

Richard
quelle
[FEHLER in Abfrage 4] Sie haben einen Fehler in Ihrer SQL-Syntax. Überprüfen Sie das Handbuch, das Ihrer MySQL-Serverversion entspricht, auf die richtige Syntax für die Verwendung in der Nähe von '- dest.lon) * pi () / 180/2), 2))) als Abstand FROM network_pos dest mit d' in Zeile 2
Felipe
Hallo, der @dist ist auf Milles? danke
Jorge Olaf Erlandsen
1
@OlafErlandsen ja es ist in der Meile
Jan van der Vegt
4

Punktdatentypen sind OK; Sie können einfach X (Koordinate) / Y (Koordinate) aufrufen, um die Lat / Lon-Werte zu erhalten.

Beispielsweise:

SELECT id, 
(3959 
    * acos(
        cos(radians(37)) 
        * cos(radians(Y(coord)))
        * cos(radians(X(coord)) - radians(-122)) 
        + sin(radians(37))
        * sin(radians(Y(coord)))
      )
) AS distance 
FROM markers HAVING distance < 25 
ORDER BY distance LIMIT 20;
Shahak Nagiel
quelle
37 ist lat und -122 ist lon? Und 25 ist Meter oder km?
Felipe
1

Finden Sie die 100 Restaurants, die einer Koordinate am nächsten liegen: Siehe effizienten Code unter http://mysql.rjweb.org/doc.php/latlng. Er enthält eine gespeicherte Funktion zur Berechnung der Entfernung "großer Kreise".

Rick James
quelle