4.5MongoDB实现地理位置索引

MongoDB支持二维空间索引,使用空间索引,mongoDB支持一种特殊查询,如某地图网站上可以查找离你最近的咖啡厅,银行等信息。这个使用mongoDB的空间索引结合特殊的查询方法很容易实现。

现在常见的滴滴、膜拜、OFO等基于位置进行查询的场景都可以使用MongoDB的位置索引。

下面讲一下具体使用。

spring整合mongodb的信息参照4.2MongoDB和Spring整合

新建位置实体类Position.java

@Document(collection = "location")
public class Location {
    @Id
    private String id;//地点名称
    private double[] position;//位置信息

    public Location(String id, double lon, double lat) {
        this.id = id;
        double[] p = new double[]{lon, lat};
        this.position = p;
    }
//get set省略

这里面建了一个position的double二维数组,用于存储经纬度信息。
加了一个构造方法,用于初始化Location

位置查找的具体方法LocationRepository.java

@Repository
public class LocationRepository {

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 按圆形查找
     *
     * @param point
     * @param maxDistance
     * @return
     */
    public List<Location> findCircleNear(Point point, double maxDistance) {
        Query query = new Query(Criteria.where("position").near(point).maxDistance(maxDistance / 111));
        return mongoTemplate.find(query, Location.class);
    }

    /**
     * 按方形查找
     *
     * @param lowerLeft
     * @param upperRight
     * @return
     */
    public List<Location> findBoxWithin(Point lowerLeft, Point upperRight) {
        Query query = new Query(Criteria.where("position").within(new Box(lowerLeft, upperRight)));
        return mongoTemplate.find(query, Location.class);
    }

这里面两个方法,一个是按照中心点范围查找,另一个是按照矩形范围查找,两个参数,一个是左下角位置,一个是右上角位置。

测试方法Test

@Test
    public void init() {
        // 等同db.location.ensureIndex( {position: "2d"} )
        mongoTemplate.indexOps(Location.class).ensureIndex(new GeospatialIndex("position"));
        // 初始化数据
        mongoTemplate.save(new Location("天安门", 116.4041602659, 39.9096215780));
        mongoTemplate.save(new Location("东单", 116.4244857287, 39.9144951360));
        mongoTemplate.save(new Location("王府井", 116.4177807251, 39.9175129885));
        mongoTemplate.save(new Location("西单", 116.3834863095, 39.9133467579));
        mongoTemplate.save(new Location("复兴门", 116.3631701881, 39.9129554253));
        mongoTemplate.save(new Location("复兴门", 116.3631701881, 39.9129554253));
        mongoTemplate.save(new Location("西四", 116.3799838526, 39.9299098531));
        mongoTemplate.save(new Location("菜市口", 116.3809950293, 39.8952009239));
        mongoTemplate.save(new Location("东四", 116.4239387439, 39.9306126797));
    }

初始化数据,这里拿天安门附近的一些数据作为例子。
在初始化之前,建立了一个GeospatialIndex索引,即位置索引

位置索引

这个位置索引在进行相关坐标查询时起到关键作用。可以试想一下,如果把上述信息存在普通的关系数据库中,想进行按中心点查询,该是一个多么复杂的操作,需要计算所有点到中心点的距离,然后判断距离是否满足范围。

/**
     * 查找天安门附近3公里的地点
     */
    @Test
    public void findCircleNearTest() {
        List<Location> locations = locationRepository.findCircleNear(new Point(116.4041602659, 39.9096215780), 3 / 111);
        locations.forEach(location -> {
            System.out.println(location.toString());
        });
    }

这里面116.4041602659, 39.9096215780是天安门的经纬度,3/111是3公里以内的数据。111是每一个经度代表的公里数(不懂的自补地理信息)。

查询结果如下:

按中心点查询
 /**
     * 查找左下角是菜市口,右上角是东四,这个方形区域内的所有点
     */
    @Test
    public void findBoxNearTest() {
        Point point1 = new Point(116.3809950293, 39.8952009239);
        Point point2 = new Point(116.4239387439, 39.9306126797);
        List<Location> locations = locationRepository.findBoxWithin(point1, point2);
        locations.forEach(location -> {
            System.out.println(location.toString());
        });
    }

查询结果如下:

矩形查找

基于MongoDB的位置信息查询性能非常非常高,在做位置信息查找时可以尝试使用MongoDB,会起到意想不到的效果。

源码下载

本工程详细源码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容