elasticsearch地理位置查询
elasticsearch地理位置查询
一、背景
最近有个需求,需要获取某个位置附近的楼盘,**比如:**获取当前用户所在位置,方圆100km千米之内的楼盘信息。经过调研,发现可以使用 redis、mongodb、elasticsearch等实现。经过考虑之后决定使用es来实现,此处简单记录下es中geo方面api的使用。
二、geo数据类型
在es中存在2种地理位置数据类型,geo_point和geo_shape。es无法自动识别这种数据类型,需要在创建mapping的时候,自己手动指定。
1、geo_point
geo_point使用的是经纬度的坐标点,可以计算落在某个矩形内的点、以某个点为半径(圆)的点、某个多边形内的点(弃用了)、排序、聚合等操作。

2、geo_shape
geo_shape表示的是一个复杂的图形,使用的是GeoJSON的格式来表示复杂的图形。比如:我们要表示一个图书馆的坐标位置,如果图书馆占的位置比较大,用一个点表示可能就不准了,此时就可以使用geo_shape来表示了。
不过这种数据类型也有缺点:比如不能排序等等(因为是多边形的点)。
三、此处对geo_point类型实战
1、背景

1、图中的 ① ② ③ ④ 表示是需要加入到 es 中的建筑物
| 建筑物 | 坐标 | 距离地点 | 相隔距离 | 解释 |
|---|---|---|---|---|
| 上海站 | 121.462311,31.256224 | 上海站 | ||
| 上海静安洲际酒店 | 121.460186,31.251281 | 上海站 | 586.24米 | 上海站和该酒店大概像个586.24米 |
| 交通公园 | 121.473939,31.253531 | 上海站 | 1146.45米 | |
| 万业远景大厦 | 121.448215,31.26229 | 上海站 | 1501.74米 |
2、图中的圆形、正方形、多边形表示后期需要使用 es 查询出来里面里面的地点。
3、图中的短小的箭头️表示边界。
2、插入地点数据
1、创建索引
PUT /geo_index
{
"settings": {
"number_of_shards": 2,
"number_of_replicas": 2,
"analysis": {
"analyzer": {
"default": {
"type": "ik_max_word"
}
}
}
},
"mappings": {
"properties": {
"building_name": {
"type": "keyword"
},
"location": {
// 此处手动指定数据类型
"type": "geo_point"
}
}
}
}
注意️:
1、在索引中,我们自己指定来location字段的类型为geo_point类型。
2、building_name的字段类型为keyword表示不分词,这个字段只是为了测试,没有什么用。
3、不用指定索引的type,在es7中只有一个type。
2、插入地理位置数据
POST _bulk
{"create":{"_index":"geo_index","_id":1}}
{"building_name":"上海站","location":{"lat":31.256224,"lon":121.462311}}
{"create":{"_index":"geo_index","_id":2}}
{"building_name":"上海静安洲际酒店","location":"POINT (121.460186 31.251281)"}
{"create":{"_index":"geo_index","_id":3}}
{"building_name":"交通公园","location":"31.253531,121.473939"}
{"create":{"_index":"geo_index","_id":4}}
{"building_name":"万业远景大厦","location":[121.448215,31.26229]}
注意️:
1、从上面可知:地理位置的插入的格式可以存在4种方式。
1、 {"lat":"","lon":""}
2、 "lat,lon"
3、 [Well-Known Text](https://docs.opengeospatial.org/is/12-063r5/12-063r5.html) "POINT (lon lat)"
4、 [lon,lat]
5、 还有一种 geohash 的格式
需要注意的是:使用 数组/Well-Known-Text 的格式的时候,经纬度是反过来的。
3、执行检索
1、geo_bounding_box 矩形过滤

从上图可知左上角和右下方的坐标分别为 (121.444075,31.265395)和(121.468417,31.253845)
执行查询,应该可以查询出 上海站和万业远景大厦
1、es查询语句
GET /geo_index/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"geo_bounding_box": {
"location": {
"top_left": {
"lat": 31.265395,
"lon": 121.444075
},
"bottom_right": {
"lat": 31.253845,
"lon": 121.468417
}
}
}
}
}
}
}
2、查询结果

从图中可以看到,查询出来了 上海站和万业远景大厦,结果是正确的。
2、geo_distance 圆形查询
这个是距离查询,是以某个点向周围扩算的距离范围。

