zoukankan      html  css  js  c++  java
  • 利用mongodb开发lbs应用实践【转】

    近期作为突击队员,与同事一起突击构建了一个简单的lbs系统。当前比较主流的做法是使用mongodb,因为其已经封装了常用的lbs基本操作(如查找附近的人),功能非常强大,对于开发周期只有一周的项目,mongodb真可谓是救世主,把最重要的需求给完成了,谢天谢地!

    mongodb是比较著名的nosql db,想了解的同学不妨问问谷歌或度娘,对于专业问题本人倾向于问谷歌。本文还参考了这篇文章。我们使用的是目前最新版本的mongodb-2.4.9。

    首先从mongodb提供的lbs功能讲起:mongodb支持以下几种查询:

    1.区域内搜索:所谓区域内搜索,即列出附近一定范围内的所有记录,如baidu地图的“附近”。mongodb使用$geoWithin命令即可实现此类查询,其强大之处在于支持矩形区域($box)、圆形区域( $center)和多边形区域( $polygon)查询!以圆形区域查询为例,只需要给出圆心的经纬度和查询半径,就可以取到在该区域内的所有记录,不过返回结果是无序的。

    2.查找附近:查找附近即将某一个位置附近的记录按照由近到远的顺序返回,如很多社交app的查找附近的人。mongodb使用$near命令,输入中心点的坐标即可返回结果,结果是按照距离由小到大排序好的。$near接口比$geoWithin多了一步排序,但对2维坐标建索引的话,二者的查询效率基本相同。

    另外还有一个命令是$geoNear,可以认为是$near的升级版,除了返回记录之外还会返回距离及其他诊断信息。我们的应用需要计算距离,一开始就想使用这个命令,但是其使用很不方便。很奇怪的,该命令不能像$near和$geoWithin般可以和find命令集成,使用过程中很不灵活,无法完全满足我们的应用需求。

    其次说说距离计算

    MongoDB地理位置索引常用的有两种:1)2d 平面坐标索引,适用于基于平面的距离计算。2)2dsphere 几何球体索引,适用于球面几何距离运算。追求百分之百的精确,应选择2dsphere。不过,在坐标跨度不太大(如两千公里以内),这两个索引计算出的距离相差几乎可以忽略不计。关于mongodb实现的2维地理位置索引,可以参考这篇文章,写的简单易懂。

    接下来说说实践中碰到的复合索引的使用。因为mongodb是个开源项目,总会有些不完善的地方,而这些问题也只有使用的时候才会碰到。

    复合索引即对多个字段联合建立索引,假设在一个mongo集合(collection)的记录含有A和B两个字段,我们要查询A大于0且B大于100的记录,显然A、B的复合索引{“A”:1,”B”:1}可以有效提高这类查询的效率,mongodb也做到了。该查询用mongo的语言描述为:db.posts.find({ “A”:{$gt:0}, “B”:{$gt:100} } )。但如果我们要得到A大于0且按照B升序排序的记录,刚才建立的联合索引就不起作用了。这个查询用mongo的语言描述为:db.posts.find({ “A”:{$gt:0}} ).sort({“B”:1})。

    而且即使对所取记录总数做限制也无法提高查询效率。例如我假设复合条件的记录共有2000条,我只取100条,即db.posts.find({ “A”:{$gt:0}} ).sort({“B”:1}).limit(100)。按我的理解,如果复合索引起作用,不管limit与否都应该很快。但测试下来发现,查询的时间跟符合条件的记录总数成正比,即2000条取100条要50ms,而1000条取100条就只要30ms,似乎是不管limit多少,mongo会把所有满足find条件的记录全部读到内存,再根据sort的条件进行排序。这排序恰恰是性能的瓶颈所在,如果去除排序,2000条取100条也只要10ms左右,查询A大于0且B大于100的记录也是只要100ms。

    老外的分析,这个是mogodb目前的bug,应该会在2.6版本fix掉,希望如此吧。目前也没有什么办法可以优化这个问题,只能在find的时候通过更多的限制条件,减少被排序的记录数目,但在面对实际需求时往往不能这么做。

    所以,此次项目学到的经验是,开源项目的确有非常强大的功能,帮我们解决了大部分基础问题,也常常给我们很多惊喜(如mongo对地理信息查询的强大而全面的支持)。不过,所谓“天下没有免费的午餐”,使用开源项目不仅需要学习怎么用,使用过程中也会遇到一些坑,需要交点学费,所以,要时刻保持谨慎和批判的态度。

  • 相关阅读:
    623. Add One Row to Tree 将一行添加到树中
    771. Jewels and Stones 珠宝和石头
    216. Combination Sum III 组合总数三
    384. Shuffle an Array 随机播放一个数组
    382. Linked List Random Node 链接列表随机节点
    向github项目push代码后,Jenkins实现其自动构建
    centos下安装Jenkins
    python提取批量文件内的指定内容
    批处理实现:批量为文件添加注释
    python抓取每期双色球中奖号码,用于分析
  • 原文地址:https://www.cnblogs.com/fx2008/p/4115121.html
Copyright © 2011-2022 走看看