web-dev-qa-db-ja.com

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

私は、特定のランドマークの10 km /マイル(このストーリーでは重要ではない)のすべてのランドマークを見つける地理検索プロジェクトから始めようとしています。

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

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

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

Google Maps APIは役に立ちますか?

14
Dario Granich

SQL Server 2008以降、場所(緯度/経度のペア)を格納し、場所に関連するクエリを簡単に作成できる geography データ型があります。

これについて詳しく説明する既存の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
10
Flater

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

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

29
amon

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

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

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

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

worstの場合、これらのクエリでシステムが空間インデックスを使用するのに問題がある場合は、フィルターを追加できます。検索ポイントを中心とした長さ2 *(検索距離)の辺を持つ正方形の境界ボックスを作成し、テーブルジオメトリの境界ボックスをと比較します実際の距離を確認する前。それがPostGISですST_DWithin上記はとにかく内部的に行います。


GISでの距離

空間インデックスは素晴らしく、問題に対する完全に正しい解決策ですが、距離の計算は論理的に複雑になる可能性があります。特に、データがどのprojection(基本的には座標系のすべてのパラメーター)に格納されているかを考慮する必要があります。ほとんどの2D投影(その他のもの) angularさまざまな緯度/経度の投影法のような座標系)は長さを大幅に歪めます。たとえば、Webメルカトル図法(Google、Bing、およびその他すべての主要なベースマッププロバイダーで使用されているもの)- 場所が赤道から遠ざかるにつれて、エリアと距離がますます拡大します 。GISで正式に教育を受けていないため、間違っている可能性がありますが、2D投影で見た中で最も優れているのは、特定の投影法です。全世界の単一の定数点からの正しい距離(いいえ、すべてのクエリに異なる投影法を使用することは現実的ではありません。インデックスは役に立たない。)

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

これは、組み込みの空間インデックスを使用しない場合でも適用されます。現在使用している、または将来使用する技術や手法に関係なく、データにはある程度の予測があり、現在、実行中のクエリや計算にすでに影響を与えています。

11
jpmc26

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

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

3
Peter Green