Bagaimana Cara Terbaik Menerapkan pencarian tetangga terdekat di mysql?

10

Jadi, singkatnya,

  1. Apa yang harus menjadi tipe data lintang dan bujur?
  2. Apa perintah SQL yang harus saya panggil untuk mendapatkan 100 restoran terdekat pertama misalnya?

Detail:

Saya memiliki 100k catatan bisnis masing-masing dengan lattitude dan bujur. Saya melihat bahwa MySQL sebenarnya mendukung tipe data yang disebut point. Haruskah saya menggunakannya?

Apakah MySQL mendukung sistem penyimpanan KDTree http://en.wikipedia.org/wiki/File:KDTree-animation.gif

Apakah lebih baik menggunakan tipe data titik daripada tipe data float biasa untuk menyimpan latitutude dan bujur?

Akhirnya saya ingin menemukan hal-hal seperti 100 restoran pertama yang paling dekat dengan poin 105,6 misalnya dan database saya mengandung banyak biz dan poin. Jelas menghitung jarak satu per satu untuk setiap catatan dan untuk setiap poin akan menjadi O (n) dan karenanya menyebalkan.

Perhatikan bahwa saya mengetahui solusi yang lebih sederhana yang dijelaskan dalam Bagaimana Cara Aplikasi Seperti Yelp. Ambil informasi jarak dari basis data secara efisien dan akan mengimplementasikannya sendiri sebagai permulaan. Itu jawaban yang bagus.

Namun, saya pikir ada satu creme dari jawaban krop yang harus mengungguli itu kan? Bahkan, menyimpan lokasi berdasarkan lintang dan bujur dan menemukan barang-barang terdekat adalah masalah yang sangat umum. Saya berharap mysql memiliki pola desain khusus untuk itu. Apakah ada itu?

Di mana saya bisa belajar lebih banyak tentang itu? Terima kasih.

pengguna4951
sumber
Pernahkah Anda melihat pertanyaan SO ini ?
Jack bilang coba topanswers.xyz
Sepertinya solusi di sini dba.stackexchange.com/questions/4210/… adalah solusi terbaik. Maksud saya ada hal yang disebut spasial MYSQL. Namun Anda tidak dapat menarik hal-hal seperti di mana (jarak (x) <20). Itu belum diimplementasikan.
user4951

Jawaban:

11

Sejauh pola desain, pertanyaan Yelp adalah hal yang cukup standar.

Untuk jawaban yang lebih kompleks, Anda mungkin perlu jarak geospasial. Berikut ini adalah powerpoint yang menarik tentang topik itu (dan di sini juga ada versi pdf). Namun, matematika yang terlibat cukup jelek.

Dari slide mereka:

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

Ada jawaban yang lebih dalam dan lebih mendalam tentang jarak geospasial pada Stack Overflow .

Tetapi Anda masih ingin membatasi hasil dengan lintang dan bujur.

Pada akhirnya, saya akan menghindari datatype TITIK dan pergi dengan lintang / bujur. Saat ini tidak ada cara untuk menentukan jarak antara dua POINT, jadi Anda harus menyimpan lintang / bujur untuk perhitungan itu.

Satu tautan terakhir: Anda mungkin juga ingin memeriksa utas SO ini tentang mempercepat kueri menggunakan indeks spasial.

Richard
sumber
[GALAT dalam kueri 4] Anda memiliki kesalahan dalam sintaks SQL Anda; periksa manual yang sesuai dengan versi server MySQL Anda untuk sintaks yang tepat untuk digunakan di dekat '- dest.lon) * pi () / 180/2), 2))) sebagai jarak FROM network_pos dest memiliki d' pada baris 2
Felipe
Hai, @dist ada di milles? terima kasih
Jorge Olaf Erlandsen
1
@ OlafErlandsen ya itu dalam mil
Jan van der Vegt
4

Tipe data titik OK; Anda bisa memanggil X (coord) / Y (coord) untuk mendapatkan nilai Lat / Lon.

Sebagai contoh:

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
sumber
37 adalah lat dan -122 adalah lon? Dan 25 meter atau km?
Felipe