1 普通聚合分析

1.1 直接聚合统计

(1) 计算每个tag下的文档数量, 请求语法:

GET book_shop/it_book/_search
{
"size": 0, // 不显示命中(hits)的所有文档信息
"aggs": {
"group_by_tags": { // 聚合结果的名称, 需要自定义(复制时请去掉此注释)
"terms": {
"field": "tags"
}
}
}
}

(2) 发生错误:

说明: 索引book_shop的mapping映射是ES自动创建的, 它把tag解析成了text类型, 在发起对tag的聚合请求后, 将抛出如下错误:

{
"error": {
"root_cause": [
{
"type": "illegal_argument_exception",
"reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [tags] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead."
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"phase": "query",
"grouped": true,
"failed_shards": [......]
},
"status": 400
}

(3) 错误分析:

错误信息: Set fielddata=true on [xxxx] ......

错误分析: 默认情况下, Elasticsearch 对 text 类型的字段(field)禁用了 fielddata;

text 类型的字段在创建索引时会进行分词处理, 而聚合操作必须基于字段的原始值进行分析;

所以如果要对 text 类型的字段进行聚合操作, 就需要存储其原始值 —— 创建mapping时指定fielddata=true, 以便通过反转倒排索引(即正排索引)将索引数据加载至内存中.

(4) 解决方案一: 对text类型的字段开启fielddata属性:

  • 将要分组统计的text field(即tags)的fielddata设置为true:

    PUT book_shop/_mapping/it_book
    {
    "properties": {
    "tags": {
    "type": "text",
    "fielddata": true
    }
    }
    }
  • 可参考官方文档进行设置:

    https://www.elastic.co/guide/en/elasticsearch/reference/6.6/fielddata.html. 成功后的结果如下:

    {
    "acknowledged": true
    }
  • 再次统计, 得到的结果如下:

    {
    "took": 153,
    "timed_out": false,
    "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
    },
    "hits": {
    "total": 4,
    "max_score": 0.0,
    "hits": []
    },
    "aggregations": {
    "group_by_tags": {
    "doc_count_error_upper_bound": 0,
    "sum_other_doc_count": 6,
    "buckets": [
    {
    "key": "java",
    "doc_count": 3
    },
    {
    "key": "程",
    "doc_count": 2
    },
    ......
    ]
    }
    }
    }

(5) 解决方法二: 使用内置keyword字段:

  • 开启fielddata将占用大量的内存.

  • Elasticsearch 5.x 版本开始支持通过text的内置字段keyword作精确查询、聚合分析:

    GET shop/it_book/_search
    {
    "size": 0,
    "aggs": {
    "group_by_tags": {
    "terms": {
    "field": "tags.keyword" // 使用text类型的内置keyword字段
    }
    }
    }
    }

1.2 先检索, 再聚合

(1) 统计name中含有“jvm”的图书中每个tag的文档数量, 请求语法:

GET book_shop/it_book/_search
{
"query": {
"match": { "name": "jvm" }
},
"aggs": {
"group_by_tags": { // 聚合结果的名称, 需要自定义. 下面使用内置的keyword字段:
"terms": { "field": "tags.keyword" }
}
}
}

(2) 响应结果:

{
"took" : 7,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 0.64072424,
"hits" : [
{
"_index" : "book_shop",
"_type" : "it_book",
"_id" : "2",
"_score" : 0.64072424,
"_source" : {
"name" : "深入理解Java虚拟机:JVM高级特性与最佳实践",
"author" : "周志明",
"category" : "编程语言",
"desc" : "Java图书领域公认的经典著作",
"price" : 79.0,
"date" : "2013-10-01",
"publisher" : "机械工业出版社",
"tags" : [
"Java",
"虚拟机",
"最佳实践"
]
}
}
]
},
"aggregations" : {
"group_by_tags" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "Java",
"doc_count" : 1
},
{
"key" : "最佳实践",
"doc_count" : 1
},
{
"key" : "虚拟机",
"doc_count" : 1
}
]
}
}
}

1.3 扩展: fielddata和keyword的聚合比较

  • 为某个 text 类型的字段开启fielddata字段后, 聚合分析操作会对这个字段的所有分词分别进行聚合, 获得的结果大多数情况下并不符合我们的需求.

  • 使用keyword内置字段, 不会对相关的分词进行聚合, 结果可能更有用.

