특정 랜드 마크 범위 내의 모든 랜드 마크를 효율적으로 검색하려면 어떻게합니까?


14

특정 랜드 마크의 10km / 마일 (이 스토리에서는 중요하지 않음)의 모든 랜드 마크를 찾는 지리 검색 프로젝트부터 시작하려고합니다.

예를 들어 1,000,000 개의 랜드 마크 데이터베이스가 있다고 가정하겠습니다. 특정 좌표로 10 마일 범위의 랜드 마크에서 모든 랜드 마크를 찾으려면 검색에서 랜드 마크와 1,000,000 개의 랜드 마크 사이의 거리를 계산해야합니다.

더 좋은 방법이 있습니까?

대안으로 생각한 것은 국가, 지역, 도시, 이웃, 비즈니스, 역사 등과 같은 랜드 마크를 비즈니스가 이웃 또는 도시의 일부가 될 수 있도록 범주화하는 것입니다. 도시는 지역, 국가 등의 일부입니다. 계산 목록의 범위를 좁힐 수 있지만 검색이 빠르고 정확하기 위해서는 많은 작업이 필요한 것처럼 보입니다.

Google Maps API가 도움이 될 수 있습니까?


5
맨해튼의 빠른 거리 계산을 수행 한 다음 10km2 내에 있지만 반경 10km 밖에있는 랜드 마크를 제외하기 위해 두 번째 필터를 수행하면 간단히 많은 것을 제거 할 수 있습니다.
Neil

3
어떤 데이터베이스 기술을 사용하고 있습니까? 대답은 데이터베이스에 구애받지 않습니다.
jpmc26

1
@Neil 두 번째 패스로 실제 거리를 계산하지 않고 x와 y가 모두 원점에서 7km 떨어진 곳에있는 랜드 마크를 포함 할 수 있습니다.
JimmyJames

답변:


10

SQL Server 2008부터 위치 (위도 / 경도 쌍)를 저장하고 위치 관련 쿼리를 쉽게 작성할 수 있는 지리 데이터 형식이 있습니다.

이에 대한 자세한 내용은 기존 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 이내에있는 모든 것을 찾는 기본 쿼리 (질문에 대한 두 번째 답변)

-- 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

11
@KonradRudolph : 행 수가 많은 테이블에서 쿼리하는 데 사용되는 SQL 열의 경우와 같습니다. 맞습니다. 그러나 해당 주석은 답변으로 게시 된 거의 모든 SQL 쿼리에 적용됩니다.
Flater

2
질문에서 "MS SQL Server"를 어디에서 읽었습니까?
Doc Brown

3
@Flater 나는 그것이 명백하고 중복 적이라는 것에 동의하지만 OP의 문구는 그러한 메커니즘을 알지 못한다고 제안하는 것 같습니다.
Konrad Rudolph

2
@ jpmc26 : 당신은 내가 유효한 옵션을 나열하고 다른 옵션을 포함하지 않았다는 사실에 놀랐습니다. 뭐? PostGIS를 추가하는 것이 적절하다고 생각되면 스스로 답변을 추가하고 자신과 같은 생각을 가지고 있지 않다는 이유로 다른 사람을 비난하지 마십시오.
Flater

3
귀하의 답변은 기본적으로 MS SQL 판매 피치로 나타납니다. 귀하의 의견은 데이터베이스 가 실제로 상황을 더 잘 보이게 만드는 것에 대해 실제로 묻지 않고 데이터베이스 를 수 만 달러의 비용으로 전환 할 것을 제안 합니다. 또한 OP가 실제로 쿼리를 구현하는 방법을 설명하거나 공간 인덱스를 사용하고 공간을 계산하는 것이 다른 DB와 마찬가지로 MS SQL에서 간단하지 않다는 사실에 대해서도 설명하지 않습니다. 또한 기본 개념에 대해서도 논의하지 않습니다. "유효한지"에 관계없이 나쁜 대답입니다. 그것이 나를 귀찮게하는 이유입니다.
jpmc26

