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 ...
随机推荐
- WPF 通过进程实现异常隔离的客户端
当 WPF 客户端需要实现插件系统的时候,一般可以基于容器或者进程来实现.如果需要对外部插件实现异常隔离,那么只能使用子进程来加载插件,这样插件如果抛出异常,也不会影响到主进程.WPF 元素无法跨进程 ...
- list使用详解
List双向链表 再谈链表 List链表的概念再度出现了,作为线性表的一员,C++的STL提供了快速进行构建的方法,为此,在前文的基础上通过STL进行直接使用,这对于程序设计中快速构建原型是相当有必要 ...
- Zookeeper分布式安装部署
1. 解压安装 1.1 解压Zookeeper安装包到/opt/module/目录下 tar -zxvf /opt/software/apache-zookeeper-3.6.2-bin.tar.gz ...
- Mysql实现无插入有更新(不知主键的情况下)
网上很多资料说有两种方式 (必须现有唯一键) 1.INSERT 中ON DUPLICATE KEY UPDATE的使用 2.REPLACE的使用 通过可以得出结果: 如果a和b字段 能决定唯一 例子: ...
- 5ucms后台新增字段
1.修改admin\inc\class_content.asp文件,把需要的字段添加进去 2.修改\admin\admin_content.asp 文件,把需要的字段添加进后台操作模板 3.用sql语 ...
- Mybatis中使用级联查询,一对多的查询
一.需求描述 自己在开发一个小程序的过程中,需要做的一个查询是稍微比较复杂的查询,根据用户信息去查询用户所对应的宠物信息. 一个用户可能对应多个宠物,所以在用户和宠物信息的对应关系就是一对多的关系. ...
- 关于jQ的小案例分享
<!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>表 ...
- vue-cli3 取消eslint 校验代码
项目生成后会有个.eslintrc.js文件 module.exports = { root: true, env: { node: true }, 'extends': [ 'plugin:vue/ ...
- YbtOJ#752-最优分组【笛卡尔树,线段树】
正题 题目链接:http://www.ybtoj.com.cn/problem/752 题目大意 \(n\)个人,每个人有\(c_i\)和\(d_i\)分别表示这个人所在的队伍的最少/最多人数. 然后 ...
- mysql的一次意外
打开navcat连接本地mysql数据库的时候说mysql服务无法连接,切换到cmd用命令行来启动报错,发生系统错误5,查看百度,需用管理员权限运行, 用管理员运行依旧不好使 C:\WINDOWS\s ...