Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/232.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
php/mysql邮政编码邻近搜索_Php_Sql_Mysql - Fatal编程技术网

php/mysql邮政编码邻近搜索

php/mysql邮政编码邻近搜索,php,sql,mysql,Php,Sql,Mysql,我只是在寻找最好的方法来做这件事的建议 我需要创建一个搜索功能,在邮政编码50英里半径范围内搜索“用户”。我有一个邮政编码表,其中包含所有美国邮政编码及其纬度/经度,但我只是想找出构造和查询数据的最佳方法 我是否应该向users表中添加纬度/经度列,并查询给定邮政编码半径内的所有用户?或者我应该在zip codes表中查询半径范围内的所有zip codes,然后在users表中查询具有结果的所有用户(zip codes)?或在这一点上,我愿意接受任何建议 谢谢 查看此处的近距离搜索功能: 如果

我只是在寻找最好的方法来做这件事的建议

我需要创建一个搜索功能,在邮政编码50英里半径范围内搜索“用户”。我有一个邮政编码表,其中包含所有美国邮政编码及其纬度/经度,但我只是想找出构造和查询数据的最佳方法

我是否应该向users表中添加纬度/经度列,并查询给定邮政编码半径内的所有用户?或者我应该在zip codes表中查询半径范围内的所有zip codes,然后在users表中查询具有结果的所有用户(zip codes)?或在这一点上,我愿意接受任何建议


谢谢

查看此处的近距离搜索功能:


如果您的数据采用相同的符号/投影/格式(无论称为什么),它可能适合您。

每个邮政编码的纬度/长度是该邮政编码的地理中心,对吗?因此,如果您首先找到地理中心在50英里以内的邮政编码,然后找到这些邮政编码中的用户,您很容易返回50英里以外的用户。这样做会牺牲一些准确性

但是如果您有很多用户(超过邮政编码的数量),这会更快,因为您首先要查询较小的邮政编码表。您可以在users表中索引邮政编码,因此查找具有特定邮政编码的用户会很快

只是一些想法!因此,如果你希望有很多用户,而50英里的半径不需要精确,我会在50英里内找到邮政编码,然后在这些邮政编码内找到用户。

我觉得这非常棒

“在“邮政编码”表中查询半径范围内的所有邮政编码,然后在“用户”表中查询具有结果的所有用户(邮政编码)”

我发现这是最好的方法,除非你需要把用户放在谷歌地图上。如果您只是列出里程范围内的用户,那么查询数据库(使用类)以获得ZIP列表应该非常容易,然后选择这些ZIP代码中的所有用户

Select * from Users where zip_code IN (19125,19081,19107.........);

应该可以了。

这是我找到的最好的方法。当然,它需要在数据库中对所有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;
}
//获取指定半径内的所有zipcodes-默认值为20
函数zipcodeRadius($lat、$lon、$radius)
{
$radius=$radius?$radius:20;

$sql='从ZipCode中选择不同的(ZipCode),其中(3958*3.1415926*sqrt((纬度-'.$lat.)*(纬度-'.$lat.)+cos(纬度/57.29578)*cos('.$lat./57.29578)*(经度-'.$lon.*)*(经度-'.$lon.)/180)

我会考虑先用边界平方来减少候选者的数量,然后把半径作为第二步来考虑。从ZIPCODE的坐标开始,然后计算所有4个方向的50英里长/LAT,然后用简单的大/小于标准选择那个框中的候选。如果你的用户基础是很好地展开,这将大大减少候选集,然后您只需进行向量距离数学来消除“角点”。

从这里开始,但请注意解决方案不是很快:

现在,为了加快速度,我们将替换查找以使用空间索引:)

  • 使用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;
       }
    
    函数get_zips_in_range($zip,$range,$sort=1,$include_base)
    {
    //返回$zip.returns范围内的邮政编码数组
    //一个数组,其中键为邮政编码,值为距离
    //在$zip中定义的zipcode。
    $this->chronometer();//启动时钟
    $details=$this->get_zip_point($zip);//基本zip详细信息
    如果($details==false),则返回false;
    //例程的这一部分计算最小和最大lat和
    //在给定的范围内很长。这部分代码是编写的
    //杰夫·贝尔纳(http://www.jeffbearer.com).这大大减少了
    //执行查询所需的时间。我的演示耗时3.2秒
    //1.0.0版,现在只需0.4秒即可执行!太棒了,杰夫!
    //查找半径和零点的最大-最小纬度/长度并查询
    //只有拉链在那个范围内。
    $lat=$details[0];
    $lon=$details[1];
    $return=array();//此处为作用域声明
    $first=true;
    $radius=$range/69.172;
    $boundary=“多边形(”;
    对于($i=0;$i last_error=mysql_error());
    返回false;
    }否则{
    而($row=mysql\u fetch\u row($r)){
    //循环遍历结果以从src获得milage
    $dist=$this->calculate_里程($details[0],$row[7],$details[1],$row[8]);
    如果($this->units==\u UNIT\u km)$dist=$dist*\u M2KM\u系数;
    $return[str_pad($row[0]。,'.$row[1],5,“0”,str_pad_LEFT)]=舍入($dist,$this->小数);
    }
    mysql_免费_结果($r);
    }
    //排序数组
    开关($sort)
    {
    案例(拉链)(按距离排序)(ASC):
    asort(收益);
    打破
    案例_ZIPS_SORT_BY_DISTANCE_DESC:
    阿索特(返回);
    打破
    箱子(拉链)(按拉链)分类(ASC):
    ksort(返回);
    打破
    箱子(拉链)(按拉链分类)(说明):
    krsort($返回);
    打破
    }
    $this->last_time=$this->chronometer();
    if(空($return))返回false;
    return$return;
    }
    
  • 我会先
    $query = 'SELECT zzip FROM ' . table . 
                ' WHERE (POW((69.1*(zlongitude-"' . 
                $long . '")*cos(' . $long . 
                '/57.3)),"2")+POW((69.1*(zlatitude-"' . 
                $lat . '")),"2"))<(' . $radius . 
                '*' . $radius . ')';