Як найкраще здійснити пошук найближчого сусіда в mysql?


10

Отже, коротше кажучи,

  1. Яким має бути тип даних широти та довготи?
  2. Яку команду SQL я повинен зателефонувати, щоб отримати, наприклад, перші 100 найближчих ресторанів?

Детальніше:

У мене 100k бізнес запису кожен з широтою та довготою. Я бачу, що MySQL насправді підтримує тип даних під назвою точка. Чи варто використовувати це замість цього?

Чи підтримує MySQL систему зберігання KDTree http://en.wikipedia.org/wiki/File:KDTree-animation.gif

Краще використовувати тип даних даних, а не звичайний тип даних з поплавком для зберігання широти і довготи?

Врешті-решт, я хочу знайти такі речі, як перші 100 ресторанів, які є найближчими до точок 105,6, наприклад, і мої бази даних містять безліч біз-пойтів. Очевидно, що обчислення відстані одна за одною для кожного запису і для кожної точки буде O (n) і, отже, відстій.

Зауважте, що мені відомо простіше рішення, описане в розділі Як Application Like Yelp Ефективно отримувати інформацію про відстань від бази даних, і я застосую це також для початку. Це гарна відповідь.

Однак я думаю, що є одна відповідь на врожай, який повинен перевершити це право? Насправді, зберігання місця на основі широти та довготи та знаходження найближчих до нього матеріалів є дуже поширеною проблемою. Я думаю, що mysql має для цього спеціальний дизайн. Чи є це?

Де я можу дізнатися більше про це? Дякую.



Схоже, рішення тут dba.stackexchange.com/questions/4210/… - найкраще рішення. Я маю на увазі, що є ця річ, яку називають простором MYSQL. Однак ви не можете витягнути такі речі, як де (відстань (x) <20). Це ще не реалізовано.
user4951

Відповіді:


11

Що стосується моделей дизайну, питання Yelp - це досить стандартні речі.

Для більш складної відповіді вам, напевно, знадобиться геопросторова відстань. Ось захоплюючий пункт про цю тему (і ось також версія у форматі PDF). Однак математика, що займається, є досить потворною.

З їх слайду:

set @orig_lat=122.4058; set @orig_lon=37.7907;
set @dist=10;

SELECT *, 3956 * 2 * ASIN(SQRT(
POWER(SIN((@orig_lat - abs(dest.lat)) * pi()/180 / 2), 2) +  COS(@orig_lat * pi()/180 ) * COS(abs(dest.lat) * pi()/180) *  POWER(SIN((@orig_lon  dest.lon) * pi()/180 / 2), 2) )) as  distance
FROM hotels dest 
having distance < @dist
ORDER BY distance limit 10

Існує довша, більш поглиблена відповідь про геопросторову відстань на стеку Overflow .

Але ви все одно хочете обмежити результати широтою та довготою.

Зрештою, я б уникнув тип даних POINT і пішов би з широтою / довготою. Наразі немає можливості визначити відстань між двома точками, тому вам доведеться зберігати широту / довготу для цього розрахунку.

Останнє посилання: ви також можете перевірити цей потік SO щодо прискорення запитів за допомогою просторових індексів.


[ПОМИЛКА в запиті 4] Ви маєте помилку в своєму синтаксисі SQL; перевірте посібник, що відповідає вашій версії сервера MySQL, чи правильний синтаксис використовувати біля '- dest.lon) * pi () / 180/2), 2))) як відстань ВІД network_pos dest, що має d' у рядку 2
Felipe

Привіт, @dist на мільйонах? дякую
Хорхе Олаф Ерландсен

1
@OlafErlandsen так це в милі
Ян ван дер Вегт

4

Точкові типи даних в порядку; Ви можете просто викликати X (координату) / Y (координату), щоб отримати значення Lat / Lon.

Наприклад:

SELECT id, 
(3959 
    * acos(
        cos(radians(37)) 
        * cos(radians(Y(coord)))
        * cos(radians(X(coord)) - radians(-122)) 
        + sin(radians(37))
        * sin(radians(Y(coord)))
      )
) AS distance 
FROM markers HAVING distance < 25 
ORDER BY distance LIMIT 20;

37 - лат і -122 - лон? А 25 - це метри чи км?
Феліпе

1

Знайдіть 100 ресторанів, найближчих до якоїсь координати. Див. Ефективний код на сторінці http://mysql.rjweb.org/doc.php/latlng. Він включає в себе збережену функцію для обчислення відстані "великий круг".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.