ELK-Elasticsearch地理信息存储及查询之Geo_Point

https://www.cnblogs.com/kangoroo/p/6050692.html
https://blog.csdn.net/coffee_shop/article/details/107110707
导语:Elasticsearch提供了丰富的搜索和分析功能,地理位置功能可以让我们把基于地理位置的搜索、聚合、计算与全文搜索、结构化搜索和分析结合到一起。在这里易观的技术小哥哥,就跟大家做一个交流和探讨。



一、基本概念
1. GeoHash
GeoHash是一种将经纬度坐标(lat/lon)编码成字符串的方式,通过牺牲一定的精度,来获得高效的检索性能。

其原理是,将平面预先划分成多级矩形区域,在按照从大矩形到小矩形的顺序,将位置信息依次编码成二进制码,最后按照一定编码方式,转换成字符串。如:

比如这样一个点(39.923201, 116.390705) ,我们以纬度为例:

纬度的范围是(-90,90),其中间值为0。对于纬度39.923201,在区间(0,90)中,因此得到一个1;(0,90)区间的中间值为45度,纬度39.923201小于45,因此得到一个0,依次计算下去,即可得到纬度的二进制表示,如下表:

在这里插入图片描述

最后得到纬度的二进制表示为:

10111000110001111001

同理可以得到经度116.390705的二进制表示为:

11010010110001000100

合并纬度、经度的二进制:
合并方法是将经度、纬度二进制按照奇偶位合并:
11100 11101 00100 01111 00000 01101 01011 00001

按照Base32进行编码:

将上述合并后二进制编码后结果为:
wx4g0ec1

GeoHash的特点:

精度越高,字符串越长,

前缀匹配度越高,距离越近

2. geo_point
地理坐标点,在Elasticsearch中用来存经纬度数据的一种数据格式。

3. geo_shape
地理形状,Elasticsearch中用于存储复杂形状的一种数据格式,可以用来存储,点集、线、多边形、多边形集等多种集合形状。Geo-shapes 不能用于计算距离、排序、打分以及聚合。

使用geo_shope时,可以指定precision(精度)和距离误差。

本文将重点介绍geo_point相关功能,在以后的文章中,将会进一步介绍geo_shape

二、geo_point存储及查询
1. geo_point存储
geo_point是Elasticsearch中用于存储坐标点的数据格式,每一个坐标点都有经度和维度信息,geo_point格式的字段无法做自动映射,需要指定数据类型:

在这里插入图片描述

对于geo_point这种数据格式,Elasticsearch提供了三种不同的索引和展现形式:

假设经度:127.25456,纬度:25.236

(1) 对象:

在这里插入图片描述

(2) 数组:
在这里插入图片描述

(3) 字符串

在这里插入图片描述

注意:

l 使用字符串存储时,顺序是“纬度,经度”,使用数组存储时,顺序是“经度,纬度”。
| 如果geo_point为字符串或者对象时,先纬度,后经度,如果geo_point为数组时,先经度,后纬度
2.查询
geo_point支持geo_bounding_box、geo_distance、geo_polygon查询
3.在ES2.x版本时字符串数据只用string类型,没有keyword和text类型。
	ES5.x后,取消了 string类型,增加了keyword类型和text类型。


(1)geo_bounding_box查询

地理坐标盒模型:输入左上角和右下角坐标,即检索在地图上指定的矩形范围内的所有点。

geo_bounding_box是一种极其简单的查询方式,即使不使用geo_point,我们直接使用double类型存储经度和纬度数据,使用range查询一样可以实现这个功能。如果是多值,我们需要使用nested_object类型来实现。

geo_bounding_box默认使用内存过滤,这样需要一条一条计算,这是一种比较低效的查询方式,我们可以指定使用“indexed”方式,这样能够利用倒排索引实现高效检索,但是必须使用对象方式存储数据,但是,这种方式只有对单值存储有效。



(2)geo_distance查询

简而言之,这种查询,就是指定圆心和半径,圈出园内的点。Elasticsearch执行过程,是先使用圆的外切正方形快速筛选出点,在判断正方形内的每个点与圆心的距离,由此可见如果能使用倒排索引的range查询同样可以提高查询效率,所以,在设计索引和数据格式的时候,使用单值、对象方式存储经纬度数据,是比较理想的。

计算距离时,Elasticsearch提供了两种计算方式:ark、plane。

ark方式,将地球当做球体来处理,精确度高,但计算较慢,这是默认的计算方式;

plane方式,将地球当做平面来处理,精确度略低,但计算较快。

在锆云项目中,我们使用plane计算方式,在大多数应用场景中,几米的误差,完全可以忽略不计。



(3)geo_polygon 查询

输入多个坐标构成的不规则多边形,筛选出这个多边形中的点,这是一种性能极低检索方式,无法使用倒排索引提高查询性能。

3.聚合
(1)geo_distance聚合

基于geo_point的多桶聚合,类似于range聚合,指定点以及距离分段,由此得到,到点不同距离内的点的数量

在这里插入图片描述

同样,距离计算选ark,plane两种方式。



(2)geohash_grid聚合

我们知道,geohash的每一个值代表一个方格,geohash_grid聚合是指,将地图上的点,按照指定的精度,划分到各个方格中去,并返回各方格中点的个数,GeoHash的特点,对于这种“方格聚合”能够提供很好的支持,自然,精度越高,性能越差,所以,使用geohash_grid聚合,需要高精度的时候,尽量缩小数据集,在聚合之前使用filter过滤数据集。



(3)geo_bounds聚合

geo_bounds聚合可以快速找出能够包含所选点集的最小矩形,使用max ,min同样可以实现该操作。



(4)centroid聚合

中心点聚合,找出离散点集和的中心点。单独使用中心点聚合的场景并不多,多余geohash_grid聚合联合使用,以计算出每个区域中的中心点,对于提取从无规则离散点中提取有效坐标非常有效。



ES GEO空间检索

空间检索顾名思义提供了通过空间距离和位置关系进行检索的能力。有很多空间索引算法和类库可供选择。

ES内置了这种索引方式。下面详细介绍。

step1:创建索引

复制代码
def create_index():
    mapping = {
        "mappings": {
            "poi": {
                "_routing": {
                    "required": "true",
                    "path": "city_id"
                },
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "geofence_type": {
                        "type": "integer"
                    },
                    "city_id": {
                        "type": "integer"
                    },
                    "city_name": {
                        "type": "string",
                        "index": "not_analyzed"
                    },
                    "activity_id": {
                        "type": "integer"
                    },
                    "post_date": {
                        "type": "date"
                    },
                    "rank": {
                        "type": "float"
                    },
                    # 不管是point还是任意shape, 都用geo_shape,通过type来设置
                    # type在数据里
                    "location_point": {
                        "type": "geo_shape"
                    },
                    "location_shape": {
                        "type": "geo_shape"
                    },
                    # 在计算点间距离的时候, 需要geo_point类型变量
                    "point": {
                        "type": "geo_point"
                    }
                }
            }
        }
    }
    # 创建索引的时候可以不 mapping
    es.create_index(index='mapapp', body=mapping)
    # set_mapping = es_dsl.set_mapping('mapapp', 'poi', body=mapping)
	复制代码
	刷入测试数据,geo_data数据形如:

	id    geofence_type    city_id    city_name    activity_id    post_date    rank    location_point    location_shape    point
	1    1    1    北京    100301    2016/10/20    100.30     {"type":"point","coordinates":[55.75,37.616667]}    {"type":"polygon","coordinates":[[[22,22],[4.87463,52.37254],[4.87875,52.36369],[22,22]]]}    {"lat":55.75,"lon":37.616667}
	2    1    1    北京    100302    2016/10/21    12.00     {"type":"point","coordinates":[55.75,37.616668]}    {"type":"polygon","coordinates":[[[0,0],[4.87463,52.37254],[4.87875,52.36369],[0,0]]]}    {"lat":48.8567,"lon":2.3508}
	3    1    1    北京    100303    2016/10/22    3432.23     {"type":"point","coordinates":[55.75,37.616669]}    {"type":"polygon","coordinates":[[[4.8833,52.38617],[4.87463,52.37254],[4.87875,52.36369],[4.8833,52.38617]]]}    {"lat":32.75,"lon":37.616668}
	4    1    1    北京    100304    2016/10/23    246.80     {"type":"point","coordinates":[52.4796, 2.3508]}    {"type":"polygon","coordinates":[[[4.8833,52.38617],[4.87463,52.37254],[4.87875,52.36369],[4.8833,52.38617]]]}    {"lat":11.56,"lon":37.616669}

https://blog.csdn.net/qq_28165595/article/details/85101656
当location的类型 type=geo_point(而不是geo_shape)时候的圆形查询方式
	查询给定1000米距离范围内的点,我最近的项目就是要实现数据点击地图上某个点,展示该点方圆多少公里的其他点
	GET test/test/_search
	{
	  "query": {
	    "geo_distance": {
	      "distance": "1000m",
	      "location": {
	        "lat": 23.131304,
	        "lon": 113.262402
	      }
	    }
	  }
	}
	查询距离为1km上的点
	{
	    "query": {
	        "bool" : {
	            "must" : {
	                "match_all" : {}
	            },
	            "filter" : {
	                "geo_distance" : {
	                    "distance" : "1km",
	                    "location" : {
	                        "lat" : 23.131304,
	                        "lon" : 113.262402
	                    }
	                }
	            }
	        }
	    }
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值