文章 Elasticsearch检索实战 已经讲述了 Elasticsearch 基本检索使用,已满足大部分检索场景,但是某些特定项目中会使用到 聚合 和 LBS 这类高级检索,以满足检索需求。这里将讲述 Elasticsearch 的聚合和 LBS 检索使用方法。
本文示例的房源数据,见这里,检索同样使用 Elasticsearch 的 DSL 对比 SQL 来说明。
聚合
常规聚合
aggs 子句聚合是 Elasticsearch 常规的聚合实现方式。
桶和指标
先理解这两个基本概念:
名称 | 描述 |
---|---|
桶(Buckets) | 满足特定条件的文档的集合 |
指标(Metrics) | 对桶内的文档进行统计计算 |
每个聚合都是 一个或者多个桶和零个或者多个指标 的组合,聚合可能只有一个桶,可能只有一个指标,或者可能两个都有。例如这个 SQL:
SELECT COUNT(field_name) FROM table GROUP BY field_name |
其中COUNT(field_name)
相当于指标,GROUP BY field_name
相当于桶。桶在概念上类似于 SQL 的分组(GROUP BY),而指标则类似于 COUNT() 、 SUM() 、 MAX() 等统计方法。
桶和指标的可用取值列表:
分类 | 操作符 | 描述 |
---|---|---|
桶 | terms | 按精确值划分桶 |
指标 | sum | 桶内对该字段值求总数 |
指标 | min | 桶内对该字段值求最小值 |
指标 | max | 桶内对该字段值求最大值 |
指标 | avg | 桶内对该字段值求平均数 |
指标 | cardinality(基数) | 桶内对该字段不同值的数量(distinct 值) |
简单聚合
Elasticsearch 聚合 DSL 描述如下:
"aggs" : { |
其中,aggs_name 表示聚合结果返回的字段名,operate 表示桶或指标的操作符名,field_name 为需要进行聚合的字段。
- 例1,统计西二旗每个小区的房源数量:
-- SQL描述 |
Elasticsearch 聚合为:
{ |
聚合结果如下:
{ |
可见,此时聚合的结果有且只有分组后文档的 数量,只适合做一些分组后文档数的统计。
- 例2,去重统计西二旗小区的数量:
-- SQL描述 |
使用 cardinality 指标统计:
{ |
添加度量指标
上述的简单聚合,虽然可以统计桶内的文档数量,但是没法实现组内的其他指标统计,比如小区内的最低房源价格,这时就可以给桶添加一个 min 指标。
-- SQL描述 |
添加 min 指标后为:
{ |
结果为:
"buckets": [ |
嵌套桶
当然桶与桶之间也可以进行嵌套,这样就能满足复杂的聚合场景了。
例如,统计每个商圈的房源价格分布情况:
-- SQL描述 |
桶聚合实现如下:
{ |
聚合结果如下:
{ |
增加文档信息
通常情况下,聚合只返回了统计的一些指标,当需要获取聚合后每组的文档信息(小区的名字和坐标等)时,该怎么处理呢?这时,使用 top_hits 子句就可以实现。
例如,获取西二旗每个小区最便宜的房源信息:
{ |
其中,size 为组内返回的文档个数,sort 表示组内文档的排序规则,_source 指定组内文档返回的字段。
聚合后的房源信息:
{ |
字段折叠
从 Elasticsearch 5.0 之后,增加了一个新特性 field collapsing(字段折叠),字段折叠就是特定字段进行合并并去重,然后返回结果集,该功也能实现 agg top_hits 的聚合效果。
例如, 增加文档信息 部分的获取西二旗每个小区最便宜的房源信息,可以实现为:
{ |
检索结果如下:
{ |
Field collapsing 和 agg top_hits 区别:field collapsing 的结果是够精确,同时速度较快,更支持分页功能。
LBS
Elasticsearch 同样也支持了空间位置检索,即可以通过地理坐标点进行过滤检索。
索引格式
由于地理坐标点不能被动态映射自动检测,需要显式声明对应字段类型为 geo-point,如下:
PUT /rooms //索引名 |
数据格式
当需检索字段类型设置成 geo_point 后,推送的经纬度信息的形式可以是字符串、数组或者对象,如下:
形式 | 符号 | 示例 |
---|---|---|
字符串 | “lat,lon” | “40.060937,116.315943” |
对象 | lat 和 lon | { “lat”:40.060937, “lon”:116.315943 } |
数组 | [lon, lat] | [116.315943, 40.060937] |
特别需要注意数组形式时 lon 与 lat 的前后位置,不然就果断踩坑了。
然后,推送含有经纬度的数据:
POST /rooms/room/ |
检索过滤方式
Elasticsearch 中支持 4 种地理坐标点过滤器,如下表:
名称 | 描述 |
---|---|
geo_distance | 找出与指定位置在给定距离内的点 |
geo_distance_range | 找出与指定点距离在最小距离和最大距离之间的点 |
geo_bounding_box | 找出落在指定矩形框中的点 |
geo_polygon | 找出落在多边形中的点,将不说明 |
例如,查找西二旗地铁站 4km 的房源信息:
{ |
LBS 检索的结果为:
{ |
总结
本文讲述了使用 Elasticsearch 进行 聚合 和 LBS 检索,尽管文中只是以示例形式进行说明,会存在很多不全面的地方,还是希望对你我学习 Elasticsearch 能有所帮助。
相关文章 »
- Elasticsearch检索实战 (2017-08-09)