提问人:JarsOfJam-Scheduler 提问时间:1/17/2019 最后编辑:JarsOfJam-Scheduler 更新时间:1/22/2019 访问量:114
如何在不使用几何类型的情况下获得MySQL中计算距离的更高精度?
How to get more precision for a computed distance in MySQL, without using geometric types?
问:
我必须计算一个对象(一个城市)与我拥有的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
并且是餐厅的坐标(自动纳入我们正在迭代的表中,即:表,因为我们使用餐厅 DAO)lon
restaurants
问题
实际结果和意外结果
对于彼此之间非常接近的每家餐厅,计算出的与城市的距离保持不变。
示例:假设餐厅 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查询,以便更精确。
如有必要,允许使用其他计算距离的方法。
答:
对于长距离,请使用半正弦公式来确保准确性。对于短距离,毕达哥拉斯的速度是其两倍。
16 位有效数字(数据类型)是荒谬的。您无需区分狗身上的两种不同的跳蚤。DOUBLE
对于毕达哥拉斯,一定要将经度除以纬度的余弦——赫尔辛基附近的一度经度是赤道一度的一半。
更多细节在这里: http://mysql.rjweb.org/doc.php/latlng
如果是纬度差,那么可以这样想:如果你和我在同一经度,但我们的纬度是 1.605463 和 1.605464,那么,好吧,我不太了解你,无法那么接近。1.6054631070094885
在没有软糖因子的情况下比较两个浮点值是不切实际的:
If abs(a-b) < 0.00001, then treat them as equal.
更多
我推荐纬度、液化天然气和距离,因为你说的是餐馆。如果你谈论的不是超过 100 英里或公里,那么这个表达就足够精确了:FLOAT
SQRT( ($lat - lat) *
($lat - lat) +
(($lng - lng) * COS(RADIANS(lat))) *
(($lng - lng) * COS(RADIANS(lat))) ) * $factor
哪里。。。
lat
和 是表中列的名称,以度为单位。lng
FLOAT
$lat
并且是您开始的位置的值,也以度为单位。(PHP使用;其他语言使用其他约定。$lng
$
$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
评论
...) * 111,325 AS distance ...
325
400
ORDER BY distance ASC
DESC
评论
1.60546310700948851
1.60546310700948852
getAll