en yakın 20 noktayı verimli bir şekilde bulma [kapalı]


9

Yakınımda en yakın 20 iş bulmak istediğimi söyle.

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           

1.6 milyon bizs var. Tabii ki hepsi için mesafeyi hesaplamak ve sonra sıralamak aptalca.

Coğrafi mekansal indeks burada başlıyor mu?

Peki hangi SQL comman'ı yayınlamam gerekiyor?

Not:

  1. Ben kullanıyorum MySQL MyISAM mekansal indeksi. Ancak bunu daha önce belirtmedim. Bu yüzden cevap verenleri takdirimi göstermek ve başka bir soru sormak için kabul edeceğim.
  2. Tüm tablo için mesafeyi hesaplamak istemiyorum
  3. Hala verimsiz olan herhangi bir bölge için mesafeyi hesaplamak istemiyorum
  4. Mesafeleri makul sayıda nokta için hesaplamak istiyorum çünkü noktaları mesafeye göre sıralamak ve 1-20, 21-40, 41-60 vb. Noktaları gösterebilmek istiyorum.

3
çapraz yazı dba.stackexchange.com/questions/19595/… (Ayrıca her cevabın PostGIS'e hitap ettiği bir soruya sahip olmak için kötü juju gibi görünüyor)
Evan Carroll

Yanıtlar:


7

Mekansal sorgular kesinlikle kullanılacak olan şeydir.

PostGIS ile önce böyle basit bir şey dener ve aralığı gerektiği gibi değiştiririm:

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

Bu, mekansal indeksi kullanarak noktaları (aslında sınırlayıcı kutuları) karşılaştırır, bu yüzden hızlı olmalıdır. Akla gelen başka bir yaklaşım, konumunuzu arabelleğe almak ve daha sonra bu tamponu orijinal verilerle kesiştirmektir; bu daha da verimli olabilir.


9

Aradığınız tek şey yakınlık noktası aramalarıysa (en yakın komşu sorguları), bunun için eski ST_DWithin veya ST_Distance + ORDER BY'ları kullanmak istemezsiniz.

Artık değil.

PostGIS 2.0 artık gönderildiğine göre knngist dizin desteğini (yerel bir PostgreSQL özelliği) kullanıyor olmalısınız. Daha hızlı büyüklük emirleri olacak.

Bu blog girişinden PostGIS olmadan knn gist'in nasıl kullanılacağını açıklayan bir alıntı :

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

İlginçtir ki, dizin geçişi özellikleri yakınlık sırasına göre döndürecektir, bu nedenle sonuçlar için bir sıralama yapmaya (yani, sipariş vermeye) gerek yoktur!

Ancak, PostGIS ile birlikte kullanmak istiyorsanız, şimdi gerçekten kolay. Sadece bu talimatları izleyin .

İlgili kısım şudur:

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

Ama sözümü alma. Kendinize zaman ayırın :)


Bu iyi bir cevap olacak. Ancak, mysql myisam kullanıyorum. Bunu eklemeyi unutuyorum.
user4951

Yani +1 ama bunu cevabım olarak seçemiyorum. Başka bir soru oluşturmalı mıyım?
user4951

@JimThio MySQL en yakın komşu dizinine sahip olmadığından, en yakın komşu sorgusu (ORDER BY ST_Distance ile ST_Dwithin) olmadan önce PostGIS benzeri yaklaşıma güvenmeniz gerekecektir. Orta çağa tekrar hoş geldiniz :)
Ragi Yaser Burhum

Yani mongodb'a mı gitmeliyim? Tahmin etmeme izin ver. 20 en yakın noktayı bulmak gibi en basit şeyi bile yapamıyorsanız, mysql'de bir uzamsal dizin oluşturmanın anlamı nedir?
user4951

1
En yakın noktayı bir pencere kullanarak bulabilirsiniz. Aynı şey @lynxlynxlynx tarafından tarif edilen diğer tüm uzamsal veritabanı için de geçerlidir. Pencereyi ikiyle çarparak artırmaya devam edebilirsiniz. Evet, aynı durum Mongo veya başka herhangi bir veritabanı için de geçerlidir. Buradaki nokta, diğer özelliklerin çoğunu azaltmanızdır. Ayrıca, herkes yakın zamana kadar MySQL'in mekansal hiçbir şey için ciddi bir yarışmacı olmadığını biliyor.
Ragi Yaser Burhum

8

PostgreSQL 9.1 üzerindeki PostGIS 2.0 ile KNN dizinli en yakın komşu operatörü kullanabilirsiniz , örneğin:

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

Yukarıdakiler birkaç milisaniye içinde sorgulanmalıdır.

20 sonraki katları için şu adrese değiştirmek OFFSET 20, OFFSET 40vs ...


Ne anlama geldiğini bilebilir miyim <->? Teşekkürler.
northtree

<->2B mesafeyi döndüren bir operatördür.
Mike T

1

MySQL Mekansal

Buradaki herkes, size avantajlarını söylemeden KNN kullanarak PostgreSQL ile nasıl yapılacağını anlatıyor. MySQL kullanarak, tüm komşuların mesafesini hesaplamadan en yakın komşuyu belirleyemezsiniz . Bu son derece yavaş. PostgreSQL ile bu bir indekste yapılabilir. Ne MySQL ne de MariaDB şu anda KNN'yi desteklemiyor

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.