在上一步的背景中,我们知道上海站的坐标(121.462311,31.256224),同时也知道了上海站距离各个周边的距离有多远,此处我们以上海站为中心,查询方圆600米的建筑物,可知只有上海静安洲际酒店和上海站符合。
1、es查询语句
GET /geo_index/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"geo_distance": {
"distance": "600m",
"distance_type": "arc",
"_name":"optional_name",
"location": {
"lat": 31.256224,
"lon": 121.462311
}
}
}
}
}
}
注意️:
1、distance_type的值存在2个 arc和plane
arc:默认的方式,这种方式计算比较精确,但是比较慢,是把地球当作一个球体计算。plane:这种方式计算比较快,但是可能不怎么准,越靠近赤道越准,是把地球当成平坦的进行计算。
2、distance后面可用的单位有km、m、cm、mm、nmi、mi、yd、ft、in

2、查询结果

3、geo_distance 查询并排序,返回距离相隔多少米
1、es 查询语句
GET /geo_index/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"geo_distance": {
"distance": "600m",
"distance_type": "arc",
"_name": "optional_name",
"location": {
"lat": 31.256224,
"lon": 121.462311
}
}
}
}
},
"sort": [
{
"_geo_distance": {
"location": {
"lat": 31.256224,
"lon": 121.462311
},
"order": "desc",
"unit": "m",
"distance_type": "arc"
}
}
]
}
注意️:
1、sort执行排序。
2、查询结果

4、geo_distance聚合
需求:
1. 统计`上海站`500米之内的建筑物有多少。
2. 统计`上海站`500-1000米之内的建筑物有多少。
3. 统计`上海站`大于1000米的建筑物有多少。
1、es查询语句
GET /geo_index/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
}
}
},
"aggs": {
"rings_around_amsterdam": {
"geo_distance": {
"field": "location",
"origin": {
"lat": 31.256224,
"lon": 121.462311
},
"unit": "m",
"distance_type": "arc",
"ranges": [
{"to": 500,"key": "first"},
{"from": 500,"to": 1000,"key": "second" },
{"from": 1000,"key": "third"}
],
"keyed": true
}
}
}
}
2、查询结果

从上图中可以看到:
1、距离上海站在 0-500米之间的建筑物只有1个。
2、距离上海站在 500-1000之间的建筑物有1个。
3、距离上海站在 1000以上的有2个。
5、geo-polygon-多边形查询(过时)
在 es7.12 中已经过时了,推荐使用 geo_shape来实现

