ElasticSearch除了支持文本检索外,还支持地理信息检索。它主要支持两种类型的地理查询:一种是地理点(geo_point),即经纬度查询,另一种是地理形状查询(geo_shape),即支持点、线、圈、多边形查询等。
1、创建映射(mapping)
import requests import json attractions_url = "http://localhost:9200/attractions?include_type_name=true" data = { "mappings": { "hotel": { "properties": { "name": { "type": "text" }, "location": { "type": "geo_point" } } } } } json_data = json.loads(json.dumps(data)) r = requests.put(url=attractions_url, json=json_data) print(r.status_code) print(r.text)
对于某些特殊的查询,例如矩形范围查询,可以通过分别对lat和lon进行索引以提高查询速度。因为矩形范围的查询完全可以先通过lat过滤,再通过lon过滤。要实现此功能只需在location节点下添加”lat_lon”: true即可。
2、添加数据(插入文档)
import requests import json import pandas as pd f = pd.read_csv("data.csv") for index, row in df.iterrows(): url = "http://localhost:9200/attractions/hotel/{0}".format(index) data = {"name": str(int(row['hotel_id'])), "location": {"lat": row['lat'], "lon": row['lon']}} json_data = json.loads(json.dumps(data)) r = requests.put(url, json=json_data)
插入文档时,有三种格式的属性可以被映射为 geo_point 类型:
注意:数组格式是 lon 在前,lat 在后,而字符串格式正好相反。
3、查询
Elasticsearch 的地理位置查询,实际是使用过滤器对所有文档进行过滤。它支持以下四种查询方式:
以下为通过中心点距离范围内的示例:
import requests import json url = "http://localhost:9200/attractions/hotel/_search" lat, lon = 34.514020, 113.191598 data = { "query": { "bool": { "must": { "match_all": {} }, "filter": { "geo_distance": { "distance": "10km", "location": { "lat": lat, "lon": lon } } } } }, "sort": [ { "_geo_distance": { "location": [ { "lat": lat, "lon": lon } ], "unit": "m", "distance_type": "arc", "order": "asc", "validation_method": "STRICT" } } ] } json_data = json.loads(json.dumps(data)) r = requests.get(url, json=json_data)
除了中心点和距离,我们还需要指定计算距离的方式,每种方式对应着不同的精度和计算速度,常用的有三种:
对于大部分应用来说,plane的精度已经足够了,并且速度是最快的,所以推荐使用它。
ElasticSearch除了按照距离排序外,还支持按距离打分并且与其他评分一起应用。
有三种衰减函数:linear 、 exp 和 gauss (线性、指数和高斯函数),它们可以操作数值、时间以及经纬度地理坐标点这样的字段。所有三个函数都能接受以下参数:
这三个函数的唯一区别就是它们衰减曲线的形状,用图来说明会更为直观:
gauss
$$S(doc) = \exp(-\frac{\max(0,|\text{fieldvalue}_{doc}-\text{origin}|-\text{offset})^2}{2\sigma ^2})$$
其中:
$$\sigma ^2=-\frac{\text{scale}^2}{2\cdot \ln(\text{decay})}$$
exp
$$S(doc) = \exp(\lambda \cdot max(0,|\text{fieldvalue}_{doc}-\text{origin}|-\text{offset}))$$
其中:
$$\lambda = \frac{\ln(\text{scale})}{\text{scale}}$$
linear
$$S(doc) = \max(\frac{s-\max(0,|\text{fieldvalue}_{doc}-\text{origin}|-\text{offset})}{s},0)$$
其中:
$$s = \frac{\text{scale}}{1.0-\text{decay}}$$
参考连接:
Related posts: