Composite 聚合——Elasticsearch 聚合后分页新实现

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 1、聚合后分页应用场景在常规检索的基础上,用户期望返回基于特定字段的聚合结果,且用户期望分页查看检索和聚合结果。如下图所示:以2020东京奥运会热点新闻亚洲飞人"苏炳添”为例,用户期望查看有关“苏炳添”的新闻,同时期望查看相同标题的相似文章列表。

image.png

标题:如“9秒98!苏炳添百米决赛第六!铭记这个历史瞬间!",隶属:新闻的标题。


相似文章数:如 26,需要借助:实时聚合实现。


翻页:向后翻页或随机翻页。


显然,传统的from + size 分页检索不支持聚合后分页,已不能满足需求。


在【Elasticsearch聚合后分页深入详解】博文中,我探讨过聚合后分页查询的实现,核心方法是:需要借助程序自己实现。


那是 2018 年的博文,3.5 年后的 2021年,有没有新的实现方式呢?


2、聚合后分页新的实现

实际在 Elasticsearch 6.1 版本(2017年12月13日 发布)就推出了:Composite 聚合方式,能实现聚合后分页查询。


2.0 认知前提——单桶聚合&多桶聚合

一图胜千言。以如下图示,代表聚合之前的原始数据,无需过多解释,大家一看就明白。

image.png

name:product_0*: 产品名称;


color:颜色;


pt:发布时间;


brand:品牌;


price:价格。


数据建模如下:


PUT my-products

{

 "mappings": {

   "properties": {

     "brand": {

       "type": "keyword"

     },

     "pt": {

       "type": "date"

     },

     "name": {

       "type": "keyword"

     },

     "color": {

       "type": "keyword"

     },

     "price":{

       "type":"integer"

     }

   }

 }

}

批量写入数据如下:


PUT my-products/_bulk

{"index":{"_id":1}}

{"brand":"nike","pt":"2021-01-01","name":"product_01","color":"red","price":600}

{"index":{"_id":2}}

{"brand":"grke","pt":"2021-02-01","name":"product_02","color":"red","price":200}

{"index":{"_id":3}}

{"brand":"lining","pt":"2021-03-01","name":"product_03","color":"green","price":300}

{"index":{"_id":4}}

{"brand":"lining","pt":"2021-02-01","name":"product_04","color":"green","price":450}

{"index":{"_id":5}}

{"brand":"grke","pt":"2021-04-01","name":"product_05","color":"blue","price":180}

{"index":{"_id":6}}

{"brand":"grke","pt":"2021-02-01","name":"product_06","color":"yellow","price":165}

{"index":{"_id":7}}

{"brand":"grke","pt":"2021-02-01","name":"product_07","color":"yellow":"price":190}

{"index":{"_id":8}}

{"brand":"lining","pt":"2021-04-01","name":"product_08","color":"blue","price":500}

{"index":{"_id":9}}

{"brand":"nike","pt":"2021-01-01","name":"product_09","color":"blue","price":1000}

2.0.1 单桶聚合

terms 单桶聚合结果如下:


以品牌类别聚合

image.png

实现如下:


POST my-products/_search

{

 "size": 0,

 "aggs": {

   "brand_terms": {

     "terms": {

       "field": "brand",

       "size": 10

     }

   }

 }

}

按照颜色、日期实现方式一致,不再赘述。


以颜色聚合

image.png

  • 以日期聚合

image.png

2.0.2 多桶聚合

Elastic search 支持 multi-terms 多桶聚合。


multi-terms 是 terms 聚合的引申,terms 支持 单个关键字的聚合,而multi-terms 顾名思义——多个关键字的聚合。


举例:multi-terms 按照品牌、颜色两个桶聚合如下:

image.png

多桶聚合实现如下:


GET my-products/_search

{

 "size":0,

 "aggs": {

   "brands_and_colors_aggs": {

     "multi_terms": {

       "terms": [

         {

           "field": "brand"

         },

         {

           "field": "color"

         }

       ]

     }

   }

 }

}

多桶聚合返回结果如下:

image.png

这时候,不免会有问题,如果想按照品牌和价格区间(histogram)或日期区间(date_histogram) 实现聚合统计分析,该如何实现呢?


