【ELK】(四)Elasticsearch 聚合查询与多维度数据统计

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 【ELK】(四)Elasticsearch 聚合查询与多维度数据统计

文章目录


搜索

聚合

高阶概念


搜索


即从一个索引下按照特定的字段或关键词搜索出符合用户预期的一个或者一堆cocument,然后根据文档的相关度得分,在返回的结果集里并根据得分对这些文档进行一定的排序。


聚合


根据业务需求,对文档中的某个或某几个字段进行数据的分组并做一些指标数据的统计分析,比如要计算一批文档中某个业务字段的总数,平均数,最大最小值等,都属于聚合的范畴。


以上两个概念后是理解下面实验的基础,如果是传统关系数据库mysql、oracle等存储的数据,也可以搜索和聚合,但是在数据聚合分析一块,毕竟不是它们的强项,而且需要在程序中做大量的处理,耗时费力,尤其是大数据量的情况下就有些力不从心了。


但在es中,由于内置了聚合统计的相关功能,只需要使用好它的语法即可达到几近实时的聚合统计,和搜索花费时间基本上没有太大差别,因此使用es很适合在数据量大的业务场景下做聚合统计与分析。


高阶概念


  • Buckets(桶/集合):满足特定条件的文档的集合
  • Metrics(指标):对桶内的文档进行统计计算(例如最小值,求和,最大值等)


在聚合统计分析中,使用很频繁的一个名词叫 aggs,它是聚合的关键词之一,下面就用实验来演示一下使用aggs进行数据聚合的多种场景。


1、实验准备数据,首先往es整合批量插入一些实验数据,这里我们以一个家电卖场的电视为背景进行模拟


设定文档中field的相关分词属性。

PUT http://192.168.56.235:9201/demo2
{
  "setting":{
  "index":{
    "number_of_shards":5,
    "number_of_replicats":1
  }
  },
  "mappings":{
  "sales":{
    "properties":{
    "price":{
      "type":"long"
    },
    "color":{
      "type":"keyword"
    },
    "brand":{
      "type":"keyword"
    },
    "sold_date":{
      "type":"date"
    }
    }
  }
  }
}


2、批量插入数据

POST http://192.168.56.235:9201/demo2/sales
{ "price" : 1000, "color" : "红色", "brand" : "长虹", "sold_date" : "2016-10-28" }
{ "price" : 2000, "color" : "红色", "brand" : "长虹", "sold_date" : "2016-11-05" }
{ "price" : 3000, "color" : "绿色", "brand" : "小米", "sold_date" : "2017-05-18" }
{ "price" : 1500, "color" : "蓝色", "brand" : "TCL", "sold_date" : "2017-07-02" }
{ "price" : 1200, "color" : "绿色", "brand" : "TCL", "sold_date" : "2018-08-19" }
{ "price" : 2000, "color" : "红色", "brand" : "长虹", "sold_date" : "2017-11-05" }
{ "price" : 8000, "color" : "红色", "brand" : "三星", "sold_date" : "2017-01-01" }
{ "price" : 2500, "color" : "蓝色", "brand" : "小米", "sold_date" : "2018-02-12" }

image.png


数据准备完毕


image.png


2、按照颜色分组统计各种颜色电视的数量


查询语法如下:

{
  "size":0,
  "aggs":{
  "group_color":{
    "terms":{
    "field":"color"
    },
    "aggs":{
    "avg_color_price":{
      "avg":{
      "field":"price"
      }
    }
    }
  }
  }
}


查询结果如下,这里简单对其中的几个参数和结果名称做一下说明。


在查询语句中:


  • size:0表示聚合查询的结果不需要返回中间的文档内容,
  • group_color 我们自定义的分组名字,最好是见名知意的


在返回结果中:


  • hits:{},这部分存放的是返回结果的基本统计结果,如果上面的size制指定了不为0,文档内容则会放在这个里面
  • buckets:存放聚合后的统计结果详细信息,以key-value的形式展现


image.png

image.png

3、按照颜色分组统计各种颜色电视的数量,并在此基础上,统计出各种颜色电视的平均价格


分析:


按照color去分bucket,可以拿到每个color bucket中的数量,这个仅仅只是一个bucket操作, doc_count其实只是es的bucket操作默认执行的一个内置metric。


在一个aggs执行的bucket操作(terms),平级的json结构下,再加一个aggs,这个第二个aggs内部,同样取个名字,执行一个metric操作,avg,对之前的每个bucket中的数据的指定的field、price

field,求一个平均值


就是一个metric,就是一个对一个bucket分组操作之后,对每个bucket都要执行的一个metric,也可以理解成功嵌套聚合,在es中获取到某个指标的数据后,继续对这个指标的数据进行其他聚合分析也被叫做下钻


该需求查询语句如下:

{
  "size":0,
  "aggs":{
  "group_color":{
    "terms":{
    "field":"color"
    },
    "aggs":{
    "avg_color_price":{
      "avg":{
      "field":"price"
      }
    }
    }
  }
  }
}


返回结果如下,通过结果可以很清晰的看出来,在颜色统计分析的基础上,每一个{}里面还增加了一个指标,即自定义的计算平均值的avg_color_price,这个查询几乎是毫秒级的,基本没有延迟,如果转化为sql查询应该是这样的:

select avg(price) from tvs.sales group by color

image.png


4、根据颜色分组,求出每种颜色的电视价格的最大值,最小值,平均值

{
  "size":0,
  "aggs":{
  "group_by_color":{
    "terms":{
    "field":"color"
    },
    "aggs":{
    "max_price":{
      "max":{
      "field":"price"
      }
    },
    "min_price":{
      "min":{
      "field":"price"
      }
    },
    "avg_price":{
      "avg":{
      "field":"price"
      }
    }
    }
  }
  }
}


所得结果如下:

{
    "took": 4,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 7,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "group_by_color": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
                {
                    "key": "红色",
                    "doc_count": 4,
                    "max_price": {
                        "value": 8000
                    },
                    "min_price": {
                        "value": 1000
                    },
                    "avg_price": {
                        "value": 3250
                    }
                },
                {
                    "key": "蓝色",
                    "doc_count": 2,
                    "max_price": {
                        "value": 2500
                    },
                    "min_price": {
                        "value": 1500
                    },
                    "avg_price": {
                        "value": 2000
                    }
                },
                {
                    "key": "绿色",
                    "doc_count": 1,
                    "max_price": {
                        "value": 1200
                    },
                    "min_price": {
                        "value": 1200
                    },
                    "avg_price": {
                        "value": 1200
                    }
                }
            ]
        }
    }
}


/


5、按照不同的价格区间对电视进行划分,并求出每个价格区间的电视的平均价格


在es中根据区间间隔划分,有一个叫做 histogram的语法可以帮助我们执行,类似于terms,也是进行bucket分组操作,接收一个field,按照这个field的值的各个范围区间,进行bucket分组操作。

“histogram”:{
  “field”: “price”,
  “interval”: 2000
},


  • interval:2000,划分范围,0 ~ 2000,2000 ~ 4000,4000 ~ 6000,6000 ~ 8000,8000 ~ 10000,buckets
  • 根据price的值,比如2500,看落在哪个区间内,比如2000 ~ 4000,此时就会将这条数据放入2000 ~ 4000对应的那个bucket中
  • bucket划分的方法terms,将field值相同的数据划分到一个bucket中
  • bucket有了之后,一样的,去对每个bucket执行avg,count,sum,max,min,等各种metric操作,聚合分析
{
  "size":0,
  "aggs":{
  "interval_price":{
    "histogram":{
    "field":"price",
    "interval":2000
    },
    "aggs":{
      "revenue":{
      "avg":{
      "field":"price"
      }
    }
    }
  }
  } 
}


查询的结果如下:可以看到,按照2000一个等级将所有电视的价格划分在不同的区间了,并将每个区间的价格平均值统计了出来

{
    "took": 7,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 7,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "interval_price": {
            "buckets": [
                {
                    "key": 0,
                    "doc_count": 3,
                    "revenue": {
                        "value": 1233.3333333333333
                    }
                },
                {
                    "key": 2000,
                    "doc_count": 3,
                    "revenue": {
                        "value": 2166.6666666666665
                    }
                },
                {
                    "key": 4000,
                    "doc_count": 0,
                    "revenue": {
                        "value": null
                    }
                },
                {
                    "key": 6000,
                    "doc_count": 0,
                    "revenue": {
                        "value": null
                    }
                },
                {
                    "key": 8000,
                    "doc_count": 1,
                    "revenue": {
                        "value": 8000
                    }
                }
            ]
        }
    }
}


6、按照不同的时间区间对电视进行划分,并求出每个价格区间的电视的平均价格


date histogram,按照我们指定的某个date类型的日期field,以及日期interval,按照一定的日期间隔,去划分bucket,这个概念的理解和上一个有点类似,可以对照理解。


date interval = 1 month

2017-01-01~2017-01-31,就是一个bucket

2017-02-01~2017-02-28,就是一个bucket


然后会去扫描每个数据的date field,判断date落在哪个bucket中,就将其放入那个bucket

2017-01-05,就将其放入2017-01-01~2017-01-31,就是一个bucket


min_doc_count:即使某个日期interval,2017-01-01~2017-01-31中,一条数据都没有,那么这个区间也是要返回的,不然默认是会过滤掉这个区间的

extended_bounds,min,max:划分bucket的时候,会限定在这个起始日期,和截止日期内


根据上述分析我们构建查询语句

{
  "size":0,
  "aggs":{
  "sales":{
    "date_histogram":{
    "field":"sold_date",
    "interval":"month",
    "format":"yyyy-MM-dd",
    "min_doc_count":0,
    "extended_bounds":{
      "min":"2017-01-01",
      "max":"2018-12-31"
    }
    }
  }
  }
}


返回结果如下,按照月份,将指定区间内各个月份的数量做了统计


image.png


当然,如果我们觉得按照月份统计粒度太细,也可以根据季度对数据进行统计,只需要将month换成quarter即可,查询语法如下:

{
  "size":0,
  "aggs":{
  "sales":{
    "date_histogram":{
    "field":"sold_date",
    "interval":"quarter",
    "format":"yyyy-MM-dd",
    "min_doc_count":0,
    "extended_bounds":{
      "min":"2017-01-01",
      "max":"2018-12-31"
    }
    }
  }
  }
}


查询结果如下:

image.png

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
目录
相关文章
|
3天前
|
存储 搜索推荐 Java
|
3天前
|
存储 固态存储 Java
Elasticsearch中查询性能优化
Elasticsearch中查询性能优化
198 0
|
3天前
|
存储 SQL 运维
Elasticsearch 查询革新:探索 Wildcard 类型的高效模糊匹配策略
Elasticsearch 查询革新:探索 Wildcard 类型的高效模糊匹配策略
23 0
|
3天前
|
运维 测试技术 数据处理
Elasticsearch 优化查询中获取字段内容的方式,性能提升5倍!
Elasticsearch 优化查询中获取字段内容的方式,性能提升5倍!
18 0
|
3天前
|
存储 缓存 Java
Elasticsearch 8.X 聚合查询下的精度问题及其解决方案
Elasticsearch 8.X 聚合查询下的精度问题及其解决方案
17 0
|
3天前
|
自然语言处理 Java 索引
SpringBoot 实现 elasticsearch 查询操作(RestHighLevelClient 的案例实战)
SpringBoot 实现 elasticsearch 查询操作(RestHighLevelClient 的案例实战)
25 1
|
3天前
|
缓存 算法 索引
【Elasticsearch专栏 07】深入探索:Elasticsearch的倒排索引如何进行模糊查询和通配符查询
Elasticsearch的倒排索引支持模糊查询和通配符查询,通过特定的算法和数据结构,能够实现对关键词的模糊匹配和通配符匹配。这两种查询类型提供了更灵活的搜索功能,但可能影响查询性能,需结合优化策略使用。
|
3天前
|
存储 SQL Java
聚合在Elasticsearch中的使用及示例验证
聚合在Elasticsearch中的使用及示例验证
73 0
|
3天前
|
缓存 自然语言处理 数据挖掘
一篇文章让你学会Elasticsearch中的查询
一篇文章让你学会Elasticsearch中的查询
137347 118
|
3天前
|
Java Maven 开发工具
【ElasticSearch 】IK 分词器安装
【ElasticSearch 】IK 分词器安装
24 1

热门文章

最新文章