Найти длинные / лат в пределах 20 миль от пользователя длинные / лат - PullRequest
3 голосов
/ 14 сентября 2011

Я работаю над приложением, в котором пользователь может искать элементы рядом с его местоположением.

Когда пользователь регистрируется на моем сервисе, его длинные / лат координаты берутся (это на самом деле взято из почтового индекса/ почтовый индекс и затем ищется через Google для длинных / лат).Это также происходит, когда пользователь добавляет элемент, его просят указать почтовый индекс элемента, и он преобразуется в длинный / лат.

Мой вопрос заключается в том, как выполнить запрос с использованием MySQL, которыйбудет искать, скажем, в 20 милях от местоположения пользователя и получать все предметы в радиусе 20 миль?

Ответы [ 6 ]

2 голосов
/ 14 сентября 2011

Когда вы сохраняете данные широты и долготы, вы также можете хранить так называемый «геопространственный индекс», который в основном представляет собой строку, которая кодирует обе части данных одновременно.Одной из таких схем индексации является алгоритм Geohash , который использует последовательность битов для разделения земного шара на все более и более маленькие прямоугольники.

Затем, когда вы хотите выполнить поиск по расстоянию, вы сначала сужаетеобласть поиска на основе геохеша, затем отфильтруйте результаты, протестировав евклидово расстояние или воспользовавшись формулой Haversine .

Другим вариантом является использование отдельной базы данныхдля выполнения этого вида запроса.Например, MongoDB изначально поддерживает геопространственную индексацию , и CouchDB может сделать это с небольшой помощью geocouch .

Если вернуться к MySQL, эта презентация может оказаться полезной: Поиск географического расстояния с MySQL

2 голосов
/ 14 сентября 2011

Предполагая, что точность на самом деле не проблема (беря квадрат вместо круга и игнорируя местность), вы можете сделать что-то вроде этого:

SELECT ... FROM ...
WHERE (ABS(firstLong - secondLong) < 20) AND (ABS(firstLat - secondLat) < 20);

Если вы хотите сделать его кругомвместо этого просто напишите немного более сложную математическую формулу для расстояния: SQRT(longDelta*longDelta + latDelta*latDelta) < 20

1 голос
/ 15 декабря 2016

В python вы можете использовать kdtree, попробуйте этот фрагмент кода:

сначала вам нужно будет установить pysal

import pysal
from pysal.cg.kdtree import KDTree    

locations = [(40.702566, -73.816859),
         (40.70546, -73.810708),
         (40.709179, -73.820574),
         (40.700486, -73.807969),
         (40.694624, -73.820593),
         (40.695132, -73.820841),
         (40.694095, -73.821334),
         (40.694165, -73.822368),
         (40.695077, -73.822817),
         (40.6747769261, -73.8092618174)] 
tree = KDTree(locations, distance_metric='Arc', radius=pysal.cg.RADIUS_EARTH_MILES)
current_point = (40.709523, -73.802472)
# get all points within 1 mile of 'current_point'
indices = tree.query_ball_point(current_point, 1)
for i in indices:
    print(locations[i])
1 голос
/ 14 сентября 2011

В зависимости от используемой платформы существует несколько вариантов:

Грубая сила - возьмите элементы в базе данных и запустите линейную функцию географического расстояния между вашим длинным / широтным и координатами элементов примерно так:

public decimal GeoDistance(decimal lat1, decimal lng1, decimal lat2, decimal lng2)
{
    double r = 6378.7; //km

    decimal p = (decimal)(Math.PI / 180.0);
    lat1 *= p; lat2 *= p; lng1 *= p; lng2 *= p;

    return (decimal)(r * (Math.Acos(Math.Sin((double)lat1) * Math.Sin((double)lat2) + Math.Cos((double)lat1) * Math.Cos((double)lat2) * Math.Cos((double)lng2 - (double)lng1))));
}

Если вы используете MS SQL Server 2008 (другие движки баз данных также могут поддерживать), вы можете использовать методы географии

0 голосов
/ 14 сентября 2011

Чтобы быть быстродействующим, вы не хотите выполнять полное сканирование базы данных и вычислять расстояния для каждой строки, вам нужны условия, которые можно проиндексировать.Самый простой способ сделать это - вычислить поле с минимальной / максимальной широтой и минимальной / максимальной долготой и использовать МЕЖДУ, чтобы исключить все, что находится за пределами этих диапазонов.Поскольку вы имеете дело только с американскими местоположениями (на основе почтового индекса), вам не придется беспокоиться о переходе между +180 и -180 градусов.коробка в лат / лонг, когда ваши условия в милях.Вам нужно конвертировать мили в градусы.Для широты это легко, просто разделите 360 градусов по окружности земли и умножьте на 20;0,289625 градусов.Долгота является более жесткой, потому что она изменяется по широте, окружность примерно равна косинусу (широта) * 24901,461;20 миль - это 20 * 360 / (cos (широта) * 24901.461).

0 голосов
/ 14 сентября 2011

Вы можете найти интересующий меня предыдущий ответ, который очень эффективен:

Рассчитать расстояние между почтовыми индексами и пользователями

"Найти ближайшее местоположение"Почтовый индекс?

Надеюсь, это поможет:)

...