显然,multi-terms 聚合只支持:多个 terms 聚合操作,是不能满足需求的。


而,Composite 组合聚合应运而生,巧妙的解决了如上组合聚合问题。


2.1 Composite 聚合介绍

2.1.1 Composite 聚合定义

Composite 是个六级词汇,含义:并合的,复合的,混成的,合成的,集成的。


Composite 聚合是一种多桶聚合,可从不同来源创建复合桶。


具体哪些不同源呢?主要支持的聚合方式如下:


Terms 特定关键字聚合


Histogram 区间聚合


Date histogram 日期区间聚合


GeoTile grid Geo地理位置聚合


与其他多桶聚合不同,使用 Composite 聚合有效地对多级聚合( multi-level )中的所有桶进行分页。Composite 聚合提供了一种流式传输特定聚合的所有桶的方法,类似于Scroll 检索(滚动检索,适用于全量查询数据的业务场景)的实现。


关于Scroll 检索推荐阅读:


干货 | 全方位深度解读 Elasticsearch 分页查询


Composite 聚合是根据为每个文档提取/创建的值的组合构建的,每个组合都被视为一个复合桶(2.1.3 会详细举例什么是复合桶)。


2.1.2 Composite 聚合的核心功能

Composite 聚合较其他聚合的核心不同点如下:


支持多类型组合桶聚合。打破传统多桶单类型聚合的壁垒,支持:Terms、Histogram、Data histogram、GeoTile grid Geo 聚合。


支持聚合后分页。类似:scroll 检索的,仅支持向后翻页,不支持随机翻页。


2.1.3 Composite 聚合语法

Composite 语法参考如下:


GET my-products/_search

{

 "size": 0,

 "aggs": {

   "my_buckets": {

     "composite": {

       "size": 5,

       "sources": [

         {

           "brand_terms": {

             "terms": {

               "field": "brand",

               "order": "asc"

             }

           }

         },

         {

           "prices_histogram": {

             "histogram": {

               "field": "price",

               "interval": 50,

               "order": "asc"

             }

           }

         }

       ],

       "after": {

         "brand_terms": "lining",

         "prices_histogram": 500

       }

     }

   }

 }

}

sources:指定组合分桶里各个分桶检索语句,可以是一个或者多个(中括弧里面包含多个大括弧子分桶聚合语句)。


size:每次返回的结果数。


after:翻页使用,每一次检索都会有一个:“after_key”键值对组合,供下次检索使用。


复合桶:{ "brand_terms": "lining",  "prices_histogram": 500 } 实则为:品牌和价格区间两者组成的复合桶。


order:分桶内的排序方式。


3、Composite 聚合后分页实战演练

有了上面的分析,再来看Composite 聚合会非常轻松。


拿 2.0 小节的建模数据为示例。


假定需要实现:基于时间区间间隔一个月为单位,且基于品牌名称两个组合桶聚合,然后各个组合桶内实现聚合统计各个组合桶的平均价格。


拆解如下:


第一:组合桶。


分桶一:data_histogram 实现按照发布时间间隔周期(指定为1个月)的聚合。


分桶二:terms 品牌聚合。


第二:基于组合桶实现各个组合桶平均价格的统计。


通过组合指标聚合 avg aggregation 实现组合桶内求平均值的子聚合效果。


GET my-products/_search

{

 "size": 0,

 "aggs": {

   "my_buckets": {

     "composite": {

       "size":5,

       "sources": [

         {

           "date": {

             "date_histogram": {

               "field": "pt",

               "calendar_interval": "1m",

               "order": "desc",

               "time_zone": "Asia/Shanghai"

             }

           }

         },

         {

           "product": {

             "terms": {

               "field": "brand"

             }

           }

         }

       ]

     },

     "aggregations": {

       "the_avg": {

         "avg": {

           "field": "price"

         }

       }

     }

   }

 }

}

返回结果如下:

image.png

说好的聚合后分页呢?


就是在上面语句的后面,执行下一页翻页的时候,加上上一页返回的“after_key”值(对应如下代表标红:“after”部分)即可。


GET my-products/_search

