Làm thế nào để tìm 20 điểm gần nhất một cách hiệu quả [đóng]


9

Nói rằng tôi muốn tìm 20 doanh nghiệp gần nhất gần tôi.

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           

Có 1,6 triệu biz. Tất nhiên thật ngu ngốc khi tính khoảng cách cho tất cả chúng và sau đó sắp xếp nó.

Đó là nơi chỉ số không gian địa lý đá phải không?

Vì vậy, tôi cần phải sử dụng SQL comman nào?

Ghi chú:

  1. Tôi đang sử dụng chỉ số không gian mysql myisam . Tuy nhiên tôi đã không chỉ định điều này trước đây. Vì vậy, tôi sẽ chấp nhận những người trả lời nó để thể hiện sự đánh giá cao của tôi và hỏi một câu hỏi khác.
  2. Tôi không muốn tính khoảng cách cho cả bảng
  3. Tôi không muốn tính khoảng cách cho bất kỳ khu vực nào vẫn không hiệu quả
  4. Tôi muốn tính khoảng cách cho số điểm hợp lý vì tôi muốn sắp xếp các điểm theo khoảng cách và có thể hiển thị điểm 1-20, 21-40, 41-60, v.v.

3
bài chéo dba.stackexchange.com/questions/19595/... (Cũng có vẻ juju xấu để có một câu hỏi mà mỗi câu trả lời được giải quyết PostGIS)
Evan Carroll

Câu trả lời:


7

Các truy vấn không gian chắc chắn là điều để sử dụng.

Với PostGIS, trước tiên tôi sẽ thử một cái gì đó đơn giản như thế này và điều chỉnh phạm vi khi cần:

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

Điều này sẽ so sánh các điểm (thực tế là các hộp giới hạn của chúng) bằng cách sử dụng chỉ số không gian, vì vậy nó sẽ nhanh. Một cách tiếp cận khác mà bạn nghĩ đến là đệm vị trí của bạn và sau đó giao vùng đệm đó với dữ liệu gốc, có thể còn hiệu quả hơn nữa.


9

Nếu tất cả những gì bạn đang tìm kiếm là các tìm kiếm điểm gần (truy vấn lân cận gần nhất), thì bạn không muốn sử dụng ST_DWithin hoặc ST_Distance + ORDER BYs cũ cho điều đó.

Không còn nữa.

Bây giờ PostGIS 2.0 đã xuất xưởng, bạn nên sử dụng hỗ trợ chỉ mục knngist (một tính năng PostgreQuery gốc). Nó sẽ là mệnh lệnh của cường độ nhanh hơn.

Một đoạn trích từ mục blog này mô tả cách sử dụng ý chính mà không cần 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)

Thật thú vị, truyền tải chỉ mục sẽ trả về các tính năng theo thứ tự gần, do đó không cần phải thực hiện sắp xếp (tức là theo thứ tự) cho kết quả!

Tuy nhiên, nếu bạn muốn sử dụng nó cùng với PostGIS, bây giờ nó thực sự dễ dàng. Chỉ cần làm theo các hướng dẫn .

Phần có liên quan là đây:

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

Nhưng đừng hiểu ý tôi. Thời gian tự nó :)


Đây sẽ là một câu trả lời tốt. Tuy nhiên, tôi đang sử dụng mysql myisam. Tôi quên thêm điều đó.
dùng4951

Vì vậy, +1 nhưng tôi không thể chọn đây là câu trả lời của mình. Tôi có nên tạo một câu hỏi khác?
dùng4951

@JimThio MySQL không có chỉ số hàng xóm gần nhất nên bạn sẽ phải dựa vào cách tiếp cận giống như PostGIS trước khi có một truy vấn hàng xóm gần nhất (ST_Dwithin với ORDER BY ST_Distance). Chào mừng trở lại thời trung cổ :)
Ragi Yaser Burhum

Vì vậy, tôi đã đi đến mongodb? Hãy để tôi đoán. Điểm có chỉ số không gian trên mysql là gì nếu bạn thậm chí không thể làm điều đơn giản nhất như tìm 20 điểm gần nhất?
dùng4951

1
Bạn có thể tìm thấy điểm gần nhất bằng cửa sổ. Điều này cũng đúng với bất kỳ cơ sở dữ liệu không gian nào khác như được mô tả bởi @lynxlynxlynx. Bạn có thể tiếp tục tăng cửa sổ bằng cách nhân nó với hai. Vâng, điều tương tự cũng đúng với Mongo hoặc bất kỳ cơ sở dữ liệu nào khác. Vấn đề là bạn cắt giảm hầu hết các tính năng khác. Bên cạnh đó, mọi người đều biết rằng cho đến gần đây, MySQL chưa bao giờ là đối thủ nặng ký cho bất kỳ thứ gì về không gian.
Ragi Yaser Burhum

8

Với PostGIS 2.0 trên PostgreSQL 9.1, bạn có thể sử dụng toán tử lân cận gần nhất được lập chỉ mục KNN , ví dụ:

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

Ở trên nên truy vấn trong vòng một vài mili giây.

Đối với bội số tiếp theo là 20, sửa đổi để OFFSET 20, OFFSET 40, vv ...


Tôi có thể biết ý nghĩa của nó là <->gì không? Cảm ơn.
Northtree

<->là một toán tử trả về khoảng cách 2D.
Mike T

1

Không gian MySQL

Mọi người ở đây đang nói với bạn cách làm điều đó với PostgreSQL bằng KNN, mà không cho bạn biết những lợi thế. Sử dụng MySQL, bạn không thể xác định hàng xóm gần nhất mà không tính khoảng cách cho tất cả các hàng xóm. Điều đó cực kỳ chậm. Với PostgreSQL, điều này có thể được thực hiện trên một chỉ mục. Cả MySQL và MariaDB hiện tại đều không hỗ trợ KNN

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.