博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ElasticSearch 地理范围查询 距离 坐标集合
阅读量:5360 次
发布时间:2019-06-15

本文共 6546 字,大约阅读时间需要 21 分钟。

最近有两个需求是通过地图选择坐标,查询指定距离内的信息,和通过坐标集合组成不规则形状查询出不规则形状范围内的数据,在最起初我看到这个需求的时候第一个想法就是太复杂了,抵触。但是没有办法既然需求下来了只能硬着头皮上了,在调研之后最终还是决定了使用elasticsearch,下面就开始介绍如何使用elasticsearch来进行相关操作

设置数据格式

地理坐标点(geo-point) 是指地球表面可以用经纬度描述的一个点。地理坐标点可以用来计算两个坐标位置间的距离,或者判断一个点是否在一个区域中。地理坐标点不能被动态映射(dynamic mapping)自动检测,而是需要显式声明对应字段类型为 geo_point ,例子中的location字段

PUT platform_foreign_website{  "mappings": {     "store":{      "properties": {         "id": {            "type": "text"            },          "storeName": {            "type": "text"          },          "location":{            "type": "geo_point"          }    }     }  }}

存储示例:

1426490-20190619201923712-618800732.png

  • 半角逗号分割的字符串形式 “lat,lon“
  • 明确以 lat 和 lon 作为属性的对象
  • 数组形式表示 [lon,lat]

需要特别注意的就是纬度在前边经度在后边(latitude,longitude),数组表示形式是经度在前纬度在后([longitude,latitude])

geo_distance 找出指定位置在给定距离内的数据,相当于指定圆心和半径找到圆中点

  • 找出两千米范围内的所有门店
  • distance:距离 单位/km
  • location:坐标点 圆心所在位置

es代码示例

//无排序GET platform_foreign_website/communit/_search{  "query": {    "constant_score": {      "filter": {        "geo_distance": {          "distance": "2km",          "location": {            "lat": 39.662263,            "lon": 118.197815          }        }      },      "boost": 1.2    }  }}//带排序GET platform_foreign_website/communit/_search{  "query": {    "constant_score": {      "filter": {        "geo_distance": {          "distance": "1km",          "location": {            "lat": 39.662263,            "lon": 118.197815          }        }      },      "boost": 1.2    }  },"sort": [    {  "_geo_distance" : {    "location" : [      {        "lat" : 40.010955,        "lon" : 118.68545      }    ],    "unit" : "km",    "distance_type" : "arc",    "order" : "asc",    "validation_method" : "STRICT"  }}  ]}

java代码示例:

这里选用的是ElasticsearchTemplate 模板,因为没有分页取值比较方便,可以根据自己的业务逻辑自行选择

//无排序private List
getStores(CommunityToStoreParameter communityToStoreParameter) { //拼接条件 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); QueryBuilder isdeleteBuilder = QueryBuilders.termQuery("isdelete", false); // 以某点为中心,搜索指定范围 GeoDistanceQueryBuilder distanceQueryBuilder = new GeoDistanceQueryBuilder("location"); distanceQueryBuilder.point(communityToStoreParameter.getLatitude(), communityToStoreParameter.getLongitude()); //查询单位:km distanceQueryBuilder.distance(communityAndStoresdistance, DistanceUnit.KILOMETERS); boolQueryBuilder.filter(distanceQueryBuilder); boolQueryBuilder.must(isdeleteBuilder); SearchQuery storesearchQuery = new NativeSearchQueryBuilder() .withIndices(ESIndexAndTypeConstant.INDEX_NAME) .withTypes(ESIndexAndTypeConstant.STORE_TYPE_NAME) .withQuery(boolQueryBuilder) .build(); return elasticsearchTemplate.queryForList(storesearchQuery, Store.class); } //有排序private Page
getStores(Integer page, Integer size, AroundStoreParameter aroundStoreParameter, Double latitude, Double longitude, QueryBuilder isdeleteBuilder) { Pageable pageable = PageRequest.of(page - 1, size); NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder(); BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); // 以某点为中心,搜索指定范围 GeoDistanceQueryBuilder distanceQueryBuilder = new GeoDistanceQueryBuilder("location"); distanceQueryBuilder.point(latitude, longitude); //查询单位:km distanceQueryBuilder.distance(aroundStoreParameter.getDistance(), DistanceUnit.KILOMETERS); boolQueryBuilder.filter(distanceQueryBuilder); boolQueryBuilder.must(isdeleteBuilder); nativeSearchQueryBuilder.withQuery(boolQueryBuilder); // 按距离升序 GeoDistanceSortBuilder distanceSortBuilder = new GeoDistanceSortBuilder("location", latitude, longitude); distanceSortBuilder.unit(DistanceUnit.KILOMETERS); distanceSortBuilder.order(SortOrder.ASC); nativeSearchQueryBuilder.withSort(distanceSortBuilder); nativeSearchQueryBuilder.withPageable(pageable); return storeRepository.search(nativeSearchQueryBuilder.build()); }

geo_polygon(地理多边形查询): 一个查询,查询多边形内的所有的点,实现地图画圈筛选

es代码示例

GET platform_foreign_website/store/_search{  "query": {   "bool": {     "must": [       {"match_all": {}}     ],     "filter": {       "geo_polygon": {         "location": {           "points": [            { "lat": 39.634863, "lon": 118.137071 },            { "lat": 39.6349, "lon": 118.13291 },            { "lat": 39.633121, "lon": 118.128941 },            { "lat": 39.629607, "lon": 118.130915 },            { "lat": 39.632696, "lon": 118.132769 },            { "lat": 39.630513, "lon": 118.136018 }           ]         }       }     }   }  }}

java代码示例

public PageResultVO storeRange(Integer page, Integer size, List
storeRangeParameters) { Pageable pageable = PageRequest.of(page - 1, size); //坐标集合 List
geoPoints = storeRangeParameters.stream().map(a -> new GeoPoint(a.getLatitude(), a.getLongitude()) ).collect(Collectors.toList()); //拼接查询条件 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); QueryBuilder locationBuilder = QueryBuilders.geoPolygonQuery("location", geoPoints); QueryBuilder isdeleteBuilder = QueryBuilders.termQuery("isdelete", false); boolQueryBuilder.filter(locationBuilder); boolQueryBuilder.must(isdeleteBuilder); SearchQuery communityNativeBuilder = new NativeSearchQueryBuilder() .withPageable(pageable) .withQuery(boolQueryBuilder) .build(); Page
communities = communityRepository.search(communityNativeBuilder); List
communityInfoResultVOList = communities.getContent().stream().map(community -> new CommunityInfoResultVO(community.getCommunityName(), community.getLongitude(), community.getLatitude()) ).collect(Collectors.toList()); return new PageResultVO<>(communities.getTotalElements(), communityInfoResultVOList); }

这里说明一下为什么有的是用filter()有的使用must():must查询需要打分评估进行_score,但是filter,先使用filter把无用的数据过滤掉,在已经处理过的数据中must查询,能够有效地提升性能

这里说了 geo_distance(找出与指定位置在给定距离内的点) 和 geo_polygon(找出落在多边形中的点)两种方法,elasticsearch其实还有另外两种 方法 geo_bounding_box(找出落在指定矩形框中的坐标点) 和 geo_distance_range(找出与指定点距离在给定最小距离和最大距离之间的点),因为需求没有涉及到暂时没有调研,以后会慢慢晚上

所有这些过滤器的工作方式都相似: 把 索引中所有文档(而不仅仅是查询中匹配到的部分文档,见 fielddata-intro)的经纬度信息都载入内存,然后每个过滤器执行一个轻量级的计算去判断当前点是否落在指定区域

转载于:https://www.cnblogs.com/xiaoxiaoliu/p/11054405.html

你可能感兴趣的文章
sklearn之分类模型混淆矩阵和分类报告
查看>>
MySQL各存储引擎
查看>>
项目--简单导出CSV文件
查看>>
Oracle session相关数据字典(一)
查看>>
织梦文章内容提取第一张或者多张图片输出
查看>>
C#用正则表达式 获取网页源代码标签的属性或值
查看>>
BZOJ 3399 [Usaco2009 Mar]Sand Castle城堡(贪心)
查看>>
WCF(一) 简单的认知
查看>>
[MFC][DShow]简单例子
查看>>
Luogu P1141 01迷宫【搜索/dfs】By cellur925
查看>>
js onclick事件传参
查看>>
WiCloud 商业Wi-Fi管理平台
查看>>
团队项目--未完待续
查看>>
双重标准,我该怎么解决
查看>>
python中的网页标签等字符处理
查看>>
Mybatis输入类型和结果类型
查看>>
Linux常用命令(五)
查看>>
Linux常用命令(四)
查看>>
Linux常用命令(六)
查看>>
Linux常用命令(六)
查看>>