ElasticSearch聚合分析

聚合用于分析查询结果集的统计指标,我们以观看日志分析为例,介绍各种常用的ElasticSearch聚合操作。

目录:

  • 查询用户观看视频数和观看时长
  • 聚合分页器
  • 查询视频uv
    • 单个视频uv
    • 批量查询视频uv
  • Having查询
    • 根据 count 进行过滤
    • 根据其它指标进行过滤

首先展示一下我们要分析的文档结构:

{
    "video_id": 1289643545120062253, // 视频id
    "video_uid": 3931482202390368051, // 视频发布者id
    "uid": 47381776787453866, // 观看用户id
    "time": 1533891263224, // 时间发生时间
    "watch_duration": 30 // 观看时长
}

每个文档记录了一个观看事件,我们通过聚合分析用户的观看行为。

ElasticSearch引入了两个相关概念:

  • 桶(Buckets): 满足特定条件的文档的集合
  • 指标(Metrics): 桶中文档的统计值,如特定字段的平均值

查询用户观看视频数和观看时长

首先用sql语句描述这个查询:

SELECT uid, count(*) as view_count, avg(watch_duration) as avg_duration
FROM view_log
WHERE time >= #{since} AND time <= #{to}
GROUP BY uid;
GET /view_log/_search
{
   "size" : 0,
   "query": {
       "range": {
           "time": {
               "gte": 0, // since
               "lte": 0 // to
           }
       }
   },
   "aggs": {
      "agg": { // agg为聚合的名称
        "terms": { // 聚合的条件为 uid 相同
          "field": "uid"
        },
        "aggs": { // 添加统计指标(Metrics)
          "avg_duration": {
              "avg": { // 统计 watch_duration 的平均值
                "field": "watch_duration"
              }
          }
        }
      }
   }
}

response:

{
  "took": 10,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 100000,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "agg": {
      "buckets": [
        {
          "key": 21836334489858688,
          "doc_count": 4026,
          "avg_duration": {
            "value": 12778.882352941177
          }
        },
        {
          "key": 31489302390368051,
          "doc_count": 2717,
          "avg_duration": {
            "value": 2652.5714285714284
          }
        }
      ]
    }
}

result.aggregations.agg.buckets列表中包含了查询的结果。

因为我们按照terms:uid进行聚合,每个bucket为uid相同的文档集合,key字段即为uid。

doc_count 字段表明bucket中文档的数目即sql语句中的count(*) as view_count

avg_duration.value 表示 watch_duration 的平均值即该用户的平均观看时长。

聚合分页器

在实际应用中用户的数量非常惊人, 不可能通过一次查询得到全部结果因此我们需要分页器分批取回:

GET /view_log/_search
{
   "size" : 0,
   "query": {
       "range": {
           "time": {
               "gte": 0, // since
               "lte": 0 // to
           }
       }
   },
   "aggs": {
      "agg": {
        "terms": {
            "field": "uid",
            "size": 10000, // bucket 的最大个数
            "include": { // 将聚合结果分为10页,序号为[0,9], 取第一页
                "partition": 0,
                "num_partitions": 10
            }
        },
        "aggs": {
          "avg_duration": {
              "avg": {
                "field": "watch_duration"
              }
          }
        }
      }
   }
}

上述查询与上节的查询几乎完全相同,只是在aggs.agg.terms字段中添加了include字段进行分页。

查询视频uv

单个视频uv

uv是指观看一个视频的用户数(user view),与此相对没有按照用户去重的观看数称为pv(page view)。

用SQL语句来描述:

SELECT video_id, count(*) as pv, count(distinct uid) as uv
FROM view_log
WHERE video_id = #{video_id};

ElasticSearch可以方便的进行count(distinct)查询:

GET /view_log/_search
{
    "aggs": {
      "uv": {
        "cardinality": {
          "field": "uid"
        }
      }
   }
}

response:

{
  "took": 255,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 17579,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "uv": {
      "value": 11
    }
  }
}

批量查询视频uv

