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
クロスポストdba.stackexchange.com/questions/19595/…(すべての回答がPostGISに対応しているという質問をするのは、jujuにとっても悪いようです)
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

これは、空間インデックスを使用してポイント(実際にはそれらの境界ボックス)を比較するため、高速である必要があります。頭に浮かぶもう1つのアプローチは、位置をバッファリングしてから、そのバッファを元のデータと交差させることです。


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

したがって、+ 1ですが、これを私の回答として選択することはできません。別の質問を作成する必要がありますか?
user4951

@JimThio MySQLには最近傍インデックスがないため、最近傍クエリ(ORDER BY ST_Distanceを指定したST_Dwithin)が発生する前にPostGISのようなアプローチに依存する必要があります。中世へようこそ:)
Ragi Yaser Burhum

だから私はmongodbに行かなければなりませんか?私に当てさせてください。20の最も近いポイントを見つけるなどの最も簡単なことさえできない場合、mysqlで空間インデックスを使用することのポイントは何ですか?
user4951 2012年

1
ウィンドウを使用して最も近いポイントを見つけることができます。@lynxlynxlynxで説明されている他の空間データベースについても同様です。ウィンドウを2倍することで、ウィンドウを拡大し続けることができます。はい、同じことがモンゴや他のデータベースにも当てはまります。ポイントは、他のほとんどの機能を削減することです。その上、ごく最近まで、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 20OFFSET 40など...


どういう意味<->ですか?ありがとう。
ノースツリー2018年

<->2D距離を返す演算子です。
マイクT

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.