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
@Repositorypublic 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,会起到意想不到的效果。
源码下载
作者:孔垂云
链接:https://www.jianshu.com/p/592cdb0a1e48