分享

如何为实时性应用存取经纬度?

 亚典波罗的收藏 2012-06-28

如何为实时性应用存取经纬度?


Hi,现在做的东西需要实时存储用户的经纬度,然后要求能快速得到某个指定经纬度附近的用户的列表。
我的问题是:

  1. 以什么形式存储经纬度比较好?
  2. 怎么找出数据库里距离某经纬度比较近的其它用户?
  3. 需要用redis之类的nosql db么?

PS: 我现在的后台用django写的,数据库用的mysql。

joyqi 4.3k

django nosql redis python mysql
0条评论 | 修改 | 链接

5 个回答


  • joyqi joyqi 4.3k

    不需要用到redis作经纬度查询,当然你做缓存除外。实际上我们在黑客马拉松就做过一个类似的项目,它的核心思想就是取出当前用户所在地点附近的用户。

    我们使用的是MongoDB的Geo索引,这里有详细的介绍http://www./display/DOCS/G...

    但是我注意到你使用的是mysql,虽然MongoDB能够很方便的实现这一目标,但如果你不想迁移数据库的话,也还是有方法来实现的,当然你得有思想准备,此方法可能比较曲折。我以下要说的大部分内容都来自Mysql AB介绍实现geo search的文章。

    首先我们要解决的是把经纬度之差换算成距离之差,这里面涉及到一些角度转换公式,它就是

    转换公式

    其中d是距离(distance),R是地球半径。这个公式很复杂,但是我们的最终目标是把d求出来,我们来看这个求值过程,以下是伪代码

    R = 地球半径
    Δlat = lat2 lat1    //纬度之差
    Δlong = long2 long1 //经度之差
    a
    = sin2lat/2) + cos(lat1) * cos(lat2) * sin2long/2)
    c
    = 2*atan2(√a, √(1a))
    d
    = R*c

    来把它转换为SQL代码,看着会有点晕,其中3956是地球半径

    3956 * 2 * ASIN ( SQRT (
    POWER(SIN((orig.lat - dest.lat)*pi()/180 / 2), 2) + COS(orig.lat * pi()/180) * COS(dest.lat * pi()/180) * POWER(SIN((orig.lon - dest.lon) * pi()/180 / 2), 2) ) ) as distance

    OK,求值代码已经出来了,来写个SQL测试下(hotels表有三个字段hotel_name,lat,lon)

    # 设置当前位置的经纬度
    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;

    这样你就可以把距离当前位置10以内的的hotels全部搜索出来了。你可以用存储过程来优化这一代码,让它更加快速。

    2条评论 | 修改 | 链接
    • zhang yu

      把所有的坐标都算出来,然后按照距离排序,mysql这个做法效率低下,即便是用存储过程编译下,也是很恼火的。 还是建议mongodb加geo索引来做

    • LuckyWiky

      不知道提问者解决问题没有。 其实算出中心点以距离为半径的外切正方形内的经纬度范围效率比较高 SQL代码 {{{ declare @EARTH_RADIUS float set @EARTH_RADIUS = 6371000.00 ---地球的半径 declare @lat float declare @lng float declare @dlng float declare @dlat float declare @distance int ------距离 set @distance = 300 ----300米 set @lat =xx.xxxxx  ---这个是中心地点 set @lng = xxx.xxxx ---中心地点 set @dlng  = 2 * asin(sin( @distance / (2 * @EARTH_RADIUS)) / cos(@lat)) set @dlng = degrees(@dlng)  set @dlat =  300/@EARTH_RADIUS set @dlng = degrees(@dlat)  declare @lng1 float declare @lng2 float declare @lat1 float declare @lat2  float set @lat1 = @lat-@dlat set @lat2 = @lat+@dlat set @lng1 = @lng-@dlng set @lng2 = @lng+@dlng select @lat1,@lat2,@lng1,@lng2 SELECT lat,lng FROM place WHERE lat > @lat1 AND lat < @lat2 AND lng > @lng1 AND lng < @lng2; }}}

  • 牛小腩 牛小腩 77

    mongoDB实现空间数据库该有的东西.. 原生就支持地理范围检索...无需各种用不着的东西...4sq就是用它的

    1条评论 | 修改 | 链接
  • coolqing coolqing 7

    mongodb geo

    0条评论 | 修改 | 链接
  • icyflash icyflash 173

    MongoDB GEO +1

    用MYSQL的话,这个你应该用的着
    http://www./doc/2569355/Geo...

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多