简体   繁体   English

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

[英]PHP and MySQL get the n closest points using the SPATIAL extention

I realize that this question has been asked multiple times, but each answer I've seen seems very localized to what the OP wants to achieve. 我意识到这个问题已经被问过多次了,但是我看到的每个答案似乎都局限于OP想要实现的目标。 Which is why I am looking for a general answer to simply using a latitude value between -90 and 90, as well as using a longitude between -180 and 180. 这就是为什么我要寻找一个简单的答案,简单地使用-90至90之间的纬度值,以及使用-180至180之间的经度。

So here is the simple premise: There are two get variables received by the php file that contain the lat and lng. 因此,这是一个简单的前提:php文件收到两个包含lat和lng的get变量。 Find the n closest points, order by closest to furthest. 找到n个最接近的点,按最接近的顺序排序。

Let us setup a simple table that has a indexed point called 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;

Now we want to work with php 现在我们要使用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());   
}   


?>

Now, it is from my understanding that with the spatial mysql indexing of the locations, queries should be relatively fast. 现在,根据我的理解,使用位置的空间mysql索引,查询应该相对较快。 However, there is some debate between answers as to what to do. 但是,关于如何做的答案之间存在一些争论。 Some users setup functions that compute haversine distances. 一些用户设置了计算正弦距离的函数。 Some do haversine right in the query and it looks a hell of a lot messy. 有些人在查询中确实有haversine,这看起来非常混乱。 Some cut corners depending on how accurate you want the answer. 一些捷径取决于您想要答案的准确性。 Most haversine answers seem to assume the developer stores the lat/lng as doubles and I'm not sure it would be best put this math to use with the point index. 大多数错误的答案似乎都假定开发人员将经度/经度存储为双精度数,我不确定是否最好将此数学运算与点索引一起使用。 I've looked through the docs for the spatial extension and haven't been able to piece it together. 我已经在文档中查找了空间扩展,但无法将其拼凑在一起。 So that question is, what to do. 所以问题是,该怎么办。 It would be helpful to state the query and the level of accuracy it has, as well as show any sql functions you have predefined. 陈述查询及其准确性的水平,以及显示您已预定义的任何sql函数,将很有帮助。 This question assumes we looking for the closest points to a particular lat lng rather than searching for points within a particular distance(eg within 20km). 这个问题假设我们正在寻找最接近特定纬度的点,而不是寻找特定距离内(例如20公里之内)的点。 I am in particular looking for an answer that gives near 100% correctness, for a n between 100 and 500. 我特别在寻找一个答案,该答案给出100%到500之间的n的接近100%的正确性。

Okay so I ended up using haversine. 好吧,所以我最终使用了haversine。 It's actually quite fast, and using it as a ajax request to get points is a good idea. 它实际上非常快,将它作为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'];
}

Since the formula assumes the earth is a sphere(constant radius), here are the values for the radius you can use: 由于公式假定地球是一个球体(恒定半径),因此可以使用以下半径值:

For Meters, use 6371000 对于仪表,请使用6371000

For Miles, use 3959 对于英里,请使用3959

For Kilometers, use 6371 对于公里,请使用6371

I hope someone will find this helpful or at least it will give you a idea of how to approach the problem. 我希望有人会对此有所帮助,或者至少会为您提供解决问题的方法。 If you want points to be within a certain distance, like 10 meters, add "HAVING distance < 10". 如果希望点在一定距离之内(例如10米),请添加“ HAVING distance <10”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM