基于mongo的地理位置索引

前言

最近新入职的公司做的是LBS相关的项目,一般会对一些地理位置及相关数据做操作。一般存储每个地点的经纬度的坐标,组成点坐标或是多边形、矩形、圆形等区域,也可能是球面。会有一些应用场景,比如一辆车越过电子围栏区域触发报警,就比如查询一个点是否在指定区域内。或查询某个坐标点附近的地理位置场所坐标,而Mongodb专门针对这种查询建立了地理空间索引,主要分为2d和2dsphere两种分别是针对平面和球面。Mongo的位置信息查询性能非常高。

查询点是否在区域内
实体类,构建2dsphere类型的索引

@Data
@Document(collection = "area")
@CompoundIndexes({
        @CompoundIndex(name = "2dsphere_index_01", def = "{'geoJsonPolygon': '2dsphere'}"),
})
public class Area {

    @Id
    private String id;

    private String name;

    //区域点坐标集合 多边形
    private GeoJsonPolygon geoJsonPolygon;
}


数据访问,新增和查询点是否在数据库已存数据的某个区域内


@Repository
public class AreaRepository {

    @Autowired
    private MongoTemplate mongoTemplate;

    public void insert(Area area){
        mongoTemplate.insert(area);
    }

    public boolean pointIsInArea(GeoJsonPoint point){
        Query query = new Query();
        query.addCriteria(Criteria.where("geoJsonPolygon").intersects(point));
        Area area = mongoTemplate.findOne(query,Area.class);
        return area != null;
    }
}



测试用例,创建区域的时候,坐标数组的首末坐标一致。


public class AreaTests extends MongoExploreApplicationTests {


    @Autowired
    private AreaRepository areaRepository;

    @Test
    public void insert(){
        Area area = new Area();
        area.setName("一个测试的多边形区域");
        area.setGeoJsonPolygon(
                new GeoJsonPolygon(
                        new Point(113.314882,23.163055),
                        new Point(113.355845,23.167042),
                        new Point(113.370289,23.149564),
                        new Point(113.356779,23.129758),
                        new Point(113.338238,23.13913),
                        new Point(113.330979,23.124706),
                        new Point(113.313588,23.140858),
                        new Point(113.323865,23.158204),
                        new Point(113.314882,23.163055)
                )
        );
        areaRepository.insert(area);
    }

    @Test
    public void pointIsInArea(){
        GeoJsonPoint geoJsonPoint = new GeoJsonPoint(113.330908,23.155678);
        boolean exist = areaRepository.pointIsInArea(geoJsonPoint);
        Assert.isTrue(exist,"DB不存在存在该点的区域");
    }
}



使用指令:

创建索引,插入区域对象
db.area.ensureIndex( 
 { 
 geoJsonPolygon: "2dsphere"
 } 
);
 
db.area.insert(
 {
 geoJsonPolygon:
 {
 type:"Polygon",
 coordinates:[[
 [113.314882,23.163055],
 [113.355845,23.167042],
 [113.370289,23.149564],
 [113.356779,23.129758],
 [113.338238,23.13913],
 [113.330979,23.124706],
 [113.313588,23.140858],
 [113.323865,23.158204],
 [113.314882,23.163055],
 ]]
 }
 }
);


db.area.find(
 {
 geoJsonPolygon:
 {
 $geoIntersects:
 {
 $geometry:{ 
  "type" : "Point",
  "coordinates" : [113.330908,23.155678] }
 }
 }
 }
);



结果如下图

ER2C0)087QJ$2~G6APJU}F0.png

点坐标换下查询结果如下图

TK%_@SZZNM${E_627WEWKUJ.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值