web-dev-qa-db-ja.com

PostGISを使用して、指定されたポイントのn個の最近傍を検索しますか?

私はPostGISを使用してn個の最近傍を見つける問題を解決しようとしています:

出発点:

  • 緯度/経度を含むgeonames(geonames.orgから)を含むテーブルgeoname(WSG-84)
  • Srid = 4326およびdatatype = POINTのGeometryColumngeomを追加しました
  • 値で埋められたgeom:UPDATE geoname SET geom = ST_SetSRID(ST_Point(longitude、latitude)、4326);
  • GeomのGistインデックスを作成しました(CREATE INDEX geom_index ON geoname USING Gist(geom);)/ Clustered geom_index:CLUSTER geom_index ON geoname;)
  • GeonameidのPRIMARYKEY UNIQUEBTREEインデックスを作成しました

問題:id(geoname.geonameid)で表されるテーブルgeoname内の特定のポイントのn個(例:5)の最近傍を検索します。

考えられる解決策:

http://www.bostongis.com/PrinterFriendly.aspx?content_name=postgis_nearest_neighbor に触発されて、私は次のクエリを試しました:

"SELECT start.asciiname, ende.asciiname, distance_sphere(start.geom, ende.geom) as distance " +
"FROM geoname As start, geoname As ende WHERE start.geonameid = 2950159 AND start.geonameid <> ende.geonameid " +
"AND ST_DWithin(start.geom, ende.geom, 300) order by distance limit 5"

処理時間:約60秒

EXPANDに基づくアプローチも試しました。

"SELECT start.asciiname, ende.asciiname, distance_sphere(start.geom, ende.geom) as distance " +
"FROM geoname As start, geoname As ende WHERE start.geonameid = 2950159 AND start.geonameid <> ende.geonameid AND expand(start.geom, 300) && ende.geom " +
"order by distance limit 5"

処理時間:約120秒

目的のアプリケーションは、ある種のオートコンプリートです。したがって、1秒を超える時間のかかるアプローチは適用できません。 PostGISで1秒未満の応答時間を達成することは一般的に可能ですか?

22
Scholle

PostGIS 2.0以降、利用可能なジオメトリタイプのKNNインデックスがあります。これにより、「現在地...」からの距離を無視して、最も近い5つのレコードが得られます。

SELECT *
FROM your_table 
ORDER BY your_table.geom <-> "your location..."
LIMIT 5;

見る <->演算子 PostgreSQLマニュアル

50
Stefan

リストで回答されたと思うので、単位は度であるため、st_dwithinで300度でほぼ全世界を検索します。

データセットが非常に大きいため、代わりに投影されたメーターベースの投影で作業できない場合(はるかに高速でCPU負荷の少ない計算)、代わりにgeograpphyタイプの使用を検討する必要があります。次に、メーターでst_dwithinを使用できます。

ジオメトリを地理に変換した新しいテーブルを作成するだけで、処理が速くなります。

しかし、それをテストするために、その場でキャストすることができます:

SELECT start.asciiname, ende.asciiname, 
ST_Distance(start.geom::geography, ende.geom::geography) as distance 
FROM geoname As start, geoname As ende 
WHERE start.geonameid = 2950159 AND start.geonameid <> ende.geonameid AND
ST_DWithin(start.geom::geography, ende.geom::geography, 300) 
order by distance 
limit 5;

HTHニクラス

7
Nicklas Avén