{

 "size": 0,

 "aggs": {

   "my_buckets": {

     "composite": {

       "size": 5,

       "sources": [

         {

           "date": {

             "date_histogram": {

               "field": "pt",

               "calendar_interval": "1m",

               "order": "desc",

               "time_zone": "Asia/Shanghai"

             }

           }

         },

         {

           "product": {

             "terms": {

               "field": "brand"

             }

           }

         }

       ],

       "after": {

         "date": 1612137600000,

         "product": "lining"

       }

     },

     "aggregations": {

       "the_avg": {

         "avg": {

           "field": "price"

         }

       }

     }

   }

 }

}

在生产环境只需要将上述内容拼成java 或者 python 代码,实现向后翻页。


4、Composite 聚合注意事项

Composite 聚合仅能实现向后翻页,不支持随机翻页。


Composite 聚合目前与管道(pipeline)聚合(基于聚合结果的子聚合方式)不兼容,在大多数情况下也没有意义(会导致结果不准确)。


5、小结

本文重点讲述了聚合后分页的新实现方式——Composite 聚合,说新其实是较6.1 版本之前的自己实现的方式而言。


Composite 聚合的两大核心特点:组合桶(支持四种类型)聚合、聚合后分页。


您的实战环节有用到聚合后分页吗?如何实现的呢?欢迎留言交流细节。


参考

1. https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-multi-terms-aggregation.html


2. https://github.com/elastic/elasticsearch/pull/26800


3. https://ramyav.medium.com/composite-aggregation-using-java-api-38882cabc886

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
7月前
|
存储 搜索推荐 Java
|
1月前
|
存储 SQL 监控
|
2月前
|
缓存 关系型数据库 API
京东面试题:ElasticSearch深度分页解决方案!
京东面试题:ElasticSearch深度分页解决方案!
|
3月前
|
存储 自然语言处理 关系型数据库
ElasticSearch基础3——聚合、补全、集群。黑马旅游检索高亮+自定义分词器+自动补全+前后端消息同步
聚合、补全、RabbitMQ消息同步、集群、脑裂问题、集群分布式存储、黑马旅游实现过滤和搜索补全功能
ElasticSearch基础3——聚合、补全、集群。黑马旅游检索高亮+自定义分词器+自动补全+前后端消息同步
|
4月前
|
自然语言处理 Java 关系型数据库
ElasticSearch 实现分词全文检索 - 聚合查询 cardinality
ElasticSearch 实现分词全文检索 - 聚合查询 cardinality
148 1
|
5月前
|
数据库
面试题ES问题之Elasticsearch的排序分页和高亮功能如何解决
面试题ES问题之Elasticsearch的排序分页和高亮功能如何解决
44 0
|
6月前
|
SQL 安全 数据挖掘
Elasticsearch如何聚合查询多个统计值,如何嵌套聚合?并相互引用,统计索引中某一个字段的空值率?语法是怎么样的?
Elasticsearch聚合查询用于复杂数据分析,包括统计空值率。示例展示了如何计算字段`my_field`非空非零文档的百分比。查询分为三步:总文档数计数、符合条件文档数计数及计算百分比。聚合概念涵盖度量、桶和管道聚合。脚本在聚合中用于动态计算。常见聚合类型如`sum`、`avg`、`date_histogram`等。组合使用可实现多值统计、嵌套聚合和空值率计算。[阅读更多](https://zhangfeidezhu.com/?p=515)
301 0
Elasticsearch如何聚合查询多个统计值,如何嵌套聚合?并相互引用,统计索引中某一个字段的空值率?语法是怎么样的?
|
6月前
|
存储 缓存 自然语言处理
elasticsearch 聚合 : 指标聚合、桶聚合、管道聚合解析使用总结
elasticsearch 聚合 : 指标聚合、桶聚合、管道聚合解析使用总结
|
6月前
|
存储 数据库 开发者
Elasticsearch中的三种分页策略深度解析:原理、使用及对比
Elasticsearch中的三种分页策略深度解析:原理、使用及对比
|
6月前
|
缓存 Java API
在生产环境中部署Elasticsearch:最佳实践和故障排除技巧——聚合与搜索(三)
在生产环境中部署Elasticsearch:最佳实践和故障排除技巧——聚合与搜索(三)