如何在mysql中最佳实现最近邻居搜索?


10

简而言之,

  1. 纬度和经度的数据类型应该是什么?
  2. 例如,我应该调用哪个SQL命令来获取前100个最近的餐馆?

详情:

我有10万张biz记录,分别包含经度和纬度。我看到MySQL实际上支持一种称为point的数据类型。我应该改用它吗?

MySQL是否支持KDTree存储系统http://en.wikipedia.org/wiki/File:KDTree-animation.gif

最好是使用点数据类型而不是常规浮点数据类型来存储纬度和经度?

最终,我想查找例如最接近点105,6的前100家餐厅,而我的数据库包含很多biz和点。显然,对每个记录和每个点一一计算距离将是O(n),因此很糟糕。

请注意,我知道如何像Yelp这样的应用程序中描述的更简单的解决方案,可以有效地从数据库检索距离信息,并且一开始也将实现我的自我。这是一个很好的答案。

但是,我认为最好的答案应该是超越该权利吗?实际上,基于纬度和经度存储位置并查找距离它最近的东西是一个非常普遍的问题,我希望mysql为此具有特殊的设计模式。有吗?

在哪里可以了解更多信息?谢谢。


你有没有看到这个问题
杰克说,请在2011年

看起来dba.stackexchange.com/questions/4210/…中的解决方案是最好的解决方案。我的意思是说有一个叫做MYSQL空间的东西。但是,您无法提取出where(距离(x)<20)之类的东西。尚未实现。
user4951 2011年

Answers:


11

就设计模式而言,Yelp问题是非常标准的东西。

对于更复杂的答案,您可能需要地理空间距离。下面是关于该主题的一个迷人的PowerPoint(和这里就是一个PDF版本,以及)。但是,所涉及的数学非常丑陋。

从他们的幻灯片:

set @orig_lat=122.4058; set @orig_lon=37.7907;
set @dist=10;

SELECT *, 3956 * 2 * ASIN(SQRT(
POWER(SIN((@orig_lat - abs(dest.lat)) * pi()/180 / 2), 2) +  COS(@orig_lat * pi()/180 ) * COS(abs(dest.lat) * pi()/180) *  POWER(SIN((@orig_lon  dest.lon) * pi()/180 / 2), 2) )) as  distance
FROM hotels dest 
having distance < @dist
ORDER BY distance limit 10

关于Stack Overflow的地理空间距离,还有一个更长,更深入的答案。

但是您仍然想通过纬度和经度来限制结果。

最终,我将避免使用POINT数据类型,而是使用纬度/经度。当前无法确定两个POINT之间的距离,因此无论如何您都必须存储纬度/经度。

最后一个链接:您可能还想签出有关使用空间索引加快查询速度的SO线程


[查询4中的错误]您的SQL语法错误;检查与您的MySQL服务器版本相对应的手册以获取正确的语法,以在'– dest.lon)* pi()/ 180/2),2))))到第2行的network_pos dest具有d'的距离
Felipe

嗨,@dist是千分之一秒?感谢
豪尔赫·奥拉夫·埃兰森

1
@OlafErlandsen是的,它在英里里
Jan van der Vegt

4

点数据类型还可以;您只需调用X(coord)/ Y(coord)即可获取纬度/经度值。

例如:

SELECT id, 
(3959 
    * acos(
        cos(radians(37)) 
        * cos(radians(Y(coord)))
        * cos(radians(X(coord)) - radians(-122)) 
        + sin(radians(37))
        * sin(radians(Y(coord)))
      )
) AS distance 
FROM markers HAVING distance < 25 
ORDER BY distance LIMIT 20;

37是lat,-122是lon?25是米还是公​​里?
费利佩

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.