—— 推荐使用text类型字段的内置keyword进行聚合操作.

2 嵌套聚合

2.1 先分组, 再聚合统计

(1) 先按tags分组, 再计算每个tag下图书的平均价格, 请求语法:

GET book_shop/it_book/_search
{
"size": 0,
"aggs": {
"group_by_tags": {
"terms": { "field": "tags.keyword" },
"aggs": {
"avg_price": {
"avg": { "field": "price" }
}
}
}
}
}

(2) 响应结果:

  "hits" : {
"total" : 3,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"group_by_tags" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "Java",
"doc_count" : 3,
"avg_price" : {
"value" : 102.33333333333333
}
},
{
"key" : "编程语言",
"doc_count" : 2,
"avg_price" : {
"value" : 114.0
}
},
......
]
}
}

2.2 先分组, 再统计, 最后排序

(1) 计算每个tag下图书的平均价格, 再按平均价格降序排序, 查询语法:

GET book_shop/it_book/_search
{
"size": 0,
"aggs": {
"all_tags": {
"terms": {
"field": "tags.keyword",
"order": { "avg_price": "desc" } // 根据下述统计的结果排序
},
"aggs": {
"avg_price": {
"avg": { "field": "price" }
}
}
}
}
}

(2) 响应结果:

与#2.1节内容相似, 区别在于按照价格排序显示了.

2.3 先分组, 组内再分组, 然后统计、排序

(1) 先按价格区间分组, 组内再按tags分组, 计算每个tags组的平均价格, 查询语法:

GET book_shop/it_book/_search
{
"size": 0,
"aggs": {
"group_by_price": {
"range": {
"field": "price",
"ranges": [
{ "from": 00, "to": 100 },
{ "from": 100, "to": 150 }
]
},
"aggs": {
"group_by_tags": {
"terms": { "field": "tags.keyword" },
"aggs": {
"avg_price": {
"avg": { "field": "price" }
}
}
}
}
}
}
}

(2) 响应结果:

  "hits" : {
"total" : 3,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"group_by_price" : {
"buckets" : [
{
"key" : "0.0-100.0", // 区间0.0-100.0
"from" : 0.0,
"to" : 100.0,
"doc_count" : 1, // 共查找到了3条文档
"group_by_tags" : { // 对tags分组聚合
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "Java",
"doc_count" : 1,
"avg_price" : {
"value" : 79.0
}
},
......
]
}
},
{
"key" : "100.0-150.0",
"from" : 100.0,
"to" : 150.0,
"doc_count" : 2,
"group_by_tags" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "Java",
"doc_count" : 2,
"avg_price" : {
"value" : 114.0
}
},
......
}
]
}
}
]
}
}

版权声明