29

GIS (지리 정보 시스템) 쿼리 를 지원하는 데이터베이스를 사용하십시오 . 대부분의 데이터베이스는 이것을 완벽 하게 지원하거나 확장명을 갖지만 세부 사항은 데이터베이스에 따라 다릅니다 ( 정답 은 Flater가 SQL Server의 구문을 보여줍니다).

애플리케이션 내에서 이러한 쿼리를 구현해야하는 경우 공간 쿼리 (예 : kd Tree) 를 허용하는 데이터 구조를 구현할 수 있습니다 . 이것은 트리의 각 레벨이 다른 좌표 차원에서 분할된다는 점을 제외하면 이진 검색 트리와 같습니다. 이를 통해 검색을 더 작은 가능한 후보 세트로 제한 할 수 있습니다. 효과적으로 검색을“10km 반경”으로 각 좌표 치수에 대한 경계로 변환하고 트리에 반복 될 때 경계를 강화합니다.



8
PostGIS 는 최고의 무료 옵션입니다. 그것은 지원 훨씬, 훨씬 더 SQL 서버의 아주 기본적인 GIS 유형과 기능을보다. 그러나 이것은 기본 기능입니다.
jpmc26

@ amon 나는 jpmc26의 의견을 좋은 추가로 여기며 귀하의 예를 비판하는 것은 아닙니다. "처음부터 시작하려면 라이센스가있는 DB에 대한 비용을 지불 할 필요가 없습니다.이 무료 오픈 소스 데이터베이스는 트릭을 잘 수행합니다."
mgarciaisaia

11

더 좋은 방법이 있습니다. 공간 인덱스 를 사용해야합니다 . 이 인덱스는 지오메트리에 대한 메타 데이터를 구성하여 멀리있는 지오메트리를 매우 빠르게 필터링하여 설명하는 계산을 피함으로써 많은 CPU주기를 절약합니다. 모든 주요 관계형 데이터베이스는 공간 지오메트리 유형과 함께 사용할 수있는 인덱스를 제공하기 때문에 스스로 구현하는 것을 방해해서는 안됩니다.

"거리 내"쿼리 (일부 다른 지오메트리의 특정 거리 내에있는 지오메트리에 대한 쿼리)입니다. 이들은 매우 표준적이고 매우 해결 된 문제이며 위의 모든 데이터베이스에서 가능합니다 (여러 개의 내장).

  • PostGIS : ST_DWithin
  • SQL Server : STDistance(이 기능의 3D 지리 버전에서 인덱스 사용이 지원되는지 확실하지 않습니다)
  • Oracle : SDO_WITHIN_DISTANCE(이것은 인덱스 사용을 트리거한다고 명시 적으로 말하지 않습니다. 쿼리 계획을 다시 확인하겠습니다. 인덱스를 사용하려면를 적용해야 할 수도 있습니다 SDO_FILTER.)
  • MySQL : 여전히 이해하고 있습니다.

인덱스 사용 트리거를위한 ​​해결 방법

이러한 쿼리에서 시스템이 공간 인덱스를 사용하지 못하게 하는 최악의 경우 필터를 추가 할 수 있습니다. 당신은 길이 2 * (검색 거리)의 측면과 사각형 경계 상자를 생성하여 검색 지점에서 중심과에 대한 상자 경계 테이블 형상 '비교하는 것 실제 거리를 확인하기 전에. 그것이 PostGIS ST_DWithin가 내부적으로하는 일입니다.


GIS 거리

공간 인덱스는 환상적이고 문제에 대한 올바른 솔루션이지만 거리 계산은 논리적으로 복잡해질 수 있습니다. 특히 데이터가 어떤 투영 (기본적으로 좌표계의 모든 매개 변수)에 저장되어 있는지 걱정해야합니다 . 대부분의 2D 투영 (다양한 위도 / 경도 투영과 같은 각도 좌표계 이외의 것)은 길이를 크게 왜곡합니다. 예를 들어, Web Mercator 투영 (Google, Bing 및 기타 모든 주요 기본지도 제공 업체 에서 사용)은 적도에서 멀어 질수록 영역과 거리가 점점 넓어집니다 . 공식적으로 GIS 교육을받지 않았기 때문에 잘못되었을 수도 있지만 2D 프로젝션에서 볼 수있는 가장 좋은 점은전 세계에서 하나의 일정한 지점 . 아니요

