社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Elasticsearch

Elasticsearch系列---聚合查询(一)

1黄鹰 • 6 年前 • 533 次点击  
阅读 45

Elasticsearch系列---聚合查询(一)

概要

Elasticsearch的聚合查询,跟数据库的聚合查询效果是一样的,我们可以将二者拿来对比学习,如求和、求平均值、求最大最小等等。

基础概念

bucket

数据分组,一些数据按照某个字段进行bucket划分,这个字段值相同的数据放到一个bucket中。可以理解成Java中的Map<String, List>结构,类似于Mysql中的group by后的查询结果。

metric:

对一个数据分组执行的统计,比如计算最大值,最小值,平均值等 类似于Mysql中的max(),min(),avg()函数的值,都是在group by后使用的。

案例

我们还是以英文儿歌为案例背景,回顾一下索引结构:

PUT /music
{
  "mappings": {
      "children": {
        "properties": {
          "id": {
            "type": "keyword"
          },
          "author_first_name": {
            "type": "text",
            "analyzer": "english"
          },
          "author_last_name": {
            "type": "text",
            "analyzer": "english"
          },
          "author": {
            "type": "text",
            "analyzer": "english",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "name": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "content": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "language": {
            "type": "text",
            "analyzer": "english",
            "fielddata": true
          },
          "tags": {
            "type": "text",
            "analyzer": "english"
          },
          "length": {
            "type": "long"
          },
          "likes": {
            "type": "long"
          },
          "isRelease": {
            "type": "boolean"
          },
          "releaseDate": {
            "type": "date"
          }
        }
      }
  }
}
复制代码

统计目前收录的哪种语言的歌曲最多

GET /music/children/_search
{
  "size": 0,
  "aggs": {
    "song_qty_by_language": {
      "terms": {
        "field": "language"
      }
    }
  }
}
复制代码

语法解释:

  • size:0 表示只要统计后的结果,原始数据不展现
  • aggs:固定语法 ,聚合分析都要声明aggs
  • song_qty_by_language:聚合的名称,可以随便写,建议规范命名
  • terms:按什么字段进行分组
  • field:具体的字段名称

响应结果如下:

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 5,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "song_qty_by_language": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "english",
          "doc_count": 5
        }
      ]
    }
  }
}
复制代码

语法解释:

  • hits: 由于请求时设置了size:0,hits就是空的
  • aggregations:聚合查询的结果
  • song_qty_by_language:请求时声明的名称
  • buckets:根据指定字段查询后得到的数据分组集合,[]内的是每一个数据分组,其中key为每个bucket的对应指定字段的值,doc_count为统计的数量。

默认按doc_count降序排序。

按语种统计每种歌曲的平均时长

GET /music/children/_search
{
  "size": 0,
  "aggs": {
    "lang": {
      "terms": {
        "field": "language"
      },
      "aggs": {
        "length_avg": {
          "avg": {
            "field": "length"
          }
        }
      }
    }
  }
}
复制代码

这里演示的是两层aggs聚合查询,先按语种统计,得到数据分组,再在数据分组里算平均时长。

多个aggs嵌套语法也是如此,注意一下aggs代码块的位置即可。

统计最长时长、最短时长等的歌曲

最常用的统计:count,avg,max,min,sum,语法含义与mysql相同。




    
GET /music/children/_search
{
  "size": 0,
  "aggs": {
    "color": {
      "terms": {
        "field": "language"
      },
      "aggs": {
        "length_avg": {
          "avg": {
            "field": "length"
          }
        },
        "length_max": {
          "max": {
            "field": "length"
          }
        },
        "length_min": {
          "min": {
            "field": "length"
          }
        },
        "length_sum": {
          "sum": {
            "field": "length"
          }
        }
      }
    }
  }
}
复制代码

按时长分段统计歌曲平均时长

以30秒为一段,看各段区间的平均值。

histogram语法位置跟terms一样,作范围分区,搭配interval参数一起使用 interval:30表示分的区间段为[0,30),[30,60),[60,90),[90,120)

段的闭合关系是左开右闭,如果数据在某段区间内没有,也会返回空的区间。

GET /music/children/_search
{
  "size": 0,
  "aggs": {
    "sales_price_range": {
      "histogram": {
        "field": "length",
        "interval": 30
      },
      "aggs": {
        "length_avg": {
          "avg": {
            "field": "length"
          }
        }
      }
    }
  }
}
复制代码

