「[この座標] から 'n' メートル以内にあるすべての座標を返す」と言ってクエリできる GPS 座標の大規模なデータベースを作成したいと考えています。
できるだけ効率的にする必要があるため、データベース内のすべての座標をループして、座標が「n」メートル以内にあるかどうかを計算することは、望ましい解決策ではありません。
もっと簡単な解決策はありますか?
ありがとう
「[この座標] から 'n' メートル以内にあるすべての座標を返す」と言ってクエリできる GPS 座標の大規模なデータベースを作成したいと考えています。
できるだけ効率的にする必要があるため、データベース内のすべての座標をループして、座標が「n」メートル以内にあるかどうかを計算することは、望ましい解決策ではありません。
もっと簡単な解決策はありますか?
ありがとう
私は通常、緯度/経度を使用してこの種のクエリを実行します。球面ジオメトリを使用すると、特定のポイントの周りにバウンディング ボックスを配置できます。たとえば、すべての座標を 1 マイル以内に収めたいポイント (X,Y) があるとします (メートルへの変換は、読者の演習として残しておきます)。(X-1,Y-1),(X+1,Y+1) のバウンディング ボックスを決定できます。次に、BETWEEN 演算子 (SELECT foo FROM bar WHERE LAT BETWEEN X-1 AND X+1 AND LON BETWEEN Y-1 AND Y+1) を使用してポイント データベースにクエリを実行します。次に、バウンディング ボックスの「角を丸める」ための詳細な距離計算を行います。
注意点として、経度線は球の上部で互いに接近しているため、赤道から離れるほど歪んだ結果が得られます。ただし、結果セットをすばやくフィルター処理するのに役立ちます。
計算のためのグーグル「大圏距離」。
編集: 1 マイルあたり 0.167469 度の経度 (実際には 0.167469 から 0.014564 の範囲)、1 マイルあたり 0.014483 度の緯度があります。だからあなたのバウンディングボックスは(lat - (miles * 0.014483), lon - (miles * 0.167469)), (lat + (miles * 0.014483), lon + (miles * 0.167469))
SQL Server 2008では、空間データを格納するためのサポートがあります。私自身はこれを使ったことがありませんが、必要なタイプのクエリを作成できることは知っています。
多くのデータベースシステムには、地理空間データを操作するための機能があります。
SQL Server 2008、PosGIS、MySQL間の地理空間関数の比較は次のとおりです http://www.bostongis.com/PrinterFriendly.aspx?content_name=sqlserver2008_postgis_mysql_compare
GIS データベース (PostGIS を使用した PostgreSQL など) は、実際には 2 次元または 3 次元の領域検索 (空間インデックス) 用のデータ構造を提供します。最も単純なものはグリッド インデックスであり、次に R ツリーが最も頻繁に使用されるさまざまな検索ツリー (kd ツリー、クワッド ツリー) (より多くの次元の一般化された B ツリー) です。これらの方法は適切なようです。
基本的なグリッド インデックス (空間をグリッド セルに分割し、近くのセルのみを検索する) は簡単に実装でき、検索時間を大幅に短縮できます。検索ツリーは実装が少し難しいですが、多くのプログラミング言語と DB (PostGIS や Geopandas など) のオープンソース実装が多数あります。このような問題にそれらを使用すると、通常は効果があります。
Erich のフォローアップ - PostGIS (postgresql) を使用することを選択した場合、それは無料でオープン ソースです。あなたが説明しているクエリは非常に迅速に実行され、ほとんどすべてのプラットフォームで実行されますか?無料であると言いましたか?
DB を選択できる場合は、rwwilden と同じものをお勧めし、空間データ機能を備えた SQL 2008 を使用します。そのソリューションまたは空間クエリを含むソリューションを使用できない場合は、Microsoft 独自のHierarchical Triangular Meshに関する論文を参照して、それらを実装することができます。MSSQL '05 の SDK には、すぐに使用できる HTM 用のソリューション全体が付属しているため、それを使用して、使用しようとしているプラットフォームに変換することができます。
編集:
HTM と実装を説明する、より詳細なドキュメントを次に示します。もちろん、選択した DB に変換できます。完全な HTM 実装のソース コードは、SDK for 2005 にあります。
GIS 拡張を避けたい場合は、この投稿の関数を postgres sqlに適合させました。
create or replace function change_in_lat(miles numeric)
returns double precision as $$
with v as (select
3960.0 as earth_radius,
180 / pi() as radians_to_degrees
) select ( miles / earth_radius ) * radians_to_degrees from v;
$$ language sql
returns null on null input;
create or replace function change_in_long(lat numeric, miles numeric)
returns double precision as $$
with v as (select
3960.0 as earth_radius,
pi() / 180 as degrees_to_radians,
180 / pi() as radians_to_degrees
) select (
miles / (earth_radius * cos(lat * degrees_to_radians))
) * radians_to_degrees from v;
$$ language sql
returns null on null input;
それらを使用して、周囲の正方形のクエリを実行できます。
--find all "a"s within 25 miles of any "b"
select * from a join b on (
a.gpslat between
b.gpslat - change_in_lat(25) and b.gpslat + change_in_lat(25)
and a.gpslong between
b.gpslong - change_in_long(b.gpslat::numeric, 25)
and b.gpslong + change_in_long(b.gpslat::numeric, 25)
);
あなたがそれを十分に頻繁に使用していれば、 between ステートメントを単一の関数に変えるのは簡単だと確信しています。ただし、これを使用して実際の「半径内」クエリを実行したことはありません。
より複雑なものについては、他の回答が言っているように、おそらく GIS 拡張機能が必要になるでしょう。PostGIS は優れていますが、多くの GIS 固有の関数を正しく処理するのが難しい場合があり、バウンディング ボックス インデックスを使用しない限り、データ セットが十分に大きい場合、空間クエリに 1 日かかる可能性があることがわかりました。しかし、geojson 形式でデータを出力するなど、複雑さのトレードオフは、すべての凝ったものにとって間違いなく価値があります。