MySQLで最近傍検索を実装するにはどうすればよいですか?


10

つまり、要するに

  1. 緯度と経度のデータ型は何ですか?
  2. たとえば、最初の100近くのレストランを取得するには、どのSQLコマンドを呼び出す必要がありますか?

詳細:

緯度と経度がそれぞれ10万件のビジネスレコードがあります。MySQLが実際にポイントと呼ばれるデータ型をサポートしていることがわかります。代わりに使用する必要がありますか?

MySQLはKDTreeストレージシステムをサポートしますかhttp://en.wikipedia.org/wiki/File:KDTree-animation.gif

緯度と経度を格納するには、通常のfloatデータ型ではなくポイントデータ型を使用するのが最善ですか?

最終的には、たとえばポイント105,6に最も近い最初の100軒のレストランのようなものを見つけたいと思います。私のデータベースには、たくさんのビジネスとポイントが含まれています。明らかに、すべてのレコードとすべてのポイントの距離を1つずつ計算することはO(n)であり、それで問題があります。

私はYelpのようなアプリケーションはデータベースから距離情報を効率的に取得する方法で説明されているより簡単な解決策を知っており、最初に自分も実装することに注意してください。それは良い答えです。

しかし、私はそれを上回るはずの作物の答えの1つのクリームがあると思いますか?実際、緯度と経度に基づいて場所を保存し、それに最も近いものを見つけることは、mysqlに特別な設計パターンがあることを期待する非常に一般的な問題です。それはありますか?

詳細はどこで確認できますか?ありがとう。



ここのソリューションのようですdba.stackexchange.com/questions/4210/…が最良のソリューションです。つまり、MYSQL空間と呼ばれるものがあります。ただし、(距離(x)<20)のようなものを引き出すことはできません。まだ実装されていません。
user4951 2011

回答:


11

デザインパターンに関しては、Yelpの質問はかなり標準的なものです。

より複雑な答えを得るには、おそらく地理空間距離が必要になります。これは、そのトピックに関する魅力的なパワーポイントです(ここにもPDFバージョンがあります)。ただし、関連する数学はかなり醜いです。

彼らのスライドから:

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

Stack Overflowの地理空間距離については、より長く、より詳細な回答があります。

しかし、結果を緯度と経度で制限したいとします。

最終的には、POINTデータ型を避け、緯度/経度を使用します。現在、2つのPOINT間の距離を決定する方法はないため、とにかくその計算のために緯度/経度を保存する必要があります。

最後のリンク:空間インデックスを使用したクエリの高速化に関して、このSOスレッドを確認することもできます。


[クエリ4のエラー] SQL構文にエラーがあります。右の構文についてはMySQLサーバのバージョンに対応が近い使用すること取扱説明書を確認してください「 - dest.lon)*パイを()/ 2分の180)、2)))dのDEST network_posからの距離が」2行で
フェリペ

こんにちは、@ distはMillesにいますか?ありがとう
ホルヘオラフアーランセン

1
@OlafErlandsenはい、マイル
単位です

4

ポイントデータ型は問題ありません。X(coord)/ Y(coord)を呼び出すだけで、Lat / Lon値を取得できます。

例えば:

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は緯度で、-122は経度ですか?そして25はメートルまたはキロですか?
フェリペ

1

ある座標に最も近い100のレストランを見つけます 。http://mysql.rjweb.org/doc.php/latlngの効率的なコードを参照して ください。これには、「大きな円」距離を計算するためのストアド関数が含まれています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.