วิธีค้นหา 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           

มี 1.6 ล้าน bizs แน่นอนว่ามันโง่ที่จะคำนวณระยะทางสำหรับพวกเขาทั้งหมดแล้วเรียงลำดับ

นั่นคือสิ่งที่ดัชนีเชิงพื้นที่เชิงภูมิศาสตร์เตะใช่มั้ย

ดังนั้นฉันต้องการใช้ SQL comman แบบใด

บันทึก:

  1. ฉันใช้ดัชนีเชิงพื้นที่ของmysql myisam อย่างไรก็ตามฉันไม่ได้ระบุสิ่งนี้มาก่อน ดังนั้นฉันจะยอมรับผู้ที่ตอบคำถามเพื่อแสดงความขอบคุณและถามคำถามอื่น
  2. ฉันไม่ต้องการคำนวณระยะทางสำหรับทั้งตาราง
  3. ฉันไม่ต้องการคำนวณระยะทางสำหรับภูมิภาคใด ๆ ที่ยังไม่มีประสิทธิภาพ
  4. ฉันต้องการคำนวณระยะทางสำหรับจำนวนจุดที่เหมาะสมเพราะฉันต้องการเรียงลำดับตามระยะทางและสามารถแสดงจุดที่ 1-20, 21-40, 41-60 เป็นต้น

3
ข้ามโพสต์dba.stackexchange.com/questions/19595/ … (ดูเหมือนว่า juju จะมีคำถามที่คำตอบทุกคำตอบคือ 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 ดั้งเดิม) มันจะเป็นลำดับความสำคัญเร็วกว่า

ข้อความที่ตัดตอนมาจากรายการบล็อกนี้ซึ่งอธิบายวิธีใช้ knn gist โดยไม่มี PostGIS :

$ 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 ฉันลืมที่จะเพิ่ม
4951

ดังนั้น +1 แต่ฉันไม่สามารถเลือกสิ่งนี้เป็นคำตอบของฉัน ฉันควรสร้างคำถามอื่นหรือไม่
user4951

@JimThio MySQL ไม่มีดัชนีเพื่อนบ้านที่ใกล้ที่สุดดังนั้นคุณจะต้องพึ่งพาวิธีการคล้ายกับ PostGIS ก่อนที่จะมีข้อความค้นหาเพื่อนบ้านที่ใกล้ที่สุด (ST_Dwithin พร้อม ORDER BY ST_Distance) ยินดีต้อนรับกลับสู่ยุคกลาง :)
Ragi Yaser Burhum

ดังนั้นฉันต้องไปที่ Mongodb? ให้ฉันเดา. จุดของการมีดัชนีเชิงพื้นที่ใน mysql คืออะไรถ้าคุณไม่สามารถทำสิ่งที่ง่ายที่สุดเช่นการหา 20 จุดที่ใกล้เคียงที่สุด?
4951

1
คุณสามารถค้นหาจุดที่ใกล้เคียงที่สุดโดยใช้หน้าต่าง เช่นเดียวกับฐานข้อมูลเชิงพื้นที่อื่น ๆ ตามที่อธิบายโดย @lynxlynxlynx คุณสามารถเพิ่มหน้าต่างโดยคูณด้วยสอง ใช่เช่นเดียวกันกับ Mongo หรือฐานข้อมูลอื่น ๆ ประเด็นคือคุณลดทอนคุณลักษณะอื่น ๆ ส่วนใหญ่ นอกจากนี้ทุกคนรู้ว่าเมื่อไม่นานมานี้ MySQL ไม่เคยเป็นคู่แข่งที่ร้ายแรงสำหรับเรื่องอวกาศ
Ragi Yaser Burhum

8

ด้วย PostGIS 2.0 บน PostgreSQL 9.1 คุณสามารถใช้ตัวดำเนินการเพื่อนบ้านที่ใกล้เคียงกับดัชนี 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 Spatial

ทุกคนที่นี่บอกวิธีใช้กับ PostgreSQL โดยใช้ KNN โดยไม่บอกข้อดี ใช้ MySQL คุณไม่สามารถตรวจสอบเพื่อนบ้านที่ใกล้ที่สุดโดยไม่ต้องคำนวณระยะทางสำหรับทั้งหมดของเพื่อนบ้าน นั่นช้ามาก ด้วย PostgreSQL สิ่งนี้สามารถทำได้บนดัชนี ทั้ง MySQL และ MariaDB ปัจจุบันรองรับ KNN

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.