근접 검색에 geohash를 사용하십니까?


30

포인트 근접 지역 검색 시간을 최적화하려고합니다.

내 입력은 위도, 경도 포인트이며 사전 계산 된 위치 세트에서 n 개의 가장 가까운 포인트를 검색하고 있습니다.

사전 계산 된 위치 색인을 작성하는 데 얼마나 많은 시간 / 공간이 소요되는지는 신경 쓰지 않지만 쿼리는 매우 빠릅니다.

geohash를 검색 키로 사용하려고합니다. 처음에는 키의 X 문자에 대한 결과가 있는지 확인한 다음 결과를 볼 때까지 키 끝에서 문자를 계속 트리밍합니다.

지리 인덱스 기술에 대한 이해 (지금은 매우 드물게)에게이 접근 방식은 알려진 다른 모든 구현 (예 : R Tree 및 Co)과 비교할 때 쿼리 시간 측면에서 가장 빠른 결과를 얻을 수 있어야합니다.


지오 해시를 사용하고 동쪽 / 북쪽에 위도 / 경도를 저장하는 것 사이에 큰 차이가 있습니까? 아마도 두 가지 모두 문자 / 숫자를 자르면 검색 정확도를 변경할 수 있습니다. (이것은 순전히 호기심의 문제입니다-나는이 주제에 익숙하지 않습니다).
djq

이 포인트는 데이터베이스 나 메모리에 저장됩니까?
Marc Pfister

@MarcPfister이 문제는 2 세입니다 (사용 사례). 항상 커뮤니티와 관련이 있으므로 활발한 토론을 계속하겠습니다. 논의 된 데이터는 실제로 nosql 데이터베이스에 저장되었습니다.
Maxim Veksler

또한이 질문에 대답 한 시점부터 MongoDB는 geohash 인덱싱 및 검색을 성공적으로 구현 했으며이 점을 증명합니다. 아직 구현에 대한 백서를 보지 못했지만 코드는 공개되어 관심있는 모든 사람이 사용할 수 있습니다.
Maxim Veksler

그래. CouchDB는 현재 공간 해시를 사용했으며 아마도 geohash도 사용했습니다.
Marc Pfister

답변:


25

물론 가능합니다. 그리고 그것은 매우 빠를 수 있습니다. (집약적 인 계산 비트도 배포 가능)

여러 가지 방법이 있지만, 내가 작업 한 한 가지 방법은 정렬 된 정수 기반 지오 해시 목록을 사용 하고 특정 지오 해시 해상도 (해상도는 distance기준에 근접한)에 대해 가장 가까운 인접 지오 해시 범위를 모두 찾는 것입니다. 지오 해시 범위를 쿼리하여 주변 포인트 목록을 얻습니다. 나는 이것을 위해 redis와 nodejs (즉, 자바 스크립트)를 사용합니다. Redis는 매우 빠르며 정렬 된 범위를 매우 빠르게 검색 할 수 있지만 SQL 데이터베이스가 수행 할 수있는 많은 인덱싱 쿼리 조작 작업을 수행 할 수는 없습니다.

방법은 여기에 요약되어 있습니다 : https://github.com/yinqiwen/ardb/wiki/Spatial-Index

그러나 그것의 요지는 (링크를 바꾸어 말하면) :

  1. 모든 지오 해시 포인트를 원하는 최고 해상도 (액세스 가능한 경우 최대 64 비트 정수 또는 자바 스크립트의 경우 52 비트)로 정렬 된 세트 (예 : redis의 zset)로 저장합니다. 요즘 대부분의 geohash 라이브러리에는 geohash 정수 함수가 내장되어 있으므로보다 일반적인 base32 geohash 대신 이들을 사용해야합니다.
  2. 검색하려는 반경을 기준으로 검색 영역과 일치하는 비트 심도 / 해상도를 찾아야하며 이는 저장된 지오 해시 비트 심도보다 작거나 같아야합니다. 링크 된 사이트에는 geohash의 비트 깊이를 미터 단위의 경계 상자 영역과 연관시키는 테이블이 있습니다.
  3. 그런 다음이 낮은 해상도에서 원래 좌표를 다시 해시합니다.
  4. 이 낮은 해상도에서 8 개의 인접 (n, ne, e, se, s, sw, w, nw) 지오 해시 영역도 찾습니다. 네이버 방식을 수행해야하는 이유는 서로 바로 옆에있는 두 좌표가 완전히 다른 지오 해시를 가질 수 있기 때문에 검색에 포함 된 영역을 평균화해야하기 때문입니다.
  5. 이 낮은 해상도에서 모든 인접 지오 해시를 얻으면 3 단계부터 좌표의 지오 해시를 목록에 추가하십시오.
  6. 그런 다음 이 9 개 영역을 다루는 범위 내에서 검색 할 다양한 geohash 값 을 빌드해야합니다 . 5 단계의 값은 범위 하한이며 각 값에 1을 추가하면 범위 상한을 얻게됩니다. 따라서 각각 하한과 상한 해시 제한이있는 9 개의 범위 배열이 있어야합니다 (총 18 개의 지오 해시). 이 지오 해시는 2 단계에서 여전히 낮은 해상도에 있습니다.
  7. 그런 다음 18 개의 모든 지오 해시를 데이터베이스에 모든 지오 해시를 저장 한 비트 심도 / 해상도로 변환하십시오. 일반적으로 원하는 비트 심도로 비트 시프트하여이를 수행합니다.
  8. 이제이 9 개 범위 내의 포인트에 대한 범위 쿼리를 수행 할 수 있으며 대략 모든 원래 포인트의 거리 내에있는 모든 포인트를 얻을 수 있습니다. 중복이 없으므로 교차점을 수행 할 필요가 없으며 순수한 범위 쿼리 만 매우 빠릅니다. (예 : redis : ZRANGEBYSCORE zsetname lowerLimit upperLimit,이 단계에서 생성 된 9 개 범위에 걸쳐)

