SpatiaLiteでポイントの位置を持つ2つのテーブル間の最近傍を検索しますか?


10

今日SpatiaLiteを使い始めて、すでに問題に遭遇しました。

tableOneに保存されている各ポイントの場所について、tableTwoから最も近い(直線距離)ポイントを1つ選択します。

これまでのところ、VIEWを利用する不器用なソリューションを思い付きました。

CREATE VIEW testview AS 
SELECT 
A.id , 
B.myValue, 
Distance(A.Geometry, B.Geometry) AS distance
FROM tableOne AS A, tableTwo AS B
WHERE distance < 10000
ORDER BY A.Id, distance;

その後:

SELECT * FROM testview
WHERE distance = (SELECT MIN(distance) FROM testview AS t WHERE t.id = testview.id)

仕事をするようです。

2つの質問:

ビューを作成せずにそのようなクエリを実行する方法はありますか?

パフォーマンスを向上させるためにこのクエリを最適化する他の方法はありますか?実際のシナリオでは、tableOneには数百から数千のレコードがあり、tableTwoには130万があります。


数桁速いアプローチを提供できますが、スペーシャルライトの代わりにpostgresql 9のknngistインデックスを使用する必要があります...
Ragi Yaser Burhum 2011年

実際には、GRASS、ArcGIS、QGIS、SQLServer、およびその他のほとんどの空間データベース/デスクトップGISよりも高速です(ただし、Oracleの最近傍機能は試していません)。
Ragi Yaser Burhum、2011年

@Ragi:PostGISがそのような問題を処理するはるかに効率的な方法であることを私は知っています。ただし、この演習の最終的な目標は、小さなポータブルアプリを作成することです。この場合、SpatiaLiteが勝者です。
radek、2011年

ポータブルアプリの開発プラットフォームは何ですか?
Allan Adair

@Allan:現在、Windows Server 2008とUbuntuの両方に取り組んでいます。
radek、2011年

回答:


5

私はこのSQLをテストしたところ、うまくいきました:

SELECT g1.OGC_FID As id1, g2.OGC_FID As id2, MIN(ST_Distance(g1.GEOMETRY,g2.GEOMETRY)) AS DIST
FROM table_01 As g1, table_02 As g2   
WHERE g1.OGC_FID <> g2.OGC_FID
AND ST_Contains(ST_Expand(g1.geometry,50),g2.geometry)
GROUP BY id1
ORDER BY id1

ここで読むことができるように、「最近傍クエリを実行する素朴な方法は、クエリジオメトリからの距離で候補テーブルを並べ替え、最小距離のレコードを取得することです」。

宜しくお願いします、

アンドレア


このクエリを使用しようとしていますが、予期しない結果が発生しています-結果のテーブルが表示されますが、表示できる行のIDを使用すると、最も近い隣人ではありません。複数行の文字列レイヤーで、別のレイヤーの各ポイントに最も近いラインを見つけようとしています。spatiaLiteは初めてです。助言がありますか?また、私は最終的に100万個の+ポイントでこれを実行したい
kflaw

また、このステートメントの目的を理解しているかどうかもわかりません。WHEREg1.OGC_FID <> g2.OGC_FID
kflaw

また、私の結果では、距離がゼロになっています。私はIDを取得していたとしても、AND ST_Contains(ST_Expand(g1.geometry、50)、g2.geometry)だけでなく、それを削除し、まだ距離値を取得していない:私はこのラインの周り果たしている
kflaw

6

すべてのポイントの組み合わせ間の距離を計算したくない場合は、いずれかのテーブルで空間インデックスを使用できます。

SELECT 
  A.id , 
  B.myValue, 
  MIN(Distance(A.Geometry, B.Geometry)) AS distance
FROM tableOne AS A, tableTwo AS B
WHERE A.ROWID IN (
  SELECT ROWID
  FROM SpatialIndex WHERE
    f_table_name = 'A' 
    AND search_frame = BuildCircleMbr(ST_X(B.Geometry), ST_Y(B.Geometry), 10000))
GROUP BY A.id, B.myValue

空間インデックスを使用する必要があるため、投稿したソリューションを使用しようとしましたが、値が返されませんか?行のf_table_name = 'A'場合、「A」を実際のテーブル名(テーブル1)に置き換える必要がありますか?私はどちらの方法でも試しましたが、それでも何も返されません。これはなぜでしょうか
kflaw

あなたは正しいf_table_name = 'A'はずです f_table_name = 'tableOne'。このリクエストは、spatialite> 4.xを想定していることに注意してください(SpatialIndex仮想テーブルが使用されます)。をsearch_frameユースケースに合わせて調整しようとしましたか?上記の例では、ポイントは最大距離10000メートルにあると想定されています。
サミュエル

私は検索フレームの値をいじってみましたが、それは私にとってはうまくいくはずの10000メートル以内を意味すると思います。Spatialiteのどのバージョンかは実際にはわかりません。qgisを介してデータベースを作成し、qgisでguiを使用しています。私がそれを理解できるかどうか見てみましょう
kflaw

それはバージョン4.1.1とsqliteバージョン3.7.17なので、それで動作するはずですか?何が問題なのか、もう少しテストします
kflaw

3

バージョン4.4.0以降、SpatiaLiteは最近隣問題のKNN仮想テーブルインデックスをサポートします。これは、ラインストリングテーブルでポイントテーブルの各ポイントに最も近いラインを見つけるクエリです。

SELECT k.* FROM knn k, points p
WHERE f_table_name = 'linestrings' 
AND ref_geometry = p.geometry
AND max_items = 1;

2

このようにクエリを簡略化できます。

SELECT 
   A.id , 
   B.myValue, 
   MIN(Distance(A.Geometry, B.Geometry)) AS distance
FROM tableOne AS A, tableTwo AS B
GROUP BY A.id, B.myValue

より一般的なソリューションについては、このPostGIS最近傍関数を変換してみる価値があります。http://blog.mackerron.com/2011/03/postgis-nearest-neighbour/


:で、残念ながらコードの結果SQL error: "misuse of aggregate: MIN()"
ラデク・

PostGISの時点では、BostonGIS Webサイトにもいくつかのがありますが、これまでのところ、それらをSpatiaLiteに翻訳することに成功していません:/
radek
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.