Я просто ищу предложения по наилучшему способу сделать это …
Мне нужно создать функцию поиска, которая ищет «пользователей» в радиусе 50 миль от почтового индекса. У меня есть таблица zip-кода, которая содержит все почтовые индексы США с их широтой / долготой, но я просто пытаюсь найти лучший способ структурирования и запроса моих данных …
Должен ли я добавлять столбцы широты / долготы в таблицу пользователей и запрашивать его для всех пользователей в радиусе заданного почтового индекса? Или я должен запросить таблицу zip-кодов для всех почтовых индексов, которые попадают в радиус, затем запросить таблицу пользователей для всех пользователей с результатами (почтовые индексы)? Или… ??? Я открыт для любых предложений на этом этапе!
Благодаря!
Вот лучший способ, который я нашел. Конечно, это потребует, чтобы у вас были все ваши zipcodes lat / lon, закодированные в базе данных.
// 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 zipcode, для которого нужен радиус, включите дополнительный радиус и получите список zipcodes.
Вы можете очень легко изменить это, чтобы получить всех пользователей, где zipcode IN (radius_sql) и вернуть пользователей списка.
Счастливое кодирование!
http://www.micahcarrick.com/04-19-2005/php-zip-code-range-and-distance-calculation.html
Я нашел это очень удивительным.
"запросите таблицу zip-кодов для всех почтовых кодов, которые попадают в радиус, затем запросите таблицу пользователей для всех пользователей с результатами (почтовые индексы)"
Я нашел, что это лучший способ сделать это, если вам не нужно размещать пользователей на карте Google. Если вы просто перечисляете пользователей в диапазоне пробега, довольно просто запросить базу данных (используя класс) для списка zips, а затем выбрать всех пользователей в этих zipcodes.
Select * from Users where zip_code IN (19125,19081,19107.........);
Это должно сделать это.
Начните здесь, но обратите внимание, что решение не очень быстрое:
Интерпретация диапазона Zip и PHP
Теперь, чтобы сделать это быстро – мы собираемся заменить поиск, чтобы использовать пространственный индекс 🙂
Использовать MySQL
Добавьте столбец в базу данных с именем location и введите его POINT
Удостоверьтесь, что он принимает nulls прямо сейчас
Запустите следующий 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; }
Ознакомьтесь с предлагаемым здесь поиском близости:
Использование PHP / MySQL с Google Maps
Если ваши данные находятся в одной и той же нотации / проекции / формате (независимо от того, что называется), это может сработать для вас.
Сначала я хотел бы сократить число кандидатов с ограничивающим квадратом, а затем беспокоиться о радиусе в качестве второго шага. Вы начинаете с координат zipcode, затем вычисляете длинный / лат 50 миль во всех 4 направлениях, затем выбираете только кандидатов в этом поле, используя простые критерии большей / меньшей, чем критерии. Если ваша база пользователей хорошо распределена, это значительно сокращает ваш кандидат, тогда вам нужно сделать только векторную математику расстояния, чтобы устранить «углы».
Сначала я выполнил поиск всех zipcodes в радиусе цели. Затем сравните все возвращенные zipcodes с вашими zip-кодами таблицы пользователей. Вытащите соответствующих пользователей.
Он находит zipcodes в радиусе, нашел этот вызов 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 миль, тогда пользователи в этих почтовых индексах, вы можете легко вернуть пользователей более чем на 50 миль. Таким образом, вы пожертвуете некоторой точностью, делая это таким образом.
Но если у вас много пользователей (больше, чем количество почтовых индексов), это будет быстрее, так как сначала вы запрашиваете меньшую таблицу почтовых индексов. И вы можете индексировать почтовые индексы в таблице пользователей, поэтому поиск пользователей с определенным почтовым индексом будет быстрым.
Просто некоторые мысли! Итак, если вы ожидаете, что многие пользователи и радиус 50 миль не обязательно будут точными, я бы нашел почтовые индексы в пределах 50 миль, а затем пользователи в этих почтовых индексах.