6、一个综合案例
1、需求:
1、查询语句query,查询出所有的数据,并过滤出以上海站为中心的3km内的所有的建筑物。
2、aggs,用于统计出上海在 500米以内、500-1000米、1000米之外的建筑物数量。
3、sort用于排序。
4、post_filter用于将结果缩小到上海站1000米以内。
2、查询结果
GET /geo_index/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
},
// 过滤出上海站周围3km范围内的建筑物
"filter": {
"geo_distance": {
"distance": "3km",
"distance_type": "arc",
"_name":"optional_name",
"location": {
"lat": 31.256224,
"lon": 121.462311
}
}
}
}
},
// 聚合上海站周围的建筑物的数量
"aggs": {
"rings_around_amsterdam": {
"geo_distance": {
"field": "location",
"origin": {
"lat": 31.256224,
"lon": 121.462311
},
"unit": "m",
"distance_type": "arc",
"ranges": [
{"to": 500,"key": "first"},
{"from": 500,"to": 1000,"key": "second" },
{"from": 1000,"key": "third"}
],
"keyed": true
}
}
},
// 对查询到的结果排序,并将距离放到响应数据的 sort 字段中。
"sort": [
{
"_geo_distance": {
"location": {
"lat": 31.256224,
"lon": 121.462311
},
"order": "desc",
"unit": "m",
"distance_type": "arc"
}
}
],
// 将结果缩小到上海站附近1km的范围内。
"post_filter": {
"geo_distance": {
"distance": "1km",
"location": {
"lat": 31.256224,
"lon": 121.462311
}
}
}
}
四、参考文档
2、距离单位
3、排序
4、矩形查询
6、坐标拾取系统
elasticsearch地理位置查询的更多相关文章
- Java High Level REST Client 使用地理位置查询
Java High Level REST Client 使用地理位置查询 一.需求 二.对应的query语句 三.对应java代码 1.引入 jar 包 2.创建 RestHighLevelClien ...
- 【转】elasticsearch的查询器query与过滤器filter的区别
很多刚学elasticsearch的人对于查询方面很是苦恼,说实话es的查询语法真心不简单- 当然你如果入门之后,会发现elasticsearch的rest api设计是多么有意思. 说正题,ela ...
- 基于百度地图SDK和Elasticsearch GEO查询的地理围栏分析系统(1)
本文描述了一个系统,功能是评价和抽象地理围栏(Geo-fencing),以及监控和分析核心地理围栏中业务的表现. 技术栈:Spring-JQuery-百度地图WEB SDK 存储:Hive-Elast ...
- Elasticsearch Kibana查询语法
Elasticsearch Kibana查询语法 2018年06月03日 23:52:30 wangpei1949 阅读数:3992 Elasticsearch Kibana Discover的搜 ...
- MongoDB的地理位置查询,以及和mysql的使用对比
MongoDB的一个特色就是具有丰富的查询接口,比如地理位置查询. 在地理位置查询上,MongoDB有着比传统关系型数据库的优势,下面举个例子. 当前移动互联网应用,按用户离目标门店距离排序上的场景很 ...
- ElasticSearch—分页查询
ElasticSearch查询—分页查询详解 Elasticsearch中数据都存储在分片中,当执行搜索时每个分片独立搜索后,数据再经过整合返回.那么,如何实现分页查询呢? 按照一般的查询流程来说,如 ...
- Elasticsearch 邻近查询示例
Elasticsearch 邻近查询示例(全切分分词) JAVA API方式: SpanNearQueryBuilder span = QueryBuilders.spanNearQuery(); s ...
- elasticsearch简单查询
elasticsearch简单查询示例: { "from": "0", //分页,从第一页开始 "size": "10" ...
- ElasticSearch高级查询
ElasticSearch高级查询 https://www.imooc.com/video/15759/0 ElasticSearch查询 1,子条件查询:特定字段查询所指特定值 1.1query c ...
随机推荐
- Junit5快速入门指南-4
Junit5套件测试 @RunWith(JUnitPlatform.class) 执行套件 @SelectPackages({"packageA","packageB&q ...
- github上使用C语言实现的线程池
网上介绍线程池的知识很多,但是在代码实现上介绍的又不是那么多.而且给人的一种感觉就是:你的这种实现是正规的方式还是你自己的实现? 如果有这么个疑问,且想找一个靠谱的代码拿来使用,那么这个项目是个不错的 ...
- windows下nodejs正确安装方式
下载安装包: 32 位安装包下载地址 : https://nodejs.org/dist/v4.4.3/node-v4.4.3-x86.msi 64 位安装包下载地址 : https://node ...
- Request请求对象
一.Request对象由服务器创建,我们使用 浏览器访问服务器资源原理: 二.Request体系结构 其中,servlet 的service()方法参数列表是 servletRequest对象, Ht ...
- python库--tensorflow--数学函数
官方API(需FQ) 中文API 方法 返回值类型 参数 说明 算数运算符 .add() Tensor x, y, name=N 加法(若x,y都为tensor, 数据类型需一致, 以下所有x,y都如 ...
- Playfield 类方法的注释
前言 本篇随笔的底包采用的是百度炉石兄弟吧20200109折腾版中自带的 routines 文件. 本次仅为绝大多数方法添加 xml 注释和简单解析,没有具体解析与重构. Playfield 类方法众 ...
- 学生信息管理系统.cpp(大二上)
#include<iostream> #include<fstream> #include<string> #include<iomanip> #i ...
- python matplotlib.pyplot 散点图详解(1)
python matplotlib.pyplot散点图详解(1) 一.创建散点图 可以用scatter函数创建散点图 并使用show函数显示散点图 代码如下: import matplotlib.py ...
- 接口测试-Mock测试方法
接口测试-Mock测试方法一.关于Mock测试1.什么是Mock测试?Mock 测试就是在测试过程中,对于某些不容易构造(如 HttpServletRequest 必须在Servlet 容器中才能构造 ...
- 鸿蒙内核源码分析(调度队列篇) | 内核有多少个调度队列 | 百篇博客分析OpenHarmony源码 | v6.05
百篇博客系列篇.本篇为: v06.xx 鸿蒙内核源码分析(调度队列篇) | 内核有多少个调度队列 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...