特定のランドマークの範囲内のすべてのランドマークを効率的に検索するにはどうすればよいですか?


14

特定のランドマークの10 km /マイル(この話では重要ではありません)内のすべてのランドマークを見つけるジオ検索プロジェクトから始めようとしています。

たとえば、1,000,000のランドマークのデータベースがあるとします。特定の座標を持つランドマークの10マイルの範囲ですべてのランドマークを見つけるには、検索からのランドマークと1,000,000ランドマーク間の距離を計算する必要があります。

それを行うより良い方法はありますか?

私が考えていた代替手段は、国、地域、都市、近隣、ビジネス、歴史などのランドマークを、ビジネスが近隣または都市の一部になることができるように分類することです。都市は、地域、国などの一部です。これにより、計算のリストを絞り込むことができますが、検索を高速かつ正確にするためには、多くの作業を行う必要があります。

Google Maps APIは役立ちますか?


5
簡単なマンハッタン距離計算を実行し、その後2番目のフィルターを実行して、10 kmの正方形内にあるが半径10 kmの外側にあるランドマークを除外するだけで、かなりの数を削除できます。
ニール

3
どのデータベーステクノロジーを使用していますか?答えはデータベースに依存しません。
jpmc26

1
@Neil 2番目のパスとして、実際の距離を計算せずに、原点の7 kmでxとyの両方が一致するランドマークを含めることができます。
ジミージェームズ

回答:


10

SQL Server 2008以降、場所(緯度/経度のペア)を保存し、場所関連のクエリを簡単に記述できる地理データタイプがあります。

この詳細については、既存のStackOverflowの回答があります。

最も近い7つのアイテムを見つけるための基本的なクエリ

USE AdventureWorks2012  
GO  
DECLARE @g geography = 'POINT(-121.626 47.8315)';  
SELECT TOP(7) SpatialLocation.ToString(), City FROM Person.Address  
WHERE SpatialLocation.STDistance(@g) IS NOT NULL  
ORDER BY SpatialLocation.STDistance(@g);  

100m以内のすべてを見つけるための基本的なクエリ(質問に対する2番目の回答)

-- Get the center point
DECLARE @g geography
SELECT @g = geo FROM yourTable WHERE PointId = something

-- Get the results, radius 100m
SELECT * FROM yourTable WHERE @g.STDistance(geo) <= 100

11
@KonradRudolph:大量の行カウントを持つテーブルでのクエリに使用されるSQL列の場合と同様です。あなたは正しいですが、そのコメントは、回答として投稿される実質的にすべてのSQLクエリに適用されます。
18年

2
質問の「MS SQL Server」はどこで読みましたか?
Doc Brown

3
@Flater私はそれが通常明白で冗長であることに同意しますが、OPの文言は彼らがそのようなメカニズムを知らないことを示唆しているようです。
コンラッドルドルフ

2
@ jpmc26:有効なオプションをリストし、他のオプションを含めなかったことにthat然としているのですか?何?PostGISを追加することが適切だと思う場合は、自分で回答を追加し(あなたが行った)、自分と同じ考えを持っていないことを他人に批判することに頼らないでください。
フラット

3
あなたの答えは、基本的にMS SQLの売り込みのように見えます。あなたのコメントは、データベースを何万ドルもかかるものに切り替えることを示唆しています。OPがクエリを実際に実装する方法を説明したり、空間インデックスを使用したりすることはMS SQLで他のDBほど簡単ではないという事実についても説明していません。また、基礎となる概念についても説明していません。「有効」であるかどうかに関係なく、それは悪い答えです。それが私を悩ます理由です。
jpmc26

29

GIS(地理情報システム)クエリをサポートするデータベースを使用します。ほとんどのデータベースはこれを完全にサポートするか、拡張機能を備えていますが、詳細はデータベース固有です(回答では、FlaterはSQLサーバーの構文を示しています)。

アプリケーションにそのようなクエリを実装する必要がある場合は、空間クエリを許可するデータ構造(kd Treeなど)を実装できます。これは、ツリーの各レベルが異なる座標次元で分割されることを除いて、バイナリ検索ツリーに似ています。これにより、検索を実行可能な候補のより小さなセットに制限できます。効果的には、検索「半径10 km」を各座標次元の境界に変換し、ツリーに再帰的に移動するときに境界を強化します。



8
PostGISは最高の無料オプションです。SQL Serverの非常に基本的なGISタイプと機能よりもはるかに多くをサポートします。しかし、これは基本的な機能です。
jpmc26

@amon jpmc26のコメントは良い例であり、あなたの例を批判するほどではありません。「ゼロから始めたい場合は、ライセンスDBの費用を支払う必要はありません。この無料のオープンソースのDBでも、非常にうまく機能します。」
mgarciaisaia

11

はい、より良い方法があります。空間インデックスを使用する必要があります。これらのインデックスは、ジオメトリに関するメタデータを整理して、遠くのジオメトリを非常に迅速に除外し、記述した計算を回避することで多くのCPUサイクルを節約します。すべての主要なリレーショナルデータベースは、それらに対応する空間ジオメトリタイプとインデックスを提供するため、自分で実装する必要はありません。

