我必须计算一个对象(一个城市)与我拥有的 MySQL 表(一些餐馆)中的每个条目之间的距离。这个城市和餐馆位于同一个国家。
计算的距离用于显示靠近该城市的所有餐馆;阈值距离是任意的。 此外,这是一个排名列表:最先显示最近的餐厅,最远的餐厅显示在列表末尾。我的问题是关于这个排名。
我现在做了什么
所以我做了一些研究,我成功地计算出了这个距离。
$special_select_distance = "DEGREES(ACOS(COS(RADIANS(" . $oneVilles->__get('latitude')[app::getLang()] . ")) * COS(RADIANS(lat)) * COS(RADIANS(lon) - RADIANS(" . $oneVilles->__get('longitude')[app::getLang()] . ")) + SIN(RADIANS(" . $oneVilles->__get('latitude')[app::getLang()] . ")) * SIN(RADIANS(lat))))";
$restaurants = $restaurantsDAO->getAll(null, ['distance DESC'] , null, 'HAVING distance < 1.9' , null , '*, ' . $special_select_distance . " AS distance");
...其中:
['distance DESC']
代表距离排名'HAVING distance < 1.9'
代表任意阈值'*, ' . $special_select_distance . " AS distance"
是选择器$oneVilles->__get('latitude')[app::getLang()]
和$oneVilles->__get('longitude')[app::getLang()]
是城市的经纬度坐标lat
和lon
是餐厅的坐标(自动进入我们迭代的表,即:restaurants
表,因为我们使用餐厅 DAO)
问题
实际和意外结果
对于彼此距离很近的每家餐馆,计算出的与城市的距离保持不变。
示例:假设餐厅 A 和 B 距离很近。那么,A到城市的距离等于B到城市的距离,这是我实际的意外结果。
这不是我想要的。事实上,这些餐厅中有一家比另一家离市区最近。我认为 MySQL 不够精确。
预期结果
预期结果:让餐厅按照到工作城市的远近排名。换句话说,获得更精确的计算距离。
示例:假设餐厅 A 和 B 距离很近。那么,A到城市的距离比B到城市的距离短,这是我的预期结果。
计算距离的例子
在餐厅和城市之间(餐厅远离城市):
1.933156948976873
在餐厅 A 和城市之间(A 靠近城市):
1.6054631070094885
在餐厅 B 和城市之间(B 靠近 A):
1.6054631070094885
点 2. 和点 3. 的距离相同,这不正常。我想要更多数字,以便能够更有效地对我的餐厅进行排名。
约束
我不想更改 MySQL 服务器的配置。
- 特别是:我绝对不能使用 MySQL 几何类型(这是公司的限制)
预期的解决方案应该只是更改我编写并提供给您的 SQL 查询,以便在可能的情况下更加精确。
如有必要,允许使用其他计算距离的方法。
最佳答案
对于长距离,请使用 Haversine 公式来确保准确性。对于短距离,毕达哥拉斯的速度是其两倍。
16 位有效数字(数据类型 DOUBLE
)很可笑。您无需区分狗身上的两种不同跳蚤。
对于毕达哥拉斯,一定要将经度除以纬度的余弦——赫尔辛基附近的经度一度是赤道一度的一半。
更多细节在这里:http://mysql.rjweb.org/doc.php/latlng
如果 1.6054631070094885
是纬度差异,那么可以这样想:如果你我在同一经度,但我们的纬度分别是 1.605463 和 1.605464,那么,好吧,我不非常了解您,可以接近您。
在没有软糖因素的情况下比较两个浮点值是不切实际的:
If abs(a-b) < 0.00001, then treat them as equal.
更多
我推荐 FLOAT
用于纬度、经度和距离,因为您在谈论餐馆。如果您谈论的不是超过 100 英里或 100 公里,那么这个表达式就足够精确了:
SQRT( ($lat - lat) *
($lat - lat) +
(($lng - lng) * COS(RADIANS(lat))) *
(($lng - lng) * COS(RADIANS(lat))) ) * $factor
哪里...
lat
和lng
是表中FLOAT
列的名称,以度为单位。$lat
和$lng
是您起始位置的值,也以度为单位。 (PHP 使用$
;其他语言使用其他约定。)$factor
是 69.172 英里或 111.325 公里。- 我不会显示超过 1 位小数的结果。 (不要显示“12.345678 英里”;“12.3 英里”就足够了。)
毕达哥拉斯和 GCD 的比较:
Pyt GCD
To Rennes: 93.9407 93.6542
To Vannes: 95.6244 95.6241
关于mysql - 如何在不使用几何类型的情况下在 MySQL 中获得更高的计算距离精度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54237933/