作者: 马瘦风(https://healchow.com)

出处: 博客园 马瘦风的博客(https://www.cnblogs.com/shoufeng)

感谢阅读, 如果文章有帮助或启发到你, 点个[好文要顶

ES 24 - 如何通过Elasticsearch进行聚合检索 (分组统计)的更多相关文章

  1. ES 21 - Elasticsearch的高级检索语法 (包括term、prefix、wildcard、fuzzy、boost等)

    目录 1 term query - 索引词检索 1.1 term query - 不分词检索 1.2 terms query - in检索 2 prefix query - 前缀检索 3 wildca ...

  2. ES 12 - 配置使用Elasticsearch的动态映射 (dynamic mapping)

    目录 1 动态映射(dynamic mapping) 1.1 什么是动态映射 1.2 体验动态映射 1.3 搜索结果不一致的原因分析 2 开启dynamic mapping策略 2.1 约束策略 2. ...

  3. Elasticsearch学习(4) spring boot整合Elasticsearch的聚合操作

    之前已将spring boot原生方式介绍了,接下将结介绍的是Elasticsearch聚合操作.聚合操作一般来说是解决一下复杂的业务,比如mysql中的求和和分组,由于博主踩的坑比较多,所以博客可能 ...

  4. Elasticsearch(8) --- 聚合查询(Metric聚合)

    Elasticsearch(8) --- 聚合查询(Metric聚合) 在Mysql中,我们可以获取一组数据的 最大值(Max).最小值(Min).同样我们能够对这组数据进行 分组(Group).那么 ...

  5. Elasticsearch(9) --- 聚合查询(Bucket聚合)

    Elasticsearch(9) --- 聚合查询(Bucket聚合) 上一篇讲了Elasticsearch聚合查询中的Metric聚合:Elasticsearch(8) --- 聚合查询(Metri ...

  6. Elasticsearch 之聚合分析入门

    本文主要介绍 Elasticsearch 的聚合功能,介绍什么是 Bucket 和 Metric 聚合,以及如何实现嵌套的聚合. 首先来看下聚合(Aggregation): 什么是 Aggregati ...

  7. Elasticsearch系列---聚合查询原理

    概要 本篇主要介绍聚合查询的内部原理,正排索引是如何建立的和优化的,fielddata的使用,最后简单介绍了聚合分析时如何选用深度优先和广度优先. 正排索引 聚合查询的内部原理是什么,Elastich ...

  8. (转)Elasticsearch分析聚合

    Elasticsearch不仅仅适合做全文检索,分析聚合功能也很好用.下面通过实例来学习. 一.准备数据 {"index":{ "_index": " ...

  9. 用 mongodb + elasticsearch 实现中文检索

      而 elasticsearch 可以很好的支持各种语言的全文检索,但我们暂时又不想切换到 elasticsearch 作为后端数据库. 当然,可以在 web 应用中存储数据的时候,再主动写一份到 ...

随机推荐

  1. 如何成长为一名合格的web架构师?

    写代码要经历下面几个阶段.  一 .你必须学习面向对象的基础知识,如果连这个都忘了,那你的编程之路注定是在做原始初级的重复! 很多程序员都知道类.方法.抽象类.接口等概念,但是为什么要面向对象,好处在 ...

  2. 【HDU - 2181】哈密顿绕行世界问题(dfs+回溯)

    -->哈密顿绕行世界问题 Descriptions: 一个规则的实心十二面体,它的 20个顶点标出世界著名的20个城市,你从一个城市出发经过每个城市刚好一次后回到出发的城市.  Input 前2 ...

  3. jquery Easy UI Datagrid(数据网格)学习心德,附API

    第一步,引入主要的css样式和js文件 <meta http-equiv="Content-Type" content="text/html; charset=ut ...

  4. 深入学习Spring框架(一)- 入门

    1.Spring是什么? Spring是一个JavaEE轻量级的一站式开发框架. JavaEE: 就是用于开发B/S的程序.(企业级) 轻量级:使用最少代码启动框架,然后根据你的需求选择,选择你喜欢的 ...

  5. django基础知识之验证码:

    验证码 在用户注册.登录页面,为了防止暴力请求,可以加入验证码功能,如果验证码错误,则不需要继续处理,可以减轻一些服务器的压力 使用验证码也是一种有效的防止crsf的方法 验证码效果如下图: 验证码视 ...

  6. scrapy基础知识之 Scrapy-Redis分布式策略:

    Scrapy-Redis分布式策略: 假设有四台电脑:Windows 10.Mac OS X.Ubuntu 16.04.CentOS 7.2,任意一台电脑都可以作为 Master端 或 Slaver端 ...

  7. 实战Spring4+ActiveMQ整合实现消息队列(生产者+消费者)

    引言: 最近公司做了一个以信息安全为主的项目,其中有一个业务需求就是,项目定时监控操作用户的行为,对于一些违规操作严重的行为,以发送邮件(ForMail)的形式进行邮件告警,可能是多人,也可能是一个人 ...

  8. flink window实例分析

    window是处理数据的核心.按需选择你需要的窗口类型后,它会将传入的原始数据流切分成多个buckets,所有计算都在window中进行. flink本身提供的实例程序TopSpeedWindowin ...

  9. ‎Cocos2d-x 3.x 学习笔记(三):Scheduler Timer 调度与定时

    ‎1. 概述 Cocos2d-x 的 Scheduler 离不开 Timer.Timer 类是定时器,用来规定一个回调函数应该在何时被触发.Timer 封装了已运行时间.重复次数.已执行次数.延迟秒数 ...

  10. 关于vue项目font字体图标库导入未显示的问题

    运行项目时,弹出以下信息: