ElasticSearch练习二:聚合语法学习(aggs、bucket、metric、hitogram、date hitogram)

  • Post author:
  • Post category:其他




bucket与metric两个核心概念

  1. 初始化数据
city name
北京 小李
北京 小王
上海 小张
上海 小丽
上海 小陈
  1. 按照某个字段进行bucket划分,那个字段的值相同的那些数据,就会被划分到一个bucket中、比如基于city划分buckets,划分出来两个bucket,一个是北京bucket,一个是上海bucket(类似于sql的group by city)

    1) 北京bucket:包含了2个人,小李,小王

    2)上海bucket:包含了3个人,小张,小丽,小陈

  2. 类比sql:select max(score) from student group by sex的分组聚合,首先第一步就是分组,第二步是对每个组内的数据进行聚合分析。分组对应的就是bucket;聚合对应的就是metric

    metric:对一个数据分组执行的统计

    当我们有了一堆bucket之后,就可以对每个bucket中的数据进行聚合分词了,比如说计算一个bucket内所有数据的数量,或者计算一个bucket内所有数据的平均值,最大值,最小值



准备练习数据

PUT /tvs
{
  "mappings": {
    "properties": {
      "price": {
        "type": "long"
      },
      "color": {
        "type": "keyword"
      },
      "brand": {
        "type": "keyword"
      },
      "sold_date": {
        "type": "date"
      }
    }
  }
}

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



统计哪种颜色电视销量最高

# 等价于select color,count(*) from tbl group by color
GET /tvs/_search
{
  "size": 0, 
  "aggs": {
    "什么颜色的电视销量最高": {
      "terms": {
        "field": "color"
      }
    }
  }
}
  • size:只获取聚合结果,而不要执行聚合的原始数据
  • aggs:固定语法,要对一份数据执行分组聚合操作
  • 什么颜色的电视销量最高:就是对每个aggs操作都要起一个名字,这个名字是随意的,取什么都ok
  • terms:根据字段的值进行分组
  • field:根据指定的字段的值进行分组

疑问:可不可以一次性对多个字段进行group by



统计每种颜色电视平均价格

GET /tvs/_search
{
  "size": 0,
  "aggs": {
    "每种的颜色电视": {
      "terms": {
        "field": "color"
      },
      "aggs": {
        "平均价格": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}
  • 按照color去分bucket,默认分完bucket后还会统计每个bucket中的文档个数,因为这是bucket操作默认执行的一个内置metric——doc_count。
  • 如果要自定义metric聚合操作,在一个aggs执行的bucket操作(terms)平级的json结构下再加一个aggs,这个第二个aggs内部,同样取个名字,执行一个metric操作,avg,对之前的每个bucket中的数据的指定的field,price field,求一个平均值

疑问:可不可以对不同的bucket执行不同的metric?



bucket嵌套实现颜色+品牌的多层下钻,分析平均价格

什么是下钻?

下钻:

基于当前的数据,在继续进行分组聚合操作

。比如说颜色的分组,然后还要继续对这个分组内的数据再分组,比如一个颜色内,还可以分成多个不同的品牌的组,最后对每个最小粒度的分组执行聚合分析操作,这就叫做下钻分析。

实现从颜色到品牌进行下钻分析:每种颜色的平均价格,以及找到每种颜色每个品牌的平均价格。

比如说,现在红色的电视有4台,同时这4台电视中,有3台是属于长虹的,1台是属于小米的

红色电视中的3台长虹的平均价格是多少?

红色电视中的1台小米的平均价格是多少?

es下钻分析,就要对bucket进行多层嵌套,多次分组

按照多个维度(颜色+品牌)多层下钻分析,而且学会了每个下钻维度(颜色,颜色+品牌),都可以对每个维度分别执行一次metric聚合操作

GET /tvs/_search
{
  "size": 0,
  "aggs": {
    "颜色": {
      "terms": {
        "field": "color"
      },
      "aggs": {
        "平均价格": {
          "avg": {
            "field": "price"
          }
        },
        "品牌": {
          "terms": {
            "field": "brand"
          },
          "aggs": {
            "平均价格": {
              "avg": {
                "field": "price"
              }
            }
          }
        }
      }
    },
    "最高价格": {
      "max": {
        "field": "price"
      }
    }
  }
}

总结:aggs里面只有分组条件和聚合条件,并且

一个aggs里最多只能有一个分组条件;但是可以有任意个聚合条件

。我们可以用aggs+分组条件嵌套aggs+分组条件,不断嵌套下去往下分组以实现下钻的功能。



统计每种颜色电视最大最小,总和价格

GET /tvs/_search
{
  "size": 0,
  "aggs": {
    "颜色": {
      "terms": {
        "field": "color"
      },
      "aggs": {
        "最高价格": {
          "max": {
            "field": "price"
          }
        },
        "最低价格": {
          "min": {
            "field": "price"
          }
        },
        "总和价格": {
          "sum": {
            "field": "price"
          }
        }
      }
    }
  }



histogram按价格区间统计电视销量和销售额

GET /tvs/_search
{
  "size": 0,
  "aggs": {
    "价格区间": {
      "histogram": {
        "field": "price",
        "interval": 2000
      },
      "aggs": {
        "销售额": {
          "sum": {
            "field": "price"
          }
        }
      }
    }
  }
}



date hitogram之统计每月电视销量

GET /tvs/_search
{
  "size": 0,
  "aggs": {
    "电视销量": {
      "date_histogram": {
        "field": "sold_date",
        "interval": "month",
        "extended_bounds": {
          "min": "2016-01-01"
        },
        "min_doc_count": 1,
        "format": "yyyy-MM-dd"
      }, 
      "aggs": {
        "销售额": {
          "sum": {
            "field": "price"
          }
        }
      }
    }
  }
}
  • date histogram,按照指定的某个date类型的日期field,以及日期interval,按照一定的日期间隔,去划分bucket
  • date interval = 1m,

    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:默认为0,表示当桶中文档的数量最少也要等于min_doc_count才会显示出来,否则会过滤掉。比如,2017-01-01~2017-01-31中,一条数据都没有,如果想过滤它则写min_doc_count:1
  • extended_bounds,min,max:划分bucket的时候,会限定在这个起始日期,和截止日期内



下钻分析之统计每季度每个品牌的销售额

GET /tvs/_search
{
  "size": 0,
  "aggs": {
    "季度": {
      "date_histogram": {
        "field": "sold_date",
        "interval": "quarter",
        "min_doc_count": 0, 
        "format": "yyyy-MM"
      },
      "aggs": {
        "品牌": {
          "terms": {
            "field": "brand"
          },
          "aggs": {
            "销售额": {
              "sum": {
                "field": "price"
              }
            }
          }
        }
      }
    }
  }
}



统计小米有什么颜色的手机

GET /tvs/_search
{
  "size": 0,
  "query": {
    "term": {
      "brand": {
        "value": "小米"
      }
    }
  }, 
  "aggs": {
    "颜色": {
      "terms": {
        "field": "color"
      }
    }
  }
}

aggs是基于query过滤后的范围进行分组的



小米的平均价格 对比所有手机的平均价格

GET /tvs/_search
{
  "size": 0,
  "query": {
    "term": {
      "brand": {
        "value": "小米"
      }
    }
  }, 
  "aggs": {
    "小米手机": {
      "avg": {
        "field": "price"
      }
    },
    "所有手机": {
      "global": {},
      "aggs": {
        "平均价格": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}
  • global,让聚合的范围忽略query,就是将所有数据纳入聚合的scope,而不管之前的query。



统计价格大于1200的电视平均价格

GET /tvs/_search
{
  "size": 0,
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "price": {
            "gte": 1200
          }
        }
      }
    }
  },
  "aggs": {
    "平均价格": {
      "avg": {
        "field": "price"
      }
    }
  }
}
  • constant_score:表示该条件的得分是静态的,不用动态计算得分。
  • constant_score.filter:filter之所以被constant_score包裹,是因为被过滤的数据是不关心得分的。



bucket filter:统计牌品2016年的平均价格

TODO



排序:按每种颜色的平均销售额降序排序

TODO



去重cardinality:根据销售数据获取共有多少种品牌

# 类似于 select count(*) from tvs group by brand
GET /tvs/_search
{
  "size": 0, 
  "aggs": {
    "所有的品牌": {
      "cardinality": {
        "field": "brand"
      }
    }
  }
}

# 校验
GET /tvs/_search
{
  "aggs": {
    "所有的品牌": {
      "terms": {
        "field": "brand"
        }
    }
  }
}



版权声明:本文为Yal_insist原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。