地理数据搜索的优化

Posted

技术标签:

【中文标题】地理数据搜索的优化【英文标题】:Optimization of geodata search 【发布时间】:2017-05-17 21:45:36 【问题描述】:

我正在开发一个应用程序,我需要搜索某个地理区域中是否有某些项目。这些项目在数据库中与它们的纬度和经度一起被分割,在一个表中还有其他信息。我需要做的基本上是在以某些坐标为中心的圆形区域中搜索数据库中的所有项目。现在我只是进行查询以获取所有数据,然后对每个项目进行一些计算以查看它是否在该区域内(基本上是勾股定理,因为我不需要太高的精度)。已经做过类似事情的人可以就如何优化它提供一些建议吗?也许也有某种缓存系统返回先前搜索在一般区域中收集的结果,该区域的精度并不重要,将圆周移动几公里也不成问题。 我正在将 mysql 用于数据库,而 php 应该会产生我的结果。 提前谢谢你:)

编辑 我没有发布代码,因为我不是要求修改特定的代码,而是更直观地解决问题,某种算法,我以后可以自己编写 无论如何,这是数据库结构 餐桌访谈

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();

我曾想过使用 google 的 API 来计算距离,但我认为这会完全消耗服务器带宽,所以我不知道如何解决这个问题 .-.

再次感谢

【问题讨论】:

欢迎来到 ***!如果没有您发布,我们将无法帮助优化您的代码!为了让我们更好地帮助您,请更新您的问题,以便它在 minimal, complete, and verifiable example 中显示所有相关代码。如果您能告诉我们到目前为止您为解决问题所做的尝试,这也会很有帮助。如需更多信息,请参阅有关how to ask good questions 的帮助文章,并采取tour of the site :) 编辑添加相关代码 【参考方案1】:

这是一种未经优化且数学上不正确的地理球面距离方法。

    通过选择所有数据并根据毕达哥拉斯计算对其进行过滤来强制执行。

    线性距离的毕达哥拉斯计算对于地圈数据是不准确的,因为地球具有曲率,并且不是平原。更好的近似值是haversine 方法。它的实现在所有编程语言中都很容易获得。但是您甚至不必在您的案例中使用它,因为您的案例可以在数据库级别本身解决,因为大多数现代数据库都支持地理空间数据。

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

【讨论】:

【参考方案2】:

例如,最多 10K 点,这可能就足够了:

WHERE 子句中添加一个“边界框”并拥有INDEX(latitude), INDEX(longitude)

您需要除以COS(lat) 以补偿经线比纬线更靠近。

毕达哥拉斯距离可能对于不靠近两极也不越过日期变更线的“小”距离来说已经足够好了。同样,COS 是必需的。

我添加了一个标签;请参阅因此标记的其他讨论。

【讨论】:

以上是关于地理数据搜索的优化的主要内容,如果未能解决你的问题,请参考以下文章

优化表格以搜索地理位置

优化地理搜索查询

使用地名进行弹性搜索的地理定位(地理编码)

用于搜索地理坐标的数据库设计

MySQL - 如何使用地理位置数据加快搜索速度?

百度地图集成_POi搜索和正反地理编码