다음을 통해 추가로 최적화 할 수 있습니다.

  1. 6 단계에서 9 개의 범위를 취하여 서로 연결되는 위치를 찾습니다. 일반적으로 좌표의 위치에 따라 9 개의 개별 범위를 약 4 또는 5로 줄일 수 있습니다. 쿼리 시간을 절반으로 줄일 수 있습니다.
  2. 최종 범위가 확보되면 재사용을 위해 유지해야합니다. 이 범위를 계산하는 데 대부분의 처리 시간이 걸릴 수 있으므로 원래 좌표가 많이 변경되지 않지만 동일한 거리 쿼리를 다시 수행해야하는 경우 매번 계산하는 대신 준비를 유지해야합니다.
  3. redis를 사용하는 경우 쿼리를 MULTI / EXEC로 결합하여 조금 더 나은 성능을 위해 파이프 라인을 만드십시오.
  4. 가장 중요한 부분 : 계산을 한곳에서 수행하는 대신 클라이언트에 2-7 단계를 배포 할 수 있습니다. 이는 수백만 건의 요청이 들어오는 상황에서 CPU로드를 크게 줄입니다.

정밀도를 중요하게 생각하면 반환 된 결과에 원 거리 / 호버 버스터 유형 함수를 사용하여 정확도를 더욱 향상시킬 수 있습니다.

다음은 일반적인 base32 지오 해시와 redis 대신 SQL 쿼리를 사용하는 비슷한 기술입니다. https://github.com/davetroy/geohash-js

나는 내 자신의 것을 꽂는 것을 의미하지는 않지만 이것을 구현하기 쉬운 nodejs & redis 용 모듈을 작성했습니다. 원하는 경우 코드를 살펴보십시오 : https://github.com/arjunmehta/node-georedis