결론은 수학이 정확한지 확인해야한다는 것입니다. 개발 관점에서 가장 간단한 방법은 각도 프로젝션 (이것은 종종 "지리적"이라고 함)과 스페 로이드 모델을 사용하여 수학을 지원하는 함수를 사용하는 것입니다. 그러나 이러한 계산은 2D에 비해 약간 비쌉니다. 일부 DB는 색인 생성을 지원하지 않을 수 있습니다. 그러나 그것들을 사용하여 수용 가능한 성능을 얻을 수 있다면 아마도 그 방법 일 것입니다. 또 다른 일반적인 옵션은 데이터가 세계의 특정 부분에 국한된 경우 거리와 영역이 거의 정확하게 일치하는 UTM 영역과 같은 지역 투영입니다. 앱에 가장 적합한 것은 특정 요구 사항에 따라 다릅니다.

내장 공간 인덱스를 사용하지 않는 경우에도 적용됩니다. 데이터는 현재 사용 중이거나 미래에 어떤 기술이나 기술을 사용하든 관계없이 예상치가 있으며 현재 쿼리 및 계산에 영향을 미치고 있습니다.


3

가능한 경우 데이터베이스에서 특정 지원을 사용하는 것이 가장 합리적인 방법이라는 데 동의합니다.

그러나 특정 지원없이 데이터베이스 에서이 작업을 수행 해야하는 경우 (y> (y1-rad)) AND (y <(y1 + rad)) AND (x> ( x1-rad)) 및 (x <(x1 + rad)). 당신의 포인트가 대략 정사각형에 대한 분포 쿼리를 가지고 있다고 가정하면 당신의 진정한 일치 플러스 약 30 %의 추가 거짓 일치를 얻을 수 있습니다. 그런 다음 잘못된 일치 항목을 제거 할 수 있습니다.


그러나 적절한 공간 인덱스가 없으면 이러한 쿼리는 인덱스에 따라 지정된 위도 또는 경도 범위 내의 모든 항목, 즉 정사각형이 아닌 "대역"에서 최악의 전체 데이터베이스를 스캔합니다. 성능을 저하시키지 않으려면 공간 인덱스를 지원하는 데이터베이스를 사용하십시오!
jcaron

내가 믿는 @jcaron이 쿼리는 일반 B 트리 인덱스 최적화 할 수 xy. (아마도 결합, 아마도 별도의 내가 실제로 잘 작동하는 알아 내기 위해 조금 프로필 것입니다..)
jpmc26

@ jpmc26 아니, 안돼. 그것을 통해 생각, 당신은 볼 수 있습니다.
jcaron

@jcaron 아마도 간단하지 않은 것에 대해 비밀이 없다면 더 좋을 것입니다. B- 트리는 BETWEEN쿼리에 사용될 수 있습니다 . 최악의 경우 2 개의 인덱스를 가질 수 없었고 각 인덱스의 필터링 된 결과가 결합 된 이유를 알 수 없습니다. (이것은 다중 인덱스를 사용할 가치가 있다고 생각 될 때 RDBMS가 내부적으로하는 일입니다.) 결합 된 인덱스가 작동하는 경우 첫 번째 레벨에서 한 차원을 완전히 필터링 한 다음 두 번째 레벨에서 상대적으로 빠르게 좁혀 야합니다.
jpmc26

2
@jcaron 실제로 같은 뭔가를 인덱스를 사용하여 y between -68 and -69 and x between 10 and 11해당 작업에 대한 더 나은 일을 수행하지만, 물론 공간 인덱스의
후안 카를로스 Oropeza
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.