这种数据的结果可以用来生成柱状图或折线图。

按上架日期分段统计新歌数量

按月统计

date histogram与histogram语法类似,搭配date interval指定区间间隔 extended_bounds表示最大的时间范围。

GET /music/children/_search
{
  "size": 0,
  "aggs": {
    "sales": {
      "date_histogram": {
        "field": "releaseDate",
        "interval": "month",
        "format": "yyyy-MM-dd",
        "min_doc_count": 0,
        "extended_bounds": {
          "min": "2019-10-01",
          "max": "2019-12-31"
        }
      }
    }
  }
}
复制代码

interval的值可以天、周、月、季度、年等。我们可以延伸一下,比如统计今年每个季度的新发布歌曲的点赞数量

GET /music/children/_search
{
  "size": 0,
  "aggs": {
    "sales": {
      "date_histogram": {
        "field": "releaseDate",
        "interval": "quarter",
        "format": "yyyy-MM-dd",
        "min_doc_count": 0,
        "extended_bounds": {
          "min": "2019-01-01",
          "max": "2019-12-31"
        }
      },
      "aggs": {
        "lang_qty": {
          "terms": {
            "field": "language"
          },
          "aggs": {
            "like_sum": {
              "sum": {
                "field": "likes"
              }
            }
          }
        },
        "total" :{
          "sum": {
            "field": "likes"
          }
        }
      }
    }
  }
}
复制代码

带上过滤条件

聚合查询可以和query搭配使用,相当于mysql中where与group by联合使用

查询条件
GET /music/children/_search
{
  "size": 0,
  "query": {
    "match": {
      "language": "english"
    }
  },
  "aggs": {
    "sales": {
      "terms": {
        "field": "language"
      }
    }
  }
}
复制代码
过滤条件
GET /music/children/_search
{
  "size": 0,
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "language": "english"
        }
      }
    }
  },
  "aggs": {
    "sales": {
      "terms": {
        "field": "language"
      }
    }
  }
}
复制代码

global bucket查询

global:就是global bucket,会将所有的数据纳入聚合scope,不受前面的query或filter影响。

global bucket适用于同时统计指定条件的数据与全部数据的对比,如我们创造的场景:指定作者的歌与全部歌曲的点赞数量对比。

GET /music/children/_search
{
  "size": 0,
  "query": {
    "match": {
      "author": "Jean Ritchie"
    }
  },
  "aggs": {
    "likes": {
      "sum": {
        "field": "likes"
      }
    },
    "all": {
      "global": {},
      "aggs": {
        "all_likes": {
          "sum": {
            "field": "likes"
          }
        }
      }
    }
  }
}
复制代码

统计近2月,近1月的点赞数

aggs.filter针对是聚合里的数据

bucket filter:对不同的bucket下的aggs,进行filter

类似于mysql的中having语法

GET /music/children/_search
{
  "size": 0,
  "aggs": {
    "recent_60d": {
      "filter": {
        "range": {
          "releaseDate": {
            "gte": "now-60d"
          }
        }
      },
      "aggs": {
        "recent_60d_likes_sum": {
          "sum": {
            "field": "likes"
          }
        }
      }
    },
    "recent_30d": {
      "filter": {
        "range": {
          "releaseDate": {
            "gte": "now-30d"
          }
        }
      },
      "aggs": {
        "recent_30d_likes_sum"


    
: {
          "avg": {
            "field": "likes"
          }
        }
      }
    }
  }
}
复制代码

统计排序

默认按doc_count降序排序,排序规则可以改,order里面可以指定aggs的别名,如length_avg,类似于mysql的order by cnt asc。

GET /music/children/_search
{
  "size": 0,
  "aggs": {
    "group_by_lang": {
      "terms": {
        "field": "language",
        "order": {
          "length_avg": "desc"
        }
      },
      "aggs": {
        "length_avg": {
          "avg": {
            "field": "length"
          }
        }
      }
    }
  }
}
复制代码

小结

本篇主要介绍常用的聚合查询,均以示例为主,了解基本写法后可以快速阅读,有不好理解的地方,多与我们熟悉的数据库查询SQL作比较,谢谢。

专注Java高并发、分布式架构,更多技术干货分享与心得,请关注公众号:Java架构社区 可以扫左边二维码添加好友,邀请你加入Java架构社区微信群共同探讨技术

Java架构社区

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/57298