몇 가지 후속 조치 Q-이웃을 어떻게 계산합니까? 정수 해싱은 트리밍을 허용합니까 (base32 z- 곡선 기반은 지원하지 않습니다 (예 : base32 geohash에서 7은 8에서 멀리 떨어져 있음). geohash-js github.com/davetroy/geohash-js/blob/ 마스터 / matrix.txt ? 가정이 알고리즘은 근접 지오 포인트 geohash와-JS를 생산하는 동안 비슷한 않는 인접 셀의 O (1) 계산 만.
맥심 Veksler

와우, 이것은 매우 유용했다. 이 답변에 대한 많은 전문 지식. 매우 도전적인 작업
simon

9

이 질문은 여러 가지 방법으로 읽을 수 있습니다. 나는 당신이 많은 수의 포인트를 가지고 있고 좌표 쌍으로 주어진 임의의 포인트로 반복적으로 포인트를 프로브하고 n을 미리 고정하여 프로브에 가장 가까운 n 포인트를 얻으려고한다고 해석합니다. (기본적으로 n이 다를 경우 가능한 모든 n에 대한 데이터 구조를 설정하고 각 프로브와 함께 O (1) 시간에 선택할 수 있습니다. 설정 시간이 오래 걸리고 많은 RAM이 필요합니다. 그러한 우려를 무시하라는 지시를받습니다.)

모든 포인트 의 order-n Voronoi 다이어그램 을 작성하십시오 . 이렇게하면 평면이 연결된 영역으로 분할되며 각 영역은 동일한 n 개의 이웃을 갖습니다. 이것은 많은 효율적인 솔루션을 가지고있는 다각형 문제로 상황을 줄입니다.

Voronoi 다이어그램에 벡터 데이터 구조를 사용하면 포인트 인 다각형 검색에 O (log (n)) 시간이 걸립니다. 실용적인 목적으로 다이어그램의 래스터 버전을 작성하여 매우 작은 암시 적 계수로이 O (1)을 만들 수 있습니다. 래스터의 셀 값은 (i) 가장 가까운 n 개의 포인트 목록에 대한 포인터 또는 (ii)이 셀이 다이어그램에서 둘 이상의 영역에 걸쳐 있음을 나타냅니다. (x, y)에서 임의의 점에 대한 테스트는 다음과 같습니다.

Fetch the cell value for (x,y).
If the value is a list of points, return it.
Else apply a vector point-in-polygon algorithm to (x,y).

O (1) 성능을 달성하려면 래스터 메쉬는 여러 보로 노이 영역을 가로 지르는 셀에 상대적으로 적은 프로브 포인트가 떨어질 정도로 충분히 미세해야합니다. 그리드 저장 비용이 많이 들기 때문에 항상이 작업을 수행 할 수 있습니다.


3

나는 정확하게 이것을 위해 geohash를 사용합니다. 필자는 피라미드 스타일 정보 시스템을 사용하여 근접 검색을 구현해야했기 때문입니다. 여기서 8 단계 정밀도를 가진 지오 해시는 '기본'이었고 7 번째 정밀도의 지오 해시를위한 새로운 총계를 형성했습니다. . 이 총계는 면적, 지표의 유형 등이었습니다. 매우 멋진 것들을 수행하는 매우 멋진 방법이었습니다.

따라서 8 단계 지오 해시는 다음과 같은 정보를 포함합니다.

유형 : 잔디 에이커 : 1.23

7, 6 등은 다음과 같은 정보를 포함합니다.

grass_types : 123 에이커 : 6502

이것은 항상 가장 낮은 정밀도로 구축되었습니다. 이를 통해 모든 종류의 재미있는 통계를 매우 빠르게 수행 할 수있었습니다. 또한 GeoJSON을 사용하여 각 지오 해시 참조에 지오메트리 참조를 할당 할 수있었습니다.

현재 뷰포트를 구성하는 가장 큰 지오 해시를 찾은 다음 뷰포트 내에서 두 번째로 큰 정밀도의 지오 해시를 찾기 위해 여러 함수를 작성할 수있었습니다. 이것은 원하는 정밀도에 대해 최소 '86ssaaaa'및 최대 '86sszzzz'를 쿼리하는 인덱스 범위 쿼리로 쉽게 확장 될 수 있습니다.

MongoDB를 사용 하여이 작업을 수행하고 있습니다.


3

2018 년 및 일부 수학 자금 또는 Geohash의 역사적 증거를 업데이트합니다.

  • geohash와 대한 영감이 있었다 이진수 간단한 interlave 아마도 같이 소수점 숫자 순 인터리빙 알고리즘의 최적화 C 제곱 .

  • 이진 인터 레이싱은 자연스럽게 Z- 오더-곡선 인덱스 전략을 가져 왔으며, Geohash 발명가 는 "최고의 프랙탈 곡선을 찾기"시작 하지 않았습니다 .

S2 형상 라이브러리 사용

S2- 형상 접근 방식은 지구의 구면 토폴로지 (입방체)를 사용하고 선택적 투영 (모든 셀의 모양과 면적이 거의 동일 함 )을 사용하고 Hilbert- 곡선을 사용한 색인 생성이 Z- 검토 보다 낫기 때문에 Geohash보다 낫습니다. 주문 곡선 :

... 우린 더 잘할 수있다 ... 우상단에서 좌 하단 ​​쿼드로 갈 때의 불연속성은 결과적으로 연속적으로 만들 수있는 일부 범위를 분할해야한다. (...) Quadtrees 및 Hilbert Curves를 사용한 공간 인덱싱에 대한 모든 불연속 (...) blog.notdot.net/2009를 완전히 제거 할 수 있습니다.

이제 무료이며 효율적인 라이브러리입니다. https://s2geometry.io를 참조 하십시오.

추신 :도있다 (좋은) 비 공식 단순화 된 버전 NodeJS의s2-geometry 많은 '놀이터', 추가 기능 및 데모 등 s2.sidewalklabs.com .


2

redis에서 GEORADIUS 쿼리를 사용하는 것이 좋습니다.

GEOADD 호출을 사용하여 가장 적합한 geohash 레벨로 샤딩 된 데이터를 푸시하십시오.

또한 이것-> ProximityHash를 살펴보십시오 .

ProximityHash는 중심 좌표와 반경이 주어지면 원형 영역을 커버하는 지오 해시 세트를 생성합니다. 또한 GeoRaptor를 사용하는 추가 옵션이있어 최고 수준에서 시작하여 최적의 혼합이 만들어 질 때까지 반복하여 원을 나타 내기 위해 다양한 수준에서 지오 해시의 최상의 조합을 만듭니다. 결과 정확도는 시작 geohash 수준과 동일하게 유지되지만 데이터 크기가 상당히 줄어들어 속도와 성능이 향상됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.