地理数据搜索的优化

时间:2017-05-17 21:45:36

标签: php mysql optimization geolocation

我正在开发一个应用程序,我需要搜索某个地理区域是否有某些项目。这些物品在数据库中,在具有其他信息的表格中以纬度和经度进行分割。我需要做的是基本上在一些坐标中搜索数据库中所有项目的圆形区域。现在我只是在查询获取所有数据,然后对每个项目进行一些计算,看它是否在该区域内(基本上是毕达哥拉斯定理,因为我不需要太多的精度)。有没有做过类似事情的人可以就如何优化它提出一些建议吗?也许还有某种缓存系统返回先前搜索在一般区域收集的resoult,该区域的精度并不重要,并且将圆圈移动几公里也不会成为问题。 我使用MySql作为数据库,PHP应该产生我的结果。 提前谢谢你:)

修改 我没有发布代码,因为我没有要求特定的代码修改,而是更直接的方法来解决问题,某种算法我以后可以自己编写代码 无论如何这是数据库结构 表Interv

ID Int
Addr Text
Info Text
Area Int
Type Text
Lat Double
Lng Double
Time Datetime

Table Area
ID Int
Name Text

这是PHP页面

require("Utils.php");
    require("Config.php");

    if(!array_key_exists("Lat",$_GET) || !array_key_exists("Lng",$_GET)){
        $re = array("error"=>"1");
        echo json_encode($re);
        exit();
    } 
    $lat = $_GET["Lat"];
    $lng = $_GET["Lng"];

    $mysqli = get_mysqli();
    $query = "SELECT `Interv`.`Addr`,`Interv`.`Info`,`Interv`.`Lat`,`Interv`.`Lng`,`Interv`.`Type`, `Area`.`Name` FROM `Interv` JOIN `Area` ON `Interv`.`Area`=`Area`.`ID` WHERE  `Time` > '".date("Y-m-d H:i:s",(time() - Max_Time))."';";
    $result = $mysqli->query($query);
    if($result->num_rows >0){
        $responce = array("Error" => 0 , "Data" => array());
        $i = 0;
        while($row = $result->fetch_array(MYSQLI_ASSOC)){
            if(sqrt(pow($lat-$row["Lat"],2)+pow($lng-$row["Lng"],2)) < Max_Distance){
                $responce["Data"][$i] = array("Addr" => $row["Addr"], "Info" => $row["Info"], "Type" => $row["Type"], "Area" => $row["Name"]);
                $i++;
            }

        }
        echo json_encode($responce);
        $result->close();
    }
    $mysqli->close();

我想过使用谷歌的API来计算距离,但我认为这会完全扼杀服务器带宽,因此我不确定如何处理这个问题.-。

再次感谢

2 个答案:

答案 0 :(得分:0)

这是一种未优化的,也是数学上不正确的做地理球距的方法。

  1. 通过选择所有数据并根据毕达哥拉斯计算对其进行过滤,您就是强制性的。

  2. 毕达哥拉斯线性距离的计算对于地圈数据来说是不准确的,因为地球有曲率,并且不是平原。更好的近似是haversine方法。它的实现很容易在所有编程语言中使用。但是你甚至不必在你的情况下使用它,因为你的情况可以在数据库级别解决,因为大多数现代数据库都支持地理数据。

  3. 对于mysql 5.6+,内置地理空间数据类型和查询。因此,您可以将所有数据与坐标一起存储,并执行单个查询以查找位于特定圆形范围内的所有点。一个很好的解释here和官方文档here

答案 1 :(得分:0)

对于最多10K分,这可能会做得足够好:

添加一个&#34;边界框&#34;到WHERE子句并INDEX(latitude), INDEX(longitude)

你需要除以COS(lat)来补偿经度线比纬度线更接近。

毕达哥拉斯距离可能足以让小&#39;小&#39;距离不靠近极点也不越过日期线的距离。同样,需要COS

我添加了一个标签;见其他标记的讨论。