20 개의 가장 가까운 점을 효율적으로 찾는 방법 [닫힌]


9

내 주변에서 가장 가까운 20 개의 비즈니스를 찾고 싶다고 가정 해 보겠습니다.

My table structure is like this:

    BusinessID  varchar(250)    utf8_unicode_ci         No  None        Browse distinct values  Change  Drop    Primary     Unique  Index   Fulltext
    Prominent   double          No  None        Browse distinct values  Change  Drop    Primary     Unique  Index   Fulltext
    LatLong     point           No  None        Browse distinct values  Change  Drop    Primary     Unique  Index   Fulltext
    FullTextSearch  varchar(600)    utf8_bin        No  None        Browse distinct values  Change  Drop    Primary     Unique  Index   Fulltext
With selected: Check All / Uncheck All With selected:
Print viewPrint view Propose table structurePropose table structureDocumentation
Add new fieldAdd field(s) At End of Table At Beginning of Table After
Indexes: Documentation
Action  Keyname Type    Unique  Packed  Field   Cardinality Collation   Null    Comment
Edit    Drop    PRIMARY BTREE   Yes No  BusinessID  1611454 A       
Edit    Drop    Prominent   BTREE   No  No  Prominent   0   A       
Edit    Drop    LatLong BTREE   No  No  LatLong (25)    0   A       
Edit    Drop    sx_mytable_coords   SPATIAL No  No  LatLong (32)    0   A       
Edit    Drop    FullTextSearch  FULLTEXT    No  No  FullTextSearch  0           

160 만 개의 비즈가 있습니다. 물론 모든 거리를 계산 한 다음 정렬하는 것은 어리석은 일입니다.

그것이 지리 공간 지수가 올바른 곳입니까?

그렇다면 어떤 SQL 명령을 캐스팅해야합니까?

노트 :

  1. 내가 사용하고 MySQL의의 MyISAM 공간 인덱스를. 그러나 나는 이것을 전에 지정하지 않았다. 그래서 나는 그것에 감사하는 사람들을 받아 들여서 감사를 표하고 또 다른 질문을 할 것입니다.
  2. 전체 테이블의 거리를 계산하고 싶지 않습니다.
  3. 여전히 비효율적 인 지역의 거리를 계산하고 싶지 않습니다.
  4. 거리별로 점을 정렬하고 점 1-20, 21-40, 41-60 등을 표시 할 수 있기 때문에 합리적인 수의 점에 대한 거리를 계산하고 싶습니다.

3
cross post dba.stackexchange.com/questions/19595/… (또한 모든 답변이 PostGIS를 다루는 질문이있는 것은 나쁜 주주 인 것 같습니다)
Evan Carroll

답변:


7

공간 쿼리는 확실히 사용하는 것입니다.

PostGIS를 사용하여 먼저 이와 같은 단순한 것을 시도하고 필요에 따라 범위를 조정합니다.

SELECT * 
FROM table AS a
WHERE ST_DWithin (mylocation, a.LatLong, 10000) -- 10km
ORDER BY ST_Distance (mylocation, a.LatLong)
LIMIT 20

공간 인덱스를 사용하여 점 (실제로 경계 상자)을 비교하므로 속도가 빨라야합니다. 염두에 두어야 할 또 다른 방법은 위치를 버퍼링 한 다음 해당 버퍼를 원본 데이터와 교차시키는 것입니다.


9

당신이 찾고있는 모든 근접 포인트 검색 (가장 가까운 쿼리)이라면, 당신은 그것을 위해 이전 ST_DWithin 또는 ST_Distance + ORDER BY를 사용하고 싶지 않습니다.

더 이상은 아닙니다.

PostGIS 2.0이 출시되었으므로 knngist 인덱스 지원 (기본 PostgreSQL 기능)을 사용해야합니다. 수십 배 빠릅니다.

PostGIS없이 knn gist를 사용하는 방법을 설명하는이 블로그 항목 의 발췌 :

$ create table test ( position point );

CREATE TABLE
Table created. Now let’s insert some random points:
$ insert into test (position) select point( random() * 1000, random() * 1000) from generate_series(1,1000000);

INSERT 0 1000000
1 million points should be enough for my example. All of them have both X and Y in range <0, 1000). Now we just need the index:
$ create index q on test using gist ( position );

CREATE INDEX
And we can find some rows close to center of the points cloud:
$ select *, position <-> point(500,500) from test order by position <-> point(500,500) limit 10;

              position               |     ?column?

-------------------------------------+-------------------

 (499.965638387948,499.452529009432) | 0.548548271254899

 (500.473062973469,500.450353138149) |  0.65315122744144

 (500.277776736766,500.743471086025) | 0.793668174518778

 (499.986605718732,500.844359863549) | 0.844466095200968

 (500.858531333506,500.130807515234) | 0.868439207229501

 (500.96702715382,499.853323679417)  | 0.978087654172406

 (500.975443981588,500.170825514942) | 0.990289007195055

 (499.201623722911,499.368405900896) |  1.01799596553335

 (498.899147845805,500.683960970491) |  1.29602394829404

 (498.38217580691,499.178630765527)  |  1.81438764851559

(10 rows)
And how about speed?
$ explain analyze select *, position <-> point(500,500) from test order by position <-> point(500,500) limit 10;

                                                        QUERY PLAN

--------------------------------------------------------------------------------------------------------------------------

 Limit  (cost=0.00..0.77 rows=10 width=16) (actual time=0.164..0.475 rows=10 loops=1)

   ->  Index Scan using q on test  (cost=0.00..76512.60 rows=1000000 width=16) (actual time=0.163..0.473 rows=10 loops=1)

         Order By: ("position" <-> '(500,500)'::point)

 Total runtime: 0.505 ms

(4 rows)

흥미롭게도 인덱스 순회는 근접한 순서대로 피처를 반환하므로 결과에 대해 정렬 (즉, 정렬) 할 필요가 없습니다!

그러나 PostGIS와 함께 사용하려면 정말 쉽습니다. 다음 지침을 따르십시오 .

관련 부분은 다음과 같습니다.

SELECT name, gid
FROM geonames
ORDER BY geom <-> st_setsrid(st_makepoint(-90,40),4326)
LIMIT 10;

그러나 내 말을 듣지 마십시오. 스스로 시간 :)


이것은 좋은 대답이 될 것입니다. 그러나 mysql myisam을 사용하고 있습니다. 나는 그것을 추가하는 것을 잊었다.
user4951

따라서 +1이지만 이것을 내 답변으로 선택할 수 없습니다. 다른 질문을 작성해야합니까?
user4951

@JimThio MySQL에는 가장 가까운 네이버 인덱스가 없으므로 가장 가까운 네이버 쿼리 (ORDER BY ST_Distance와 함께 ST_Dwithin)가 있기 전에 PostGIS와 유사한 접근 방식을 사용해야합니다. 중세에 다시 오신 것을 환영합니다 :)
Ragi Yaser Burhum

그래서 mongodb에 가야합니까? 어디 보자. 20 개의 가장 가까운 점을 찾는 것과 같은 가장 간단한 일조차 할 수 없다면 mysql에 공간 인덱스를 갖는 요점은 무엇입니까?
user4951

1
창을 사용하여 가장 가까운 지점을 찾을 수 있습니다. @lynxlynxlynx에서 설명한 다른 공간 데이터베이스에서도 마찬가지입니다. 창에 2를 곱하여 창을 계속 늘릴 수 있습니다. 예, Mongo 또는 다른 데이터베이스에서도 마찬가지입니다. 요점은 대부분의 다른 기능을 줄이는 것입니다. 게다가, 모든 사람들은 최근까지도 MySQL이 공간적인 것에 대한 심각한 경쟁자는 결코 아니라는 것을 알고 있습니다.
Ragi Yaser Burhum

8

PostgreSQL 9.1의 PostGIS 2.0을 사용하면 KNN 색인화 된 가장 가까운 이웃 연산자를 사용할있습니다 .

SELECT *, geom <-> ST_MakePoint(-90, 40) AS distance
FROM table
ORDER BY geom <-> ST_MakePoint(-90, 40)
LIMIT 20 OFFSET 0;

위의 내용은 몇 밀리 초 내에 쿼리해야합니다.

20의 다음 배수의 OFFSET 20경우 OFFSET 40, 등으로 수정하십시오 ...


무슨 뜻인지 알 수 있을까요 <->? 감사.
northtree

<->2D 거리를 반환하는 연산자입니다.
Mike T

1

MySQL 공간

여기의 모든 사람들은 KNN을 사용하여 PostgreSQL로 이점을 얻는 방법을 알려주는 방법을 알려줍니다. MySQL을 사용하면 모든 이웃에 대한 거리를 계산하지 않고 가장 가까운 이웃을 결정할 수 없습니다 . 매우 느립니다. PostgreSQL을 사용하면 인덱스에서 수행 할 수 있습니다. MySQL과 MariaDB는 현재 KNN을 지원하지 않습니다.

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