SpatiaLite에서 포인트 위치가있는 두 테이블 사이에서 가장 가까운 이웃을 찾으십니까?


10

나는 오늘 SpatiaLite를 가지고 놀기 시작했고 이미 문제에 걸려 넘어졌습니다.

tableOne에 저장된 각 포인트 위치에 대해 tableTwo에서 가장 가까운 (선형 거리) 포인트를 선택하고 싶습니다.

지금까지 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)

일을하는 것 같습니다.

두 가지 질문 :

VIEW를 만들지 않고 이러한 쿼리를 수행하는 방법이 있습니까?

성능 향상을 위해이 쿼리를 최적화하는 다른 방법이 있습니까? 실제 시나리오에서 tableOne은 수백-커플 수천 개의 레코드와 tableTwo-130 만 개의 레코드를 갖게됩니다.


나는 당신에게 몇 배 더 빠른 접근 방법을 줄 수 있지만, 공간 대신에 postgresql 9 knngist 인덱스를 사용해야합니다 ...
Ragi Yaser Burhum

실제로 GRASS, ArcGIS, QGIS, SQLServer 및 기타 다른 공간 db / Desktop GIS보다 빠릅니다 (Oracle에서 가장 가까운 인접 기능을 시도하지는 않았습니다). 옵션인지 알려주십시오.
Ragi Yaser Burhum

@ Ragi : PostGIS가 그러한 문제를 처리하는 데 훨씬 효율적인 방법이라는 것을 알고 있습니다. 그러나이 연습의 궁극적 인 목표는 소형 휴대용 앱을 만드는 것입니다.이 경우 SpatiaLite가 승자입니다.
radek

휴대용 앱을위한 개발 플랫폼은 무엇입니까?
Allan Adair

@Allan : 현재 작업중인 Windows Server 2008 및 Ubuntu
radek

답변:


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를 처음 사용합니다. 어떤 제안? 또한, 나는 궁극적으로 이것을 백만 점 이상에서 실행하고 싶습니다
kflaw

나는 또한이 진술의 목적을 이해하지 못한다 : g1.OGC_FID <> g2.OGC_FID
kflaw

또한 내 결과에서 null 거리를 얻습니다. 나는이 줄을 가지고 놀았습니다 : AND ST_Contains (ST_Expand (g1.geometry, 50), g2.geometry)뿐만 아니라 ID를 받고 있어도 제거하고 거리 값을 얻지 못합니다
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'를 실제 테이블 이름 (테이블 이름)으로 바꿔야합니까? 나는 어느 쪽이든 시도했지만 여전히 아무것도 반환하지 않습니다. 왜 이것이 될 수
있습니까

당신이 옳 f_table_name = 'A'아야합니다 f_table_name = 'tableOne'. 이 요청은 공간적 공간> 4.x ( SpatialIndex가상 테이블 사용)를 가정합니다 . search_frame사용 사례 에 맞게를 조정하려고 했습니까 ? 위의 예에서 포인트는 최대 거리 10000 미터 인 것으로 가정합니다.
사무엘

나는 검색 프레임 값을 가지고 놀았는데, 그것이 나를 위해 작동 해야하는 10000 미터 이내의 수단을 가정합니다. 나는 실제로 어떤 버전의 공간 라이트를 알지 못하고 qgis를 통해 데이터베이스를 만들었고 qgis에서 gui를 사용하고 있습니다. 내가 알아낼 수 있는지 보자
kflaw

sqlite 버전 3.7.17이있는 버전 4.1.1이므로 작동해야합니까? 문제가 무엇인지 더 궁금해합니다
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 Nearest Neighbor 기능을 변환하는 것이 좋습니다 : http://blog.mackerron.com/2011/03/postgis-nearest-neighbour/


불행히도 코드 결과는 다음과 같습니다.SQL error: "misuse of aggregate: MIN()"
radek

PostGIS 기준 으로 BostonGIS 웹 사이트에 몇 가지 예가 있지만 지금까지는 SpatiaLite로 번역하는 데 성공하지 못했습니다 : /
radek
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.