由于地理位置邻近公式(商店定位器)而导致结果缺失

2024-04-18

好的 - 我已经断断续续地与这个问题斗争了大约 3 个月,因为我已经用尽了我遇到的所有地理邻近公式,但我距离获得正确的结果还差得很远,我认为是时候了寻求帮助。

THE AIM

我正在设置一个相当基本的商店定位器实现。用户输入邮政编码并从预定义的搜索半径列表中进行选择。 gmaps API 生成该地址的纬度/经度坐标并将其传递给 php 脚本。在此脚本中,根据 mysql 数据库表查询用户坐标(结构如下)

post_id int(11)                             
post_type varchar(20)                                
lat   float(10,6)                               
lng   float(10,6)

该查询的结果(帖子 ID)被输入到 wordpress 查询中,该查询生成包含地图标记数据的 XML。 (wordpress 查询使用 post__in 和 posts_per_page -1 显示查询生成的所有 ID 的信息

问题

简而言之,我遇到的半正矢公式的每次实现似乎都会导致标记缺失 - 特别是任何非常接近用户输入的坐标的标记(不确切知道,但我认为它在大约 500m 之内)。这是一个大问题,因为如果用户输入他们的邮政编码,并且有一家商店非常靠近他们的位置,它就不会显示。

我已经尝试了大约 8 种不同的论坛排列,这些排列是我从各种教程中挖掘出来的,但结果相同。下面是我当前在网站上使用的公式,它提供了除非常接近用户输入位置的标记之外的所有标记:

$center_lat = $_GET["lat"];
$center_lng = $_GET["lng"];
$radius = $_GET["radius"];

// Calculate square radius search

$lat1 = (float) $center_lat - ( (int) $radius / 69 );
$lat2 = (float) $center_lat + ( (int) $radius / 69 );
$lng1 = (float) $center_lng - (int) $radius / abs( cos( deg2rad( (float) $center_lat ) ) * 69 );
$lng2 = (float) $center_lng + (int) $radius / abs( cos( deg2rad( (float) $center_lat ) ) * 69 );

$sqlsquareradius = "
SELECT 
post_id, lat, lng
FROM
wp_geodatastore
WHERE
lat BETWEEN ".$lat1." AND ".$lat2."
AND
lng BETWEEN ".$lng1." AND ".$lng2."
"; // End $sqlsquareradius

// Create sql for circle radius check
$sqlcircleradius = "
SELECT
t.post_id,
3956 * 2 * ASIN(
    SQRT(
        POWER(
            SIN(
                ( ".(float) $center_lat." - abs(t.lat) ) * pi() / 180 / 2
            ), 2
        ) + COS(
            ".(float) $center_lat." * pi() / 180
        ) * COS(
            abs(t.lat) * pi() / 180
        ) * POWER(
            SIN(
                ( ".(float) $center_lng." - t.lng ) * pi() / 180 / 2
            ), 2
        )
    )
) AS distance
FROM
(".$sqlsquareradius.") AS t
HAVING
distance <= ".(int) $radius."
ORDER BY distance
"; // End $sqlcircleradius


$result = mysql_query($sqlcircleradius);

$row = mysql_fetch_array( $result );

while($row = mysql_fetch_array( $result )) {
// the contents of each row
$post_ids[] = $row['post_id'];
}

我尝试过 Mike Pelley 在这里建议的 1 个公式:地理定位 SQL 查询未找到确切位置 https://stackoverflow.com/questions/2695365/geolocation-sql-query-not-finding-exact-location

该公式似乎显示了非常接近用户输入位置的标记,但错过了应该在给定半径内显示的其他标记。为了消除任何混乱,这是我使用的代码:

$center_lat = $_GET["lat"];
$center_lng = $_GET["lng"];
$radius = $_GET["radius"];

$sql = "
SELECT post_id, lat, lng, 
truncate((degrees(acos( sin(radians(lat)) 
* sin(radians(".$center_lat.")) 
+ cos(radians(lat)) 
* cos(radians(".$center_lat.")) 
* cos(radians(".$center_lng." - lng) ) ) ) 
* 69.09*1.6),1) as distance 
FROM wp_geodatastore HAVING distance <= ".$radius." ORDER BY distance desc
"; // End $sqlcircleradius


$result = mysql_query($sql);

$row = mysql_fetch_array( $result );

while($row = mysql_fetch_array( $result )) {
// Print out the contents of each row
$post_ids[] = $row['post_id'];
}

要求

基本上我想知道为什么这些代码块都没有显示正确的标记。如果有人可以对代码提出任何改进建议,或者可以向我指出一些我可能错过的资源,那就太好了

EDIT

以为我的伪答案有效,但事实证明仍然存在问题。我现在最终采用了一种非常不同的策略,我正在使用一个非常好的 jquery 存储定位器,可以在这里找到:http://www.bjornblog.com/web/jquery-store-locator-plugin http://www.bjornblog.com/web/jquery-store-locator-plugin

并不适用于每个项目,但对于我的需求来说,它是完美的(并且有效!)


EDIT这个定位器出现的频率足够高,我已经写了一篇关于它的文章。

http://www.plumislandmedia.net/mysql/havesine-mysql-nearest-loc/ http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/

原帖

让我们首先处理一下半正弦公式,将其放入一个存储函数中,这样我们就可以忘记它的粗糙细节。注意:整个解决方案以法定英里为单位。

DELIMITER $$

CREATE
    FUNCTION distance(lat1 FLOAT, long1 FLOAT, lat2 FLOAT, long2 FLOAT)
    RETURNS FLOAT
    DETERMINISTIC NO SQL
    BEGIN
    RETURN (3959 * ACOS(COS(RADIANS(lat1)) 
                 * COS(RADIANS(lat2)) 
                 * COS(RADIANS(long1) - RADIANS(long2)) 
                 + SIN(RADIANS(lat1)) 
                 * SIN(RADIANS(lat2)) 
                )); 
    END$$

DELIMITER ;

现在,让我们组合一个在边界框上搜索的查询,然后使用距离函数和按距离排序来细化搜索

根据您问题中的 PHP 代码:

Assume $radius是你的半径,$center_lat, $center_lng是你的参考点。

$sqlsquareradius = "
SELECT post_id, lat, lng
  FROM
(
    SELECT post_id, lat, lng,
           distance(lat, lng, " . $center_lat . "," . $center_lng . ") AS distance
      FROM wp_geodatastore
     WHERE lat >=  " . $center_lat . " -(" . $radius . "/69)
       AND lat <=  " . $center_lat . " +(" . $radius . "/69)
       AND lng >=  " . $center_lng . " -(" . $radius . "/69)
       AND lng <=  " . $center_lng . " +(" . $radius . "/69)
)a
WHERE distance <= " . $radius . "
ORDER BY distance
";

请注意与此相关的一些事情。

首先,它使用 SQL 而不是 PHP 进行边界框计算。除了将所有计算保留在一个环境中之外,没有充分的理由这样做。(radius / 69)是度数radius法定里程。

其次,它不会根据纬度调整纵向边界框的大小。相反,它使用一个更简单但稍微太大的边界框。这个边界框捕获了一些额外的记录,但距离测量消除了它们。对于典型的邮政编码/商店查找应用程序,性能差异可以忽略不计。如果您搜索更多记录(例如所有电线杆的数据库),它可能不会那么微不足道。

第三,它使用嵌套查询来消除距离,以避免为每个项目多次运行距离函数。

第四,它按距离升序排序。这意味着您的零距离结果应该首先显示在结果集中。首先列出最近的事物通常是有意义的。

五、它使用FLOAT而不是DOUBLE自始至终。这是有充分理由的。半正矢距离公式并不完美,因为它近似地认为地球是一个完美的球体。该近似值恰好与 epsilon 的准确度大致相同。FLOAT数字。所以DOUBLE对于这个问题来说,数字是具有欺骗性的杀伤力。 (不要使用这个半正矢公式来做停车场排水等土木工程工作,否则你会得到几个 epsilon 的大水坑,几英寸深,我保证。)这对于商店查找应用程序来说很好。

第六,您肯定会想要为您的内容创建一个索引lat柱子。如果您的位置表不经常更改,那么为您的位置创建索引将有所帮助lng专栏也是如此。但你的lat索引将为您带来大部分查询性能提升。

最后,我测试了存储过程和 SQL,但没有测试 PHP。

参考:http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL还有我在医疗保健机构使用大量邻近探测器的经验。

- - - - - - - - 编辑 - - - - - - - - - -

如果您没有可让您定义存储过程的用户界面,那就很麻烦了。无论如何,PHP 允许您在 sprintf 调用中使用编号参数,因此您可以像这样生成整个嵌套语句。注意:您可能需要 %$1f 等。您需要对此进行试验。

$sql_stmt = sprintf ("
  SELECT post_id, lat, lng
    FROM
  (
    SELECT post_id, lat, lng,
           (3959 * ACOS(COS(RADIANS(lat)) 
                 * COS(RADIANS(%$1s)) 
                 * COS(RADIANS(lng) - RADIANS(%$2s)) 
                 + SIN(RADIANS(lat)) 
                 * SIN(RADIANS(%$1s)) 
            ))
           AS distance
      FROM wp_geodatastore
     WHERE lat >=  %$1s -(%$3s/69)
       AND lat <=  %$1s +(%$3s/69)
       AND lng >=  %$2s -(%$3s/69)
       AND lng <=  %$2s +(%$3s/69)
  )a
   WHERE distance <= %$3s
   ORDER BY distance
",$center_lat,$center_lng, $radius);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

由于地理位置邻近公式(商店定位器)而导致结果缺失 的相关文章

  • HTML/PHP if-else 语句

    我正在使用 Bootstrap 创建一个网站 我想输入 if else 语句 但我不知道该怎么做 让我解释 Here is an image of my current HTML snippet 现在我想要的是 如果我通过 An Aussc
  • YOUTUBE API:检索视频关键字

    最近 YouTube 决定仅向经过身份验证的开发者输出视频关键字 我注册了开发者密钥 我试图获取一个我将解析的 XML 通过请求 https gdata youtube com feeds api videos COwIYbYQUrQ ke
  • 如何使PHP库松耦合? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 在 CodeIgniter 中使用 ajax 时出现 403 禁止错误

    我正在显示我的名字textbox使用 ajax 自动完成 但我的 ajax URL 不起作用 每次都显示在网络选项卡中 403 禁止 我尝试过像这样的ajax URL url baseUrl index php Employee contr
  • PHP exec - 检查是否启用或禁用

    有没有办法检查 php 脚本是否exec 在服务器上启用还是禁用 这将检查该功能是否确实有效 权限 权利等 if exec echo EXEC EXEC echo exec works
  • 以阿拉伯语显示日期

    这是我的代码 setlocale LC ALL ar echo strftime e b Y strtotime 2011 10 25 Output 25 Sep 2011 为什么不显示阿拉伯日期 我是否错误地使用了 strftime 在这
  • PhpStorm Docker PHPUnit 数据库

    I setup https blog jetbrains com phpstorm 2016 11 docker remote interpreters PhpStorm PHP PHPUnit 与 Docker 我在 PhpStorm 数
  • MySQL 中复制一条记录

    我有一个表 我想复制表中的特定行 我知道这不是最好的方法 但我们正在寻找快速解决方案 这比我最初想象的要难 我需要做的就是将整个记录复制到 MySql 中自动增量表中的新记录 而不需要指定每个字段 这是因为该表将来可能会发生变化 并且可能会
  • 从 PHP/Web 应用程序打印多个标签到 Dymo LabelWriter 450 Turbo

    我希望添加使用 Dymo LabelWriter 450 Turbo 打印多个标签的功能 我已经从 Dymo 网站下载了 DYMO Label v 8 SDK dmg 但看不到任何 Javascript Web 相关的 SDK 文件或文档
  • 这段php代码安全吗?

    我知道我应该使用准备好的语句 但我的下一个项目将使用准备好的语句 我只需要完成这个简单的小应用程序 所以我的问题是 以下代码片段安全吗 我使用了 htmlentities 以及 mysql real escape string 因为我认为这
  • 如何在PHP中使用curl GET发送原始数据?

    我正在开发 REST API 虽然很容易在 cURL 中为 POST 请求设置原始 JSON 数据 payload json encode array user gt data attach encoded JSON string to t
  • 无法加载 php_curl

    我已经在WindowsXp上安装了php5 2 13 apache2 2 15 将C php添加到PATH ssystem变量中 我无法启用卷曲扩展 我配置了extension dir并删除了 在 php ini 中形成 php curl
  • 选择当前项目 id 周围的 N 个上一个项目和 M 个下一个项目

    我有一张有照片的桌子 id year comm count 0 2015 1 1 2016 2 2 2017 5 3 2018 7 4 2019 1 5 2020 9 6 2021 1 7 2022 1 我选择具有给定 ID 的照片 位于所
  • PHP PDO 与 mysql*() 的安全优势

    使用 PHP PDO 代替 mysql connect 等有任何安全优势吗 不会 与 MySQL 扩展相比 PDO 没有任何安全优势 墨菲定律告诉我们的除外 该定律对两者都适用 两者都会通过转义相同的字符来保证输入安全 然而 PDO 还有其
  • 如何在 mysql 正则表达式中匹配大写 ÅäÖ

    当我在 MySQL 中进行 REGEXP 比较时 我得到了瑞典字符大写版本的一些奇怪结果 我正在使用 utf8 swedish ci 排序规则 我想查找大写单词 SELECT ster REGEXP BINARY A Z a z 应该返回
  • 优化 SELECT 和 WHERE 子句中的存储函数调用

    我有一个具有以下结构的 SQL 查询 SELECT storedfunc param table field as f FROM table WHERE storedfunc param table field lt value ORDER
  • 在 PHP 中查找数字的倍数

    我想在 PHP 中找到一个数字的所有倍数 我正在使用这样的东西 if count 20 计算出如果 count不等于20 但我还需要这个脚本来检查是否 count不等于 20 40 60 80 100 120 140 160 等 有任何想法
  • PHP md5() 给出与 MySQL md5 不同的输出

    我正在尝试设置登录系统 但无法解决一个问题 PHP 通过 md5 给了我另一个输出 比MySQL 例如 在 PHP 中 password md5 brickmasterj return password 返回 3aa7b18f304e2e2
  • php中有指针吗?

    这段代码是什么意思 这就是你在 php 中声明指针的方式吗 this gt entryId entryId PHP 中的变量名称以 开头 因此 entryId 是变量的名称 this是PHP面向对象编程中的一个特殊变量 它是对当前对象的引用
  • MySQL 周数和新年

    我现在正在开发的网站有一个仪表板 显示各个用户在前一周输入的数据 我使用简单的 WHERE 子句选择此数据 SELECT FROM table WHERE WEEK date 1 WEEK CURDATE 1 1 然而 新年即将到来 当用户

随机推荐