Arhn - архитектура программирования

MySQL - найти точки в радиусе от базы данных

У меня есть таблица, в которой есть столбец POINT, содержащий широту и долготу различных мест.

Затем у меня также есть местоположение пользователей из геолокации в браузере.

Что мне нужно сделать, так это найти все записи из таблицы, где значение POINT находится в радиусе 10 км (или радиусе X км), упорядоченные по расстоянию с ближайшим первым.

Моя таблица имеет индекс SPATIAL в столбце POINT.

15.03.2017

  • Вы не можете найти точки внутри круга с помощью индекса, но если вы определите ограничивающую рамку для индексированного поиска, а затем отфильтруете на основе расстояния от центра, вы получите быстрые результаты. 18.03.2017
  • Приведенные здесь решения плохо работают для больших наборов данных. Если это проблема, см. mysql.rjweb.org/doc.php/find_nearest_in_mysql. 01.05.2020

Ответы:


1

В настоящее время я работаю над проектом, в котором я рассчитываю расстояния между несколькими местоположениями. Я использую следующий запрос для выбора object_id, которые находятся в пределах заданного радиуса.

SELECT id, 
( 6371 * 
    ACOS( 
        COS( RADIANS( db_latitude ) ) * 
        COS( RADIANS( $user_latitude ) ) * 
        COS( RADIANS( $user_longitude ) - 
        RADIANS( db_longitude ) ) + 
        SIN( RADIANS( db_latitude ) ) * 
        SIN( RADIANS( $user_latitude) ) 
    ) 
) 
AS distance FROM the_table HAVING distance <= $the_radius ORDER BY distance ASC"

Я не могу объяснить саму формулу ACOS, потому что я получил ее из исследований.

db_latitude = database latitude field
db_longitude = database longitude field
$user_latitude = browser latitude coördinate
$user_longitude = browser longitude coördinate
$the_radius = the radius that you want to search in

В километрах.

15.03.2017
  • Привет @Bas и спасибо за это, но моя широта / долгота хранится как поле MySQL POINT, а не два отдельных числа с плавающей запятой. Насколько я понял, это правильный способ хранения этой информации, поэтому я могу иметь индекс SPATIAL для эффективности. 15.03.2017
  • Привет, @tip2tail, извини, что упустил из виду эту деталь. Я не знаком с полем "POINT". Нашел этот пост стека, надеюсь, он поможет вам stackoverflow.com/a/21170928/5567106 15.03.2017
  • Это был ответ, хотя мне пришлось вывести свою POINT на широту и долготу с помощью функций X () и Y () MySQL. 25.03.2017
  • Если вам нужен диапазон в МИЛЯХ, замените 6371 на 3959. 02.07.2017
  • Разве это не потребует вычисления ВСЕХ существующих точек в базе данных одну за другой? кажется, что это просто не будет работать, если у вас сохранены миллионы точек? 11.11.2017
  • @EvrenYurtesen просматривает каждую запись. Я не знаю, насколько быстро это будет с таким количеством записей. Я использовал это с базой данных, в которой у меня было 17 тысяч записей, и это было довольно быстро. 12.11.2017
  • @Bas van Dijk, вы выбираете широту и долготу для каждой строки, а затем вычисляете «расстояние» до введенной пользователем точки (не говоря уже о том, что вы используете дорогостоящие функции тригонометрии). Затем отфильтруйте результаты по радиусу. Да, вы просматриваете каждую строку в своей таблице каждый раз, когда запускаете запрос. Используйте EXPLAIN, чтобы узнать, сколько строк используется. Но для 17 тысяч строк и нескольких запросов за раз это сработает. Нет, когда у вас есть большое количество строк и больше доступа, он просто не будет масштабироваться. Я бы не стал использовать это в производстве. 12.11.2017
  • @EvrenYurtesen, когда у вас есть большие наборы данных, вы можете классифицировать данные. 13.11.2017
  • Да, извините, я ошибочно прочитал ваш предыдущий ответ, так как «это не выглядит», нужно больше спать. Думаю, я бы сначала использовал квадратную область для фильтрации данных с минимальной/максимальной широтой/долготой, а затем использовал бы вашу формулу для оставшихся точек. Это если мне нужна предельная точность. Если бы я мог обойтись квадратной площадью, я мог бы избежать всех этих вычислений. В любом случае, спасибо за ответ. 13.11.2017
  • я удивлен, что нет способа просто отсортировать по точке и нужно выполнять расчет каждый раз 05.07.2020
  • Я могу понять ваше разочарование, может быть, через 3 года есть лучшее решение? Если вы найдете лучшее решение, пожалуйста, дайте мне знать :) 06.07.2020

  • 2

    Приведенный ниже запрос действительно работал для меня:

    $query = "SELECT *,
        ( 6371 * 
        acos( 
        cos( radians( ".$user_lat." ) ) * 
          cos( radians( lat ) ) * 
          cos( radians( lng ) - 
          radians( ".$user_lng." ) ) + 
            sin( radians( ".$user_lat." ) ) * 
              sin( radians( lat ) ) ) ) 
              AS distance FROM parkings 
              HAVING distance <= ".$radius." ORDER BY distance ASC";
    
      $stmt = $conn->execute($query);
    
      $rows = $stmt->fetchAll('assoc');
    

    где: $user_lat и $user_lng — широта и долгота браузера, $radius = 10, имя таблицы —parkings

    25.09.2017

    3

    Может вам поможет, https://ru.scribd.com/presentation/2569355/Geo-Distance-Search-with-MySQL

    Для Django я использую это

        dist = 20 #дистанция 20 км
        mylon = 51.5289156201 # долгота центра
        mylat = 46.0209384922 # широта 
        lon1 = mylon-dist/abs(math.cos(math.radians(mylat))*111.0) # 1 градус широты = 111 км
        lon2 = mylon+dist/abs(math.cos(math.radians(mylat))*111.0)
        lat1 = mylat-(dist/111.0)
        lat2 = mylat+(dist/111.0)
        profiles = UserProfile.objects.filter(lat__range=(lat1, lat2)).filter(lon__range=(lon1, lon2))
    

    Он ищет всех пользователей в квадрате 20 км.

    15.03.2017
  • Привет @Nickita и спасибо за это. Это очень похоже на ответ выше, пожалуйста, смотрите мои комментарии там. 15.03.2017
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..