ElasticSearch也可以批量查询count(distinct), 先用SQL进行描述:

SELECT video_id, count(*) as pv, count(distinct uid) as uv
FROM view_log
GROUP BY video_id;

查询:

GET /view_log/_search
{
    "size": 0,
    "aggs": {
      "video": {
        "terms": {
          "field": "video_id"
        },
        "aggs": {
          "uv": {
              "cardinality": {
                "field": "uid"
              }
          }
        }
      }
   }
}

response:

{
  "took": 313,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 16940,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "video": {
      "buckets": [
        {
          "key": 25417499722062, // 视频id
          "doc_count": 427, // 视频观看次数 pv
          "uv": {
            "value": 124 // 观看视频的用户数 uv
          }
        },
        {
          "key": 72446898144,
          "doc_count": 744,
          "uv": {
            "value":233
          }
        }
      ]
    }
  }
}

Having查询

SQL可以使用HAVING语句根据聚合结果进行过滤,ElasticSearch可以使用pipeline aggregations达到此效果不过语法较为繁琐。

根据 count 进行过滤

使用SQL查询观看超过200次的视频:

SELECT video_id, count(*) as view_count
FROM view_log
GROUP BY video_id
HAVING count(*) > 200;
GET /view_log/_search
{
  "size": 0,
  "aggs": {
    "view_count": {
      "terms": {
        "field": "video_id"
      },
      "aggs": {
        "having": {
          "bucket_selector": {
            "buckets_path": { // 选择 view_count 聚合的 doc_count 进行过滤
              "view_count": "_count"
            },
            "script": {
              "source": "params.view_count > 200"
            }
          }
        }
      }
    }
  }
}

response:

{
  "took": 83,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 775,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "view_count": {
      "buckets": [
        {
          "key": 35025417499764062,
          "doc_count": 529
        },
        {
          "key": 19913672446898144,
          "doc_count": 759
        }
      ]
    }
  }
}

ElasticSearch实现类似HAVING查询的关键在于使用[bucket_selector]选择聚合结果进行过滤。

根据其它指标进行过滤

接下来我们尝试查询平均观看时长大于5分钟的视频, 用SQL描述该查询:

SELECT video_id FROM view_log
GROUP BY video_id
HAVING avg(watch_duration) > 300;
GET /view_log/_search
{
  "size": 0,
  "aggs": {
    "video": {
      "terms": {
        "field": "video_id"
      },
      "aggs": {
        "avg_duration": {
          "avg": {
            "field": "watch_duration"
          }
        },
        "avg_duration_filter": {
          "bucket_selector": {
            "buckets_path": {
              "avg_duration": "avg_duration"
              },
              "script": {
                "source": "params.avg_duration > 200"
              }
          }
        }
      }
    }
  }
}

response:

{
  "took": 137,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 255,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "video": {
      "buckets": [
        {
          "key": 5417499764062,
          "doc_count": 91576,
          "avg_duration": {
            "value": 103
          }
        },
        {
          "key": 19913672446898144,
          "doc_count": 15771,
          "avg_duration": {
            "value": 197
          }
        }
      ]
    }
  }
}

原文地址:https://www.cnblogs.com/Finley/p/9499534.html

时间: 2024-08-04 03:25:03

ElasticSearch聚合分析的相关文章

ElasticSearch聚合分析API——非常详细,如果要全面了解的话,最好看这个

转自:http://www.tianyiqingci.com/2016/04/11/esaggsapi/ 前言 说完了ES的索引与检索,接着再介绍一个ES高级功能API – 聚合(Aggregations),聚合功能为ES注入了统计分析的血统,使用户在面对大数据提取统计指标时变得游刃有余.同样的工作,你在hadoop中可能需要写mapreduce或hive,在mongo中你必须得用大段的mapreduce脚本,而在ES中仅仅调用一个API就能实现了. 开始之前,提醒老司机们注意,ES原有的聚合功

Elasticsearch 之聚合分析入门

