ich ein Datenbankmodell haben Position(lat,lon)
die latitudes
und longitudes.
Rails Verschachtelte SQL-Abfragen
ich eine Controller-Aktion haben hält show_close_by
genannt, die in Grad eine Position recieves (my_lat, my_lon)
, eine Toleranz (in Kilometern) und sollte die Liste der Positionen zurückkehren in der Datenbank, die innerhalb des Toleranzbereichs liegen.
Dafür verwende ich die hairsine_distance Formel, die die Entfernung in Kilometern (auf der Erdoberfläche) zwischen zwei Koordinaten (lat1, lon1, lat2, lon2)
berechnet.
Um die Abfrage schneller zu machen, schrieb ich die ganze haversine_distance
Formel in der Abfrage:
... WHERE 2*6371*asin(sqrt(power(sin((:lat2-latitude)*pi()/(180*2)) ,2) + cos(latitude*pi()/180)*cos(:lat2*pi()/180)*power(sin((:lon2-longitude)*pi()/(180*2)),2))) < tolerance
Die Besonderheiten der Abfrage keine Rolle spielen. Mein Zweifel ist: Ist es notwendig, diese riesige Funktion für JEDE Position in der Datenbank zu berechnen? Kann ich mit einer einfacheren Funktion deutlich zu weit entfernte Positionen herausfiltern?
Nun, ich kann: Mit einer verschachtelten SQL-Abfrage kann ich die Datenbank nach Positionen abfragen, die sich innerhalb eines großen "Quadrats" (in lat/lon) befinden und dann diejenigen mit der teureren trigonometrischen Funktion filtern. Etwas wie folgt aus:
SELECT * FROM (SELECT * FROM Positions WHERE lat-latitude < some_reasonable_upper_bound AND lon-longitude < same_upper_bound) WHERE costly_haversine_distance < tolerance
Schließlich meine Frage: wie kann ich dies in Rails implementieren (ohne die gesamte Abfrage Schreiben selbst)? Ist Positions.where(reasonable_upper_bound).where(costly_but_accurate_restriction)
eine verschachtelte Abfrage? Wenn nicht, wie?
Vielen Dank!
Kennen Sie [Geocoder] (https://github.com/alexreisner/geocoder)? Du installierst den Edelstein, fügst eine Linie in dein Positionsmodell ein und kannst dann Sachen wie 'Position.near ([40.71, 100.23], 20)' machen. Dieses Juwel ist ziemlich populär, also würde ich sagen, dass sie das tun, was du gut machen willst. (sprich, du weißt schon, das Verbinden von 'where'-Klauseln macht nicht das, was du willst. Ich denke, es überschreibt einfach die vorherigen). – Robin
Ja, ich weiß über Geocoder und ich könnte es am Ende benutzen, aber es schien ein bisschen groß für das, was ich will (ich will nur Abstände zwischen Objekten). Wie viel langsamer ist eine App, die ein ganzes Geocoder-Objekt im Vergleich zu der von mir programmierten Barebones-Funktion hairsine_distance lädt? – gdiazc
@Robin Es überschreibt das vorherige nicht, aber es * fügt * die Bedingungen hinzu, die 'AND' zu der gegenwärtigen Abfrage verwenden, die nicht ganz ist, wonach der Fragesteller sucht. – nzifnab