調べたいのは「距離内」クエリ(他のジオメトリから一定の距離内にあるジオメトリのクエリ)です。これらは非常に標準的で非常に解決された問題であり、上記のすべてのデータベースで可能です(そしていくつかに組み込まれています):

  • PostGIS: ST_DWithin
  • SQLサーバー: STDistanceこの関数の3Dジオグラフィバージョンでのインデックスの使用がサポートされていることは明らかではありません)
  • Oracle:(SDO_WITHIN_DISTANCEこれは、インデックスの使用をトリガーすることを明示的に言っていません。クエリプランを再確認します。インデックスを使用するためにを適用する必要があるかもしれませんSDO_FILTER。)
  • MySQL:まだこれを理解しています。

インデックスの使用をトリガーするための回避策

システムがこれらのクエリで空間インデックスを使用するのに問題がある最悪の場合、追加のフィルタを追加できます。あなたの探索点を中心とテーブルジオメトリがに対してバウンディングボックスを比較する(距離を検索)長さ2 *の側面と正方形のバウンディングボックスを作成したいという実際の距離をチェックする前に。ST_DWithinとにかく、上記のPostGIS が内部的に行うことです。


GISの距離

空間インデックスは素晴らしいものであり、問​​題に対する絶対的な正しい解決策ですが、距離の計算は論理的に複雑になる可能性があります。特に、データがどの投影(基本的には座標系のすべてのパラメーター)に保存されているかを考慮する必要があります。ほとんどの2D投影(さまざまな緯度/経度投影などの角度座標系以外のもの)は長さを大きく歪めます。たとえば、Webメルカトル図法(Google、Bing、および他のすべての主要なベースマッププロバイダーで使用されているもの)は、位置が赤道から遠くなるにつれて面積と距離を拡大します。私はGISで正式に教育を受けていないので間違っているかもしれませんが、2D投影で見た中で最も良いのは、全世界の単一の、一定のポイント。(いいえ、クエリごとに異なるプロジェクションを使用するのは実用的ではありません。インデックスを使用できなくなります。)

一番下の行は、あなたの数学が正確であることを確認する必要があるということです。開発の観点から最も簡単な方法は、回転投影(これらは「地理」と呼ばれることが多い)と回転楕円体モデルを使用した数学の実行をサポートする関数を使用することですが、これらの計算は2Dの計算よりも少し高価ですまた、一部のDBはインデックス作成をサポートしていない場合があります。ただし、それらを使用して許容可能なパフォーマンスを得ることができる場合は、おそらくそれが道です。もう1つの一般的なオプションは、データが世界の特定の部分に限定されている場合に距離と面積の両方をかなり正確に近づける地域投影(UTMゾーンなど)です。アプリに最適なものは、特定の要件によって異なりますが、

これは、組み込みの空間インデックスを使用しない場合でも適用されます。現在使用している、または将来使用するテクノロジーやテクニックに関係なく、データには何らかの予測があり、現在、実行中のクエリや計算にすでに影響を及ぼしています。


3

可能であれば、データベースで特定のサポートを使用することが、これを行う最も賢明な方法であることに同意します。

ただし、特定のサポートなしでデータベースでこれを行う必要がある場合は、循環を囲む正方形をクエリすることから始めます(例:(y>(y1-rad))AND(y <(y1 + rad))AND(x>( x1-rad))AND(x <(x1 + rad))。ポイントにほぼ均等な分布クエリがあると仮定すると、真のマッチに加えて約30%の余分なマッチが得られます。その後、誤った一致を除外することができます。


しかし、適切な空間インデックスがないと、このようなクエリは、最悪でもデータベース全体、インデックスに応じて指定された緯度または経度の範囲内のすべてのアイテム、つまり正方形ではなく「バンド」をスキャンします。パフォーマンスを低下させたくない場合は、空間インデックスをサポートするデータベースを使用してください!
jcaron

@jcaronとの通常のBツリーインデックスを使用してx、このクエリを最適化できると思いますy。(おそらく結合され、おそらく分離されています。実際にはどちらがよりうまく機能するかを把握するために、少しプロファイルを作成します。)
jpmc26

@ jpmc26いいえ、できません。よく考えてみてください。
jcaron

@jcaronおそらく、あなたは明らかに簡単ではない何かについて謎めいていない方が良いでしょう。BツリーはBETWEENクエリに使用できます。最悪の場合、2つのインデックスを作成できなかった理由はわかりませんが、各インデックスからのフィルター結果は結合されます。(これは、RDBMSが複数のインデックスを使用する価値があると判断したときに内部的に行うことです。)結合インデックスが機能する場合、第1レベルで1つのディメンションを完全に除外し、第2レベルで比較的迅速に絞り込みます。
jpmc26

2
@jcaronは実際には次のようなものにインデックスを使用できます y between -68 and -69 and x between 10 and 11が、もちろん空間インデックスはそのタスクのためにより良い仕事をします
フアンカルロスオ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.