Поиск по почтовому индексу php/mysql
Я просто ищу предложения о лучшем способе сделать это...
Мне нужно создать функцию поиска, которая ищет "пользователей" в радиусе 50 миль от почтового индекса. У меня есть таблица почтовых индексов, которая содержит все почтовые индексы США с указанием широты и долготы, но я просто пытаюсь найти лучший способ структурировать и запрашивать мои данные...
Должен ли я добавить столбцы широты / долготы в таблицу пользователей и запросить ее для всех пользователей в радиусе заданного почтового индекса? Или я должен запросить таблицу почтовых индексов для всех почтовых индексов, которые попадают в радиус, а затем запросить таблицу пользователей для всех пользователей с результатами (почтовые индексы)? Или же...??? Я открыт для любых предложений на данный момент!
Спасибо!
7 ответов
Вот лучший способ, который я нашел. Конечно, для этого потребуется, чтобы в базе данных были закодированы все ваши почтовые индексы в латах и латах.
// get all the zipcodes within the specified radius - default 20
function zipcodeRadius($lat, $lon, $radius)
{
$radius = $radius ? $radius : 20;
$sql = 'SELECT distinct(ZipCode) FROM zipcode WHERE (3958*3.1415926*sqrt((Latitude-'.$lat.')*(Latitude-'.$lat.') + cos(Latitude/57.29578)*cos('.$lat.'/57.29578)*(Longitude-'.$lon.')*(Longitude-'.$lon.'))/180) <= '.$radius.';';
$result = $this->db->query($sql);
// get each result
$zipcodeList = array();
while($row = $this->db->fetch_array($result))
{
array_push($zipcodeList, $row['ZipCode']);
}
return $zipcodeList;
}
Вы должны быть в состоянии просто включить эту функцию. Передайте ему $ lat и $ lon почтового индекса, для которого вы хотите получить радиус, включите дополнительный радиус и получите список почтовых индексов.
Вы можете очень легко изменить это, чтобы получить всех пользователей с почтовым индексом IN (radius_sql) и получить ваш список пользователей обратно.
Удачного кодирования!
http://www.micahcarrick.com/04-19-2005/php-zip-code-range-and-distance-calculation.html
Я нашел это очень круто.
"запросить в таблице почтовых индексов все почтовые индексы, попадающие в радиус, а затем запросить в таблице пользователей всех пользователей с результатами (почтовые индексы)"
Я обнаружил, что это лучший способ сделать это, если вам не нужно размещать пользователей на карте Google. Если вы просто перечисляете пользователей в диапазоне пробега, должно быть довольно легко запросить базу данных (используя класс) для списка почтовых индексов, а затем выбрать всех пользователей в этих почтовых индексах.
Select * from Users where zip_code IN (19125,19081,19107.........);
Это должно сделать это.
Проверьте поиск близости, показанный здесь:
Использование PHP/MySQL с Google Maps
Если ваши данные находятся в той же записи / проекции / формате (как бы это ни называлось), они могут работать на вас.
Начните здесь, но обратите внимание, что решение не очень быстрое:
PHP Почтовый индекс Диапазон и расчет расстояния
Теперь, чтобы сделать это быстро - мы собираемся заменить поиск, чтобы использовать пространственный индекс:)
Используйте MySQL
Добавьте столбец в базу данных с именем location и установите для него тип POINT
Убедитесь, что он принимает нули прямо сейчас
Запустите следующий SQL-запрос
UPDATE zip_code SET location = PointFromText(CONCAT('POINT(',lon,' ',lat,')'));
Теперь, чтобы столбец не принимал значения NULL
Добавить пространственный индекс в столбец местоположения
В коде из вышеприведенного проекта замените функцию 'get_zips_in_range' на следующую:
function get_zips_in_range($zip, $range, $sort=1, $include_base) { // returns an array of the zip codes within $range of $zip. Returns // an array with keys as zip codes and values as the distance from // the zipcode defined in $zip. $this->chronometer(); // start the clock $details = $this->get_zip_point($zip); // base zip details if ($details == false) return false; // This portion of the routine calculates the minimum and maximum lat and // long within a given range. This portion of the code was written // by Jeff Bearer (http://www.jeffbearer.com). This significanly decreases // the time it takes to execute a query. My demo took 3.2 seconds in // v1.0.0 and now executes in 0.4 seconds! Greate job Jeff! // Find Max - Min Lat / Long for Radius and zero point and query // only zips in that range. $lat = $details[0]; $lon = $details[1]; $return = array(); // declared here for scope $first = true; $radius = $range/69.172; $boundary = "POLYGON(("; for($i=0; $i <= 360; $i += 360/24) { if($first) { $first = false; } else { $boundary .= ', '; } $clon = $radius*cos(deg2rad($i)) + $lon; $clat = $radius*sin(deg2rad($i)) + $lat; $boundary .= "$clon $clat" ; } $boundary .= '))'; $sql = "SELECT zip_code, city, county, state_name, state_prefix, area_code, time_zone, lat, lon FROM zip_code WHERE MBRContains(GeomFromText('$boundary'), location);"; //echo $sql; $r = mysql_query($sql); if (!$r) { // sql error $this->last_error = mysql_error(); return false; } else { while ($row = mysql_fetch_row($r)) { // loop through the results to get the milage from src $dist = $this->calculate_mileage($details[0],$row[7],$details[1],$row[8]); if ($this->units == _UNIT_KILOMETERS) $dist = $dist * _M2KM_FACTOR; $return[str_pad($row[0].', '.$row[1], 5, "0", STR_PAD_LEFT)] = round($dist, $this->decimals); } mysql_free_result($r); } // sort array switch($sort) { case _ZIPS_SORT_BY_DISTANCE_ASC: asort($return); break; case _ZIPS_SORT_BY_DISTANCE_DESC: arsort($return); break; case _ZIPS_SORT_BY_ZIP_ASC: ksort($return); break; case _ZIPS_SORT_BY_ZIP_DESC: krsort($return); break; } $this->last_time = $this->chronometer(); if (empty($return)) return false; return $return; }
Я бы сначала сделал поиск по всем почтовым индексам в радиусе цели. Затем сравните все возвращенные почтовые индексы с вашими пользовательскими почтовыми индексами. Вытащите подходящих пользователей.
Он нашел почтовые индексы в радиусе, нашел этот вызов MySQL:
$query = 'SELECT zzip FROM ' . table .
' WHERE (POW((69.1*(zlongitude-"' .
$long . '")*cos(' . $long .
'/57.3)),"2")+POW((69.1*(zlatitude-"' .
$lat . '")),"2"))<(' . $radius .
'*' . $radius . ')';
MySQL делает всю математику за вас.
Я нашел класс, который использует это здесь: http://www.nucleusdevelopment.com/code/do/zipcode
Надеюсь, это поможет.
Я бы подумал о том, чтобы сначала уменьшить количество кандидатов с ограничивающим квадратом, а потом беспокоиться о радиусе. Вы начинаете с координат почтового индекса, затем рассчитываете длину / широту 50 миль во всех 4 направлениях, затем выбираете только кандидатов в этом поле, используя простые критерии "больше / меньше". Если ваша пользовательская база хорошо распределена, это значительно сокращает ваш набор кандидатов, тогда вам нужно всего лишь выполнить векторную математическую дистанцию, чтобы устранить "углы".
Лат / лонг, который у вас есть для каждого почтового индекса, является географическим центром для этого почтового индекса, верно? Поэтому, если вы сначала найдете почтовые индексы с географическими центрами в пределах 50 миль, а затем пользователи в этих почтовых индексах, вы можете легко возвращать пользователей на расстоянии более 50 миль. Таким образом, вы бы пожертвовали некоторой точностью, делая это таким образом.
Но если у вас много пользователей (больше, чем число почтовых индексов), это будет быстрее, так как вы сначала запросите меньшую таблицу почтовых индексов. И вы можете индексировать почтовые индексы в таблице пользователей, поэтому поиск пользователей с определенным почтовым индексом будет быстрым.
Просто некоторые мысли! Итак, если вы ожидаете большого количества пользователей и радиус 50 миль не обязательно должен быть точным, я бы нашел почтовые индексы в пределах 50 миль, тогда пользователи в этих почтовых индексах.