MongoDB支持二維空間索引,使用空間索引,mongoDB支持一種特殊查詢,如某地圖網(wǎng)站上可以查找離你最近的咖啡廳,銀行等信息。這個使用mongoDB的空間索引結(jié)合特殊的查詢方法很容易實現(xiàn)择份。
現(xiàn)在常見的滴滴歌憨、膜拜娘赴、OFO等基于位置進(jìn)行查詢的場景都可以使用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二維數(shù)組砾隅,用于存儲經(jīng)緯度信息俱济。
加了一個構(gòu)造方法嘶是,用于初始化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);
}
這里面兩個方法蛛碌,一個是按照中心點范圍查找聂喇,另一個是按照矩形范圍查找,兩個參數(shù)蔚携,一個是左下角位置希太,一個是右上角位置。
測試方法Test
@Test
public void init() {
// 等同db.location.ensureIndex( {position: "2d"} )
mongoTemplate.indexOps(Location.class).ensureIndex(new GeospatialIndex("position"));
// 初始化數(shù)據(jù)
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("復(fù)興門", 116.3631701881, 39.9129554253));
mongoTemplate.save(new Location("復(fù)興門", 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));
}
初始化數(shù)據(jù)酝蜒,這里拿天安門附近的一些數(shù)據(jù)作為例子誊辉。
在初始化之前,建立了一個GeospatialIndex
索引亡脑,即位置索引
這個位置索引在進(jìn)行相關(guān)坐標(biāo)查詢時起到關(guān)鍵作用堕澄。可以試想一下霉咨,如果把上述信息存在普通的關(guān)系數(shù)據(jù)庫中蛙紫,想進(jìn)行按中心點查詢,該是一個多么復(fù)雜的操作躯护,需要計算所有點到中心點的距離,然后判斷距離是否滿足范圍丽涩。
/**
* 查找天安門附近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
是天安門的經(jīng)緯度,3/111
是3公里以內(nèi)的數(shù)據(jù)棺滞。111是每一個經(jīng)度代表的公里數(shù)(不懂的自補(bǔ)地理信息)。
查詢結(jié)果如下:
/**
* 查找左下角是菜市口矢渊,右上角是東四继准,這個方形區(qū)域內(nèi)的所有點
*/
@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());
});
}
查詢結(jié)果如下:
基于MongoDB的位置信息查詢性能非常非常高,在做位置信息查找時可以嘗試使用MongoDB矮男,會起到意想不到的效果移必。