PHP / MySQL: выберите местоположения, близкие к заданному местоположению из БД

В PHP у меня есть следующий код для расчета расстояния между двумя точками:

<?php
function distance($lat1, $long1, $lat2, $long2) {
    // DEGREE TO RADIAN
    $latitude1 = $lat1/180*pi();
    $longitude1 = $long1/180*pi();
    $latitude2 = $lat2/180*pi();
    $longitude2 = $long2/180*pi();
    // FORMULA: e = ARCCOS ( SIN(Latitude1) * SIN(Latitude2) + COS(Latitude1) * COS(Latitude2) * COS(Longitude2-Longitude1) ) * EARTH_RADIUS
    $distance = acos(sin($latitude1)*sin($latitude2)+cos($latitude1)*cos($latitude2)*cos($longitude2-$longitude1))*6371;
    return $distance;
}
echo distance(9.9921962, 53.5534074, 9.1807688, 48.7771056); // Hamburg, DE - Stuttgart, DE
?>

Но теперь я хочу выбрать местоположения, близкие к заданному, через PHP из моей базы данных MySQL:

  • Пользователь попадает в свой родной город
  • Мой скрипт получает значения широты / долготы через Google API.
  • В моей базе данных около 200 местоположений с полем для значения широты и полем для значения долготы.
  • Мне нужен код для PHP и MySQL, чтобы выбрать 10 мест, ближайших к родному городу пользователя.

Я надеюсь, что вы можете мне помочь. Заранее спасибо!


person caw    schedule 21.05.2009    source источник


Ответы (7)


MySQL Great Circle Distance (формула Хаверсина) делает именно то, что вам нужно.

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

Расчет расстояния между почтовыми индексами в PHP имеет несколько реализаций PHP: этот алгоритм.

Geo Proximity Search - это почти та же проблема, что и у вас.

person cletus    schedule 24.05.2009
comment
Спасибо, как сказал nOw2, это формула Хаверсина. У меня еще есть реализация PHP, см. Код в моем вопросе. - person caw; 24.05.2009

Может что-то вроде

SELECT field1, field2, ...,
    ACOS(SIN(latitude / 180 * PI()) * SIN(:1) + COS(latitude / 180 * PI()) * COS(:2) * COS(:2 - longtidude)) * 6371 AS distance
    ORDER BY distance ASC;

or

SELECT field1, field2, ...,
    ACOS(SIN(RADIANS(latitude)) * SIN(:1) + COS(RADIANS(latitude)) * COS(:2) * COS(:2 - longtidude)) * 6371 AS distance
    ORDER BY distance ASC;

(прямой перевод из PHP-кода)

:1 и :2 - это $lat2/180*pi() и $long2/180*pi() соответственно.

person itsbth    schedule 24.05.2009
comment
Спасибо, это то же самое, что и ответ nOw2, не так ли? Вы пишете $ lat2 / 180 * pi (). Почему не просто РАДИАНЫ ($ lat2)? Вы использовали его в остальной части запроса, так почему бы не и здесь? - person caw; 24.05.2009
comment
: 1 и: 2 происходят из PHP, в котором нет РАДИАНОВ. Однако можно использовать us2.php.net/deg2rad. - person itsbth; 24.05.2009

Это формула Хаверсина. Вы можете перевести PHP непосредственно в SQL, чтобы вы могли запрашивать базу данных пространственно (альтернативой является извлечение каждой записи из базы данных и прогон данных через PHP). MySQL предоставляет все необходимые математические функции.

Я сделал это для коммерческого веб-сайта, который предоставлял поиск по почтовым / почтовым индексам на расстоянии, так что это, безусловно, возможно без конкретных функций ГИС.

person nOw2    schedule 23.05.2009
comment
Спасибо, отлично работает! :) Я не знал, что в MySQL есть все математические функции. - person caw; 24.05.2009

Для этого доступны функции MySQL.

http://dev.mysql.com/doc/refman/5.0/en/gis-introduction.html

person Frank Farmer    schedule 21.05.2009
comment
Спасибо, но я не могу использовать геопространственные функции MySQL. - person caw; 23.05.2009

MySQL имеет возможность индексировать строки географически. Возможно, вам не придется делать эту математику самостоятельно (вы можете просто попросить MySQL вычислить расстояние между двумя геообъектами и отсортировать по нему ...).

См .: http://forums.mysql.com/read.php?23,159205,159205

person Assaf Lavie    schedule 21.05.2009
comment
Спасибо, но я не могу использовать геопространственные функции MySQL. - person caw; 23.05.2009

Только что коснулся этой темы. Может быть, кому-то будет интересна эта функция, протестированная в MySql 5.7:

    create function GetDistance(lat1 real, lng1 real, lat2 real, lng2 real) returns real no sql
    return ATAN2(SQRT(POW(COS(RADIANS(lat2)) * SIN(RADIANS(lng1 - lng2)), 2) + 
                POW(COS(RADIANS(lat1)) * SIN(RADIANS(lat2)) - SIN(RADIANS(lat1)) *
                COS(RADIANS(lat2)) *  COS(RADIANS(lng1 - lng2)), 2)), 
                (SIN(RADIANS(lat1)) * SIN(RADIANS(lat2)) + COS(RADIANS(lat1)) *
                COS(RADIANS(lat2)) * COS(RADIANS(lng1 - lng2)))) * 6372.795;

Звонок:

select GetDistance(your_latitude, your_longitude, table_field_lat,
                   table_field_lng) as dist from [your_table] limit 5;
person Irina S.    schedule 14.06.2018

Почему бы вам не использовать геопространственные функции MySQL ...? Нет, просто прикалываюсь.

Если 200 записей являются реальными местами, такими как города и т. Д., То в качестве альтернативы вы могли бы использовать API GeoNames?

Следующий веб-сервис предоставит 10 ближайших местоположений к предоставленным широте и долготе:

http://ws.geonames.org/findNearby?lat=47.3&lng=9 < / а>

Источник: http://www.geonames.org/export/web-services.html#findNearbyPlaceName

Полный список: http://www.geonames.org/export/ws-overview.html

person mr-euro    schedule 23.05.2009
comment
Спасибо! У меня есть данные в моей базе данных, поэтому мне не нужно использовать API GeoNames. - person caw; 24.05.2009
comment
Да, я понимаю, но вы можете сопоставить эти 200 записей с ответами от Geonames и получить 10 самых близких совпадений. Это снова предполагает, что ваши 200 записей каким-то образом являются известными местами, а не какими-то случайными позициями. - person mr-euro; 24.05.2009