本文主要介绍 Elasticsearch 的聚合功能,介绍什么是 Bucket 和 Metric 聚合,以及如何实现嵌套的聚合. 首先来看下聚合(Aggregation): 什么是 Aggregation? 首先举一个生活中的例子,这个是京东的搜索界面,在搜索框中输入"华为"进行搜索,就会得到如上界面,搜索框就是我们常用的搜索功能,而下面这些,比如分类.热点.操作系统.CPU 类型等是根据 ES 的聚合分析获得的相关结果. 看完上面这个例子,下面来看下聚合的定义: ES 除了搜索以外,

elasticsearch系列六:聚合分析(聚合分析简介、指标聚合、桶聚合)

一.聚合分析简介 1. ES聚合分析是什么? 聚合分析是数据库中重要的功能特性,完成对一个查询的数据集中数据的聚合计算,如:找出某字段(或计算表达式的结果)的最大值.最小值,计算和.平均值等.ES作为搜索引擎兼数据库,同样提供了强大的聚合分析能力. 对一个数据集求最大.最小.和.平均值等指标的聚合,在ES中称为指标聚合   metric 而关系型数据库中除了有聚合函数外,还可以对查询出的数据进行分组group by,再在组上进行指标聚合.在 ES 中group by 称为分桶,桶聚合 bucke

ElasticStack学习(八):ElasticSearch索引模板与聚合分析初探

一.Index Template与Dynamic Template的概念 1.Index Template:它是用来根据提前设定的Mappings和Settings,并按照一定的规则,自动匹配到新创建的索引上. 1)模板仅是一个索引被创建时才会起作用,修改模板并不会影响已创建的索引: 2)可以设定多个索引模板,这些设置会被merge在一起: 3)通过指定order的数值,控制merge的过程: 2.Index Template的工作方式如下: 当一个索引被创建时,会执行如下操作: 1)应用Ela

Elasticsearch系列---常见搜索方式与聚合分析

概要 本篇主要介绍常见的6种搜索方式.聚合分析语法,基本是上机实战,可以和关系型数据库作对比,如果之前了解关系型数据库,那本篇只需要了解搜索和聚合的语法规则就可以了. 搜索响应报文 以上篇建立的music索引为例,我们先看看搜索结果的属性都有哪些 { "took": 1, "timed_out": false, "_shards": { "total": 5, "successful": 5, "

Elasticsearch学习之深入聚合分析1--基本概念

首先明白两个核心概念:bucket和metric 1. bucket:一个数据分组 1 city name 2 3 北京 小李 4 北京 小王 5 上海 小张 6 上海 小丽 7 上海 小陈 基于city划分buckets,划分出来两个bucket,一个是北京bucket,一个是上海bucket 北京bucket:包含了2个人,小李,小王上海bucket:包含了3个人,小张,小丽,小陈 按照某个字段进行bucket划分,那个字段的值相同的那些数据,就会被划分到一个bucket中,有一些mysql

Elasticsearch学习之深入聚合分析二---案例实战

以一个家电卖场中的电视销售数据为背景,来对各种品牌,各种颜色的电视的销量和销售额,进行各种各样角度的分析,首先建立电视销售的索引,然后 添加几条销售记录 PUT /tvs { "mappings": { "sales": { "properties": { "price": { "type": "long" }, "color": { "type"

Elasticsearch学习之深入聚合分析三---案例实战

1. 统计指定品牌下每个颜色的销量 任何的聚合,都必须在搜索出来的结果数据中进行,搜索结果,就是聚合分析操作的scope GET /tvs/sales/_search { "size": 0, "query": { "term": { "brand": { "value": "小米" } } }, "aggs": { "group_by_color"

Elasticsearch学习之深入聚合分析四---案例实战

1. 需求:比如有一个网站,记录下了每次请求的访问的耗时,需要统计tp50,tp90,tp99 tp50:50%的请求的耗时最长在多长时间tp90:90%的请求的耗时最长在多长时间tp99:99%的请求的耗时最长在多长时间 PUT /website { "mappings": { "logs": { "properties": { "latency": { "type": "long"