PHP和MySQL使用SPATIAL扩展获得最近的点

时间:2014-01-19 06:07:44

标签: php mysql sql google-maps geospatial

我意识到这个问题已被多次询问,但我看到的每个答案似乎都非常局限于OP希望实现的目标。这就是为什么我正在寻找一个简单的使用-90到90之间的纬度值,以及使用-180到180之间的经度的一般答案。

所以这里有一个简单的前提:php文件收到两个包含lat和lng的get变量。找到 n 最近的点,按最接近的顺序排序。

让我们设置一个简单的表,它有一个名为location

的索引点
CREATE TABLE `trees` 
(
  `TREEID` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `location` point NOT NULL,
  PRIMARY KEY (`TREEID`),
  SPATIAL KEY `location` (`location`)
) ENGINE=MyISAM;

现在我们想使用php

<?php

//Setup variables
$lat = trim(mysql_prep($_GET['lat'])); 
$lng = trim(mysql_prep($_GET['lng'])); 
$n   = 100;

//Make sure they are valid lat and lng
if (!is_numeric($lat) || floatval($lat) < -90  || floatval($lat) > 90 || 
    !is_numeric($lng) || floatval($lng) < -180 || floatval($lng) > 180  )
{
        die("Invalid lng and lat coordinates.");
}
else
{
        //Lets find the n closest points to our $lat, $lng
        $get_trees = "Select * FROM trees WHERE _____?______ Order by _?_ ASC";
        $result = mysql_query($get_trees , SQL_Connection());   
}   


?>

现在,根据我的理解,通过对位置进行空间mysql索引,查询应该相对较快。但是,关于做什么的答案之间存在一些争论。一些用户设置计算半径距离的函数。有些人在查询中做了正确的事情,看起来很麻烦。根据您想要答案的准确程度,有些人会偷工减料。大多数hasrsine答案似乎假设开发人员将lat / lng存储为双精度,我不确定最好将此数学用于点索引。我已经查看了文档中的空间扩展,并且无法将它拼凑在一起。所以这个问题是,做什么。查询查询及其准确性级别以及显示您预定义的任何sql函数将会很有帮助。这个问题假设我们寻找最接近特定纬度的点而不是搜索特定距离内的点(例如在20km内)。我特别希望找到一个接近100%正确性的答案, n 在100到500之间。

1 个答案:

答案 0 :(得分:2)

好的,所以我最终使用了半身像。它实际上非常快,并且使用它作为获取点的ajax请求是一个好主意。

$get_trees = "Select TREEID,  X(location) as lat, Y(location) as lng,
(6371000 * 
        acos( 
          cos( radians($lat) )
        * cos( radians( X(location) ) ) 
        * cos( radians( Y(location) ) - radians($lng) )
        + sin( radians($lat) ) 
        * sin( radians( X(location) ) ) ) ) AS distance 


FROM trees ORDER BY distance ASC LIMIT 0 , $n;";

$result = mysql_query($get_trees , SQL_Connection());   

while ($record = mysql_fetch_assoc ($result))
{
    $tree_identity = $record['TREEID'];
    $distance_in_meters = $record['distance'];
    $tree_lat = $record['lat'];
    $tree_lng = $record['lng'];
}

由于公式假设地球是一个球体(恒定半径),以下是您可以使用的半径值:

对于Meters,请使用6371000

对于里程,请使用3959

对于公里,请使用6371

我希望有人会觉得这很有帮助,或者至少会让你知道如何处理这个问题。如果您希望点在一定距离内,例如10米,请添加“HAVING distance&lt; 10”。