SpringMVC下MongoDB查询周围商家距离最近的点

     随着信息量的急剧增长,LBS技术现今已与我们的生活密不可分,今天主要分享的是基于MongoDB下,根据经纬度获取附近商家的实现。MongoDB是一个基于分布式文件存储的高性能数据库。

    对于距离的计算我们知道两点间直线最短,当两个元素的距离不是很远时,通过区域划分,可以直接使用勾股定理就能算得元素之间的距离。我们平时使用的「附近的人」的功能,元素距离都不是很大,勾股定理算距离足矣。不过需要注意的是,经纬度坐标的密度不一样 (地球是一个椭圆),勾股定律计算平方差时之后再求和时,需要按一定的系数比加权求和,如果不求精确的话,也可以不必加权,当然我们现实生活处于一个三维空间,除了经度和维度之外还有一个高程的概念也就是海拔。

      当前主流的距离算法(geoHash算法)包括redis和MongoDB在计算距离是都是使用该算法的,geohash简单来说就是将二位的平面坐标转换成一维的整数,对于地理坐标数据我们不好构建索引,当将其转成一维整数时我们就能够很容易的构建索引提高查询效率,无论是范围的Btree还是精确的hash索引。

    首先假设我们将需要索引的整个地图分成16×16的方格,如下图(左下角为坐标0,0 右上角为坐标16,16):

SpringMVC下MongoDB查询周围商家距离最近的点_第1张图片

 

MongoDB在建立索引的时候,会根据相应字段的坐标计算一个可以用来做索引的hash值,这个值叫做geohash,下面我们以地图上坐标为[4,6]的点(图中红叉位置)为例。

我们第一步将整个地图分成等大小的四块,这样我们在实际中 将各个区域的位置定义成对应的编号,00、01、10、11。这样之前的4,6坐标就变成了整数00。

 

SpringMVC下MongoDB查询周围商家距离最近的点_第2张图片

我们可以继续往下细分那么之前的坐标点4,6就变成了0011,当我们继续往下细分的时候得到的结果值就更加精确了,MongoDB中是切了26次52位的,将得到结果建立索引提高查询效率。

 

SpringMVC下MongoDB查询周围商家距离最近的点_第3张图片

A、插入地理坐标

db.mapinfo.insert({"address" : "深圳市丰巢","loc" : { "type": "Point", "coordinates": [111.111111,122.222222]}})

B、地理坐标索引构建

db.mapinfo.ensureIndex( { loc : "2dsphere" } )

C、查询一定范围内的坐标 倒序 单位是米

db.mapinfo.find({ "loc" : { "$near" : { "$geometry" :

{ "type" : "Point", "coordinates" : [111.111111,122.222222] },

"$maxDistance" : 5000 } } }).limit(50);

Java存储,存储到mongo的地理坐标需要重新构建一个对象存放,查询方圆一公里内距离最近的点,升序排列

DBObject query=new BasicDBObject();

query.put("geomp",newBasicDBObject("$nearSphere",

newBasicDBObject("$geometry",newBasicDBObject("type","Point")

.append("coordinates",newdouble[] {lng,lat})).append("$maxDistance",meter)));

if(StringFormatter.strIsNotNull(businessMongoEntity.getName())) {

Patternpattern= Pattern.compile(

"^.*"+businessMongoEntity.getName() +".*$",Pattern.CASE_INSENSITIVE);

query.put("name",pattern);

}

Query query1=new BasicQuery(query);

query1.skip(fromcount);

query1.limit(page.getSize());

List bme=template.find(query1,

BusinessMongoEntity.class);

inttotal=template.getCollection("businessMongoEntity").find(query).count();

// List list =

// template.getCollection("businessMongoEntity").find(query).skip(10).limit(20).toArray();

page.setRecords(bme);

page.setTotal(total);

return page;

 java更新代码


DBObjectdbObject=newBasicDBObject();

dbObject.put("registernum",businessMongoEntity.getRegisternum());

DBObjectdbObjectupdate=newBasicDBObject();

dbObjectupdate.put("imgurl",businessMongoEntity.getImgurl());

dbObjectupdate.put("openid",businessMongoEntity.getOpenid());

dbObjectupdate.put("geomp",businessMongoEntity.getGeomp());

dbObjectupdate.put("username",businessMongoEntity.getUsername());

dbObjectupdate.put("password",businessMongoEntity.getPassword());

//template.getCollection("businessMongoEntity").update(dbObject, dbObjectupdate);

Updateupdate= Update.update("geomp",businessMongoEntity.getGeomp())

.set("imgurl",businessMongoEntity.getImgurl())

.set("openid",businessMongoEntity.getOpenid())

.set("username",businessMongoEntity.getUsername()).set("password",businessMongoEntity.getPassword());

Queryquery=newBasicQuery(dbObject);

template.upsert(query,update, BusinessMongoEntity.class)

 

计算两点间的距离

 /**   
     * 通过经纬度获取距离(单位:米)   
     * @param lat1   纬度
     * @param lng1   经度
     * @param lat2   纬度
     * @param lng2   经度
     * @return   
     */    
    public static double getDistance(double lat1, double lng1, double lat2,    
                                     double lng2) {    
        double radLat1 = rad(lat1);    
        double radLat2 = rad(lat2);    
        double a = radLat1 - radLat2;    
        double b = rad(lng1) - rad(lng2);    
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)    
                + Math.cos(radLat1) * Math.cos(radLat2)    
                * Math.pow(Math.sin(b / 2), 2)));    
        s = s * EARTH_RADIUS;    
        s = Math.round(s * 10000d) / 10000d;    
        s = s*1000;    
        return s;    
    }

导入架包

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;

构建坐标对象对象

public class GeomArrayBean {

	private String type;
	private Double[] coordinates;
	
	public GeomArrayBean(){
		type = "Point";
	}
	
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	public Double[] getCoordinates() {
		return coordinates;
	}
	public void setCoordinates(Double[] coordinates) {
		this.coordinates = coordinates;
	}
	
	
}

数据存储

BusinessMongoEntity businessMongoEntity=new BusinessMongoEntity();

			businessMongoEntity.setId(IdWorker.getInstance().nextId());
            //构建存储对象
			GeomArrayBean ga = new GeomArrayBean();
			ga.setType("Point");
			Double a = 118.803799d;
			Double b = 31.979234d;
			Double[] aa = {a, b};
			ga.setCoordinates(aa);
			businessMongoEntity.setName("林青2");
			businessMongoEntity.setGeomp(ga);
			businessMongoEntity.setUsername("18050010830");
			businessMongoEntity.setPassword("010830");
			businessMongoEntity.setRegisternum("666");
			businessMongoEntity.setImgurl("www.baidu.com");
			businessMongoEntity.setOpenid("7890");
			businessMongoEntity.setTel("联系电话");
			businessMongoEntity.setContact("联系人");
			businessMongoService.insertBusinessMongoEntity(businessMongoEntity);

 

你可能感兴趣的:(mysql,数据库)