MySQL en yakın komşu arama nasıl yapılır?


10

Kısacası,

  1. Enlem ve boylam veri türü ne olmalıdır?
  2. Örneğin en yakın ilk 100 restoranı almak için hangi SQL komutunu çağırmalıyım?

Detay:

Her biri enlem ve boylam ile 100 bin kayıt var. MySQL'in aslında nokta adı verilen bir veri türünü desteklediğini görüyorum. Bunun yerine kullanmalı mıyım?

MySQL, KDTree depolama sistemini destekliyor mu http://en.wikipedia.org/wiki/File:KDTree-animation.gif

Enlem ve boylamı saklamak için normal kayan noktalı veri türü yerine nokta veri türünü kullanmak en iyisidir?

Sonunda örneğin 105,6 puanına en yakın ilk 100 restoran gibi şeyler bulmak istiyorum ve veritabanlarımda çok sayıda biz ve puan var. Açıkçası her kayıt ve her puan için mesafeyi tek tek hesaplamak O (n) ve dolayısıyla berbat olacaktır.

Uygulama Nasıl Yapılır? Yelp Nasıl Yapılır? Gibi tarif edilen daha basit bir çözümün farkındayım Veri tabanından mesafe bilgilerini verimli bir şekilde alın ve kendimi de bir başlangıç ​​için uygulayacağım. Bu iyi bir cevap.

Bununla birlikte, kırpma cevabından daha iyi performans göstermesi gereken bir krem ​​olduğunu düşünüyorum? Aslında, enlem ve boylam temelli konumların depolanması ve ona en yakın şeylerin bulunması, mysql'in bunun için özel bir tasarım modeline sahip olmasını beklediğim çok yaygın bir sorundur. Buna sahip mi?

Nerede daha fazla bilgi edinebilirim? Teşekkürler.



Buradaki çözüm gibi görünüyor dba.stackexchange.com/questions/4210/… en iyi çözümdür. Yani MYSQL uzaysal diye bir şey var. Ancak nerede (mesafe (x) <20) gibi şeyleri çıkaramazsınız. Henüz uygulanmadı.
user4951

Yanıtlar:


11

Tasarım desenine gelince, Yelp sorusu oldukça standart şeyler.

Daha karmaşık bir cevap için muhtemelen jeo-uzamsal mesafeye ihtiyacınız olacaktır. İşte bu konuyla ilgili bir ilginç powerpoint (ve burada hem de bunun bir pdf versiyonu). Ancak, ilgili matematik oldukça çirkin.

Slaytlarından:

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

Yığın Taşması'ndaki jeo-uzamsal mesafe hakkında daha uzun ve daha derin bir cevap var .

Ancak sonuçları yine de enlem ve boylam ile sınırlamak istiyorsunuz.

Sonuçta, POINT veri tipinden kaçınır ve enlem / boylam ile giderim. Şu anda iki POINT arasındaki mesafeyi belirlemenin bir yolu yoktur, bu nedenle bu hesaplama için enlem / boylamı yine de saklamanız gerekecektir.

Son bir bağlantı: mekansal dizinleri kullanarak sorguları hızlandırma ile ilgili bu SO iş parçacığını da kontrol etmek isteyebilirsiniz .


[Sorgu 4'teki HATA] SQL sözdiziminizde bir hata var; '- dest.lon) * pi () / 180/2), 2)))' nin 2 numaralı satırında D 'olan D' mesafesi olarak kullanılacak doğru sözdizimi için MySQL sunucu sürümünüze karşılık gelen kılavuzu kontrol edin
Felipe

Merhaba, @dist milyonlarca mı? teşekkür ederim
Jorge Olaf Erlandsen

1
@OlafErlandsen evet bu mil
Jan van der Vegt

4

Nokta veri tipleri TAMAM; Lat / Lon değerlerini almak için sadece X (koordinat) / Y (koordinat) başlatabilirsiniz.

Örneğin:

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;

37 lat ve -122 yalnız mı? Ve 25 metre mi yoksa km mi?
Felipe

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.