Elasticsearch聚合学习之三:范围限定

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 在聚合查询时,很少用到索引中的全部文档,这就需要我们对数据的范围做限定,本文对范围限定涉及的各种操作进行了说明和实践

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码): https://github.com/zq2599/blog_demos

本篇概览

  • 在《Elasticsearch聚合学习》系列的前面两篇文章中,我们熟悉了基本聚合操作,但这些操作都是面向索引中的全部数据(例如所有汽车销售记录一共有几种颜色的汽车),今天要学习的是如何对一定范围内的数据做聚合(例如以前是看所有汽车一共有几种颜色,现在只看福特汽车一共有几种颜色);

系列文章列表

  1. 《Elasticsearch聚合学习之一:基本操作》
  2. 《Elasticsearch聚合学习之二:区间聚合》
  3. 《Elasticsearch聚合学习之三:范围限定》;
  4. 《Elasticsearch聚合学习之四:结果排序》

环境信息

  • 以下是本次实战的环境信息,请确保您的Elasticsearch可以正常运行:
  1. 操作系统:Ubuntu 18.04.2 LTS
  2. JDK:1.8.0_191
  3. Elasticsearch:6.7.1
  4. Kibana:6.7.1
  • 实战用的数据依然是一些汽车销售的记录,在第一章有详细的导入步骤,请参考操作,导入后您的es中的数据如下图:

在这里插入图片描述

本章概要

  • 本篇聚焦查询范围限定,由以下内容构成:
  1. 不做限定时的默认范围;
  2. 最简单的查询范围
  3. 全局桶
  4. 使用过滤器
  5. 桶内使用过滤器

不做限定时的默认范围

  • 下面是个普通的聚合请求,将文档按照color字段聚合,由于没有做任何范围限定,因此查询的是所有文档:
GET /cars/transactions/_search
{
  "size":0,
  "aggs":{
   "popular_colors":{
     "terms": {
       "field": "color"
     }
   } 
  }
}
  • 下面请求带上了查询条件match_all,匹配所有文档,和前面不带查询条件的请求达到了同样效果:
GET /cars/transactions/_search
{
  "size":0,
  "query": {            ------查询条件
    "match_all": {}     ------匹配所有文档
  }, 
  "aggs":{
   "popular_colors":{
     "terms": {
       "field": "color"
     }
   } 
  }
}

最简单的查询范围

  • 前面提出了一个问题:福特汽车一共分为几种颜色?这就是最简单的范围限定聚合(限定了汽车品牌),查询DSL如下:
GET /cars/transactions/_search
{
  "size":0,
  "query": {                ---范围限定的查询
    "term": {               ---查询类型是精确匹配
      "make": "ford"        ---查询条件是品牌为福特
    }
  }, 
  "aggs":{                  ---聚合
   "popular_colors":{       ---聚合字段名
     "terms": {             ---桶类型
       "field": "color"     ---匹配字段是color
     }
   } 
  }
}
  • 返回结果如下,只有福特汽车的聚合数据:
{
  "took" : 7,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {                       ---聚合结果
    "popular_colors" : {                   ---聚合字段
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [                        ---这个数组的元素是所有的桶
        {
          "key" : "blue",                  ---color为blue的文档
          "doc_count" : 1                  ---文档数为1
        },
        {
          "key" : "green",                 ---color为blue的文档
          "doc_count" : 1                  ---文档数为1
        }
      ]
    }
  }
}

全局桶

  • 如果想对比福特汽车的销售额和所有汽车的销售额,可以通过全局桶对所有文档做聚合,关键字是global,全局桶的聚合不受范围限定的影响:
GET /cars/transactions/_search
{
  "size": 0,
  "query": {                 ---范围限定的查询
    "term": {                ---查询类型是精确匹配
      "make": "ford"         ---查询条件是品牌为福特
    }
  },
  "aggs": {                  ---聚合
    "ford_sales": {          ---聚合字段名
      "sum": {               ---直接对范围内的所有文档执行metrics,类型是累加
        "field": "price"     ---选择price字段的值进行累加
      }
    },
    "all": {                 ---聚合字段名
      "global": {},          ---全局桶关键字,表示忽略前面term查询的范围限定
      "aggs": {              ---聚合
        "all_sales": {       ---聚合字段名
          "sum": {           ---直接对范围内的所有文档执行metrics,类型是累加
            "field": "price" ---选择price字段的值进行累加
          }
        }
      }
    }
  }
}
  • 来看看结果:
......
  "aggregations" : {         ---聚合结果
    "all" : {                ---全局桶的聚合结果(term查询无效)
      "doc_count" : 8,       ---文档总数
      "all_sales" : {        ---聚合字段名
        "value" : 212000.0   ---总销售额
      }
    },
    "ford_sales" : {         ---聚合字段名(term查询限定了范围,只有福特汽车的销售记录)
      "value" : 55000.0      ---福特汽车销售额
    }
  }
}

不止是query

  • 前面的范围限定用到了query,其实适用于查询的过滤器也能应用在聚合操作中,下面是过滤+聚合的查询,和前面一样,也是统计总销售和和福特汽车的销售额:
GET /cars/transactions/_search
{
  "size": 0,
  "query": {
    "bool": {                 ---布尔查询,里面可以将query和filter组合使用
      "filter": {             ---本例只用到了filter
        "term": {             ---精确匹配
          "make": "ford"      ---匹配福特品牌 
        }
      }
    }
  },
  "aggs": {                   ---聚合结果
    "ford_sales": {           ---聚合字段名
      "sum": {                ---metrics操作,累加
        "field": "price"      ---累加字段是price
      }
    },
    "all": {                  ---聚合字段名                  
      "global": {},           ---全局桶关键字,表示忽略范围限定
      "aggs": {               ---聚合
        "all_sales": {        ---聚合字段名
          "sum": {            ---metrics操作,累加
            "field": "price"  ---累加字段是price
          }
        }
      }
    }
  }
}
  • 查询结果如下,和query的一样:
......
  "aggregations" : {
    "all" : {
      "doc_count" : 8,
      "all_sales" : {
        "value" : 212000.0
      }
    },
    "ford_sales" : {
      "value" : 55000.0
    }
  }
}
  • 注意:虽然query和filter限定范围的结果是一样的,但是filter会忽略评分,并且有可能缓存结果数据,这些都是性能上的优势;

桶内filter

  • 学习桶内filter之前,先看看官方的布尔查询DSL,如下所示,查询JSON对象的内部可以加入filter,对查询结果做过滤:
GET /_search
{
  "query": { 
    "bool": { 
      "must": [                                     ---布尔查询
        { "match": { "title":   "Search"        }}, 
        { "match": { "content": "Elasticsearch" }}  
      ],
      "filter": [                                   ---对查询结果做过滤
        { "term":  { "status": "published" }}, 
        { "range": { "publish_date": { "gte": "2015-01-01" }}} 
      ]
    }
  }
}
  • 桶内filter和布尔查询中的filter类似,对进入桶中的数据可以加入filter,这样桶内的数据就是此filter过滤后的数据了;
  • 举个例子,统计蓝色的福特汽车销售额,首先限定品牌范围,这个可以直接用之前的限定方式,然后在桶内加入一个filter,只保留颜色为蓝色的文档:
GET /cars/transactions/_search
{
  "size": 0,
  "query": {
    "bool": {                 ---布尔查询,里面可以将query和filter组合使用
      "filter": {             ---本例只用到了filter
        "term": {             ---精确匹配
          "make": "ford"      ---匹配福特品牌 
        }
      }
    }
  },
  "aggs": {
    "sales": {
      "filter": {             ---桶内filter
        "term": {             ---精确匹配
          "color": "blue"     ---匹配蓝色
        }
      },
      "aggs": {
        "blue_sales": {
          "sum": {            ---metrics操作,累加
            "field": "price"
          }
        }
      }
    }
  }
}
  • 返回结果如下,可见hits.total等于2,表示查询到了两个文档,但是sales.doc_count等于1,表示桶内filter作用后再桶内只剩下一个文档了:
  "hits" : {
    "total" : 2,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "sales" : {
      "doc_count" : 1,
      "green_sales" : {
        "value" : 25000.0
      }
    }
  }
}

后过滤器(post_filter)

  • 还有一种特殊的filter,名为post_filter,其作用描述如下:
  • 正常的聚合:先查询,得到查询结果A,再用A做聚合操作得到结果B,最后返回B和A;
  • 带有post_filter的聚合:先查询,得到查询结果A,再用A做聚合操作得到结果B,然后用A做过滤得到C(过滤条件就是post_filter),最后返回B和C;
  • 可见无论是否使用post_filter,返回的聚合结果都是根据A生成的B,不同之处在于用了post_filter就不返回A,而是返回A的过滤结果;
  • 以下是来自《Elasticsearch 权威指南》的post_filter示例:
GET /cars/transactions/_search
{
    "size" : 0,
    "query": {
        "match": {
            "make": "ford"
        }
    },
    "post_filter": {    
        "term" : {
            "color" : "green"
        }
    },
    "aggs" : {
        "all_colors": {
            "terms" : { "field" : "color" }
        }
    }
}
  • 值得注意得是:如果只做查询不做聚合,post_filter的作用和我们常用的filter是类似的,但由于post_filter是在查询之后才会执行,所以post_filter不具备filter对查询带来的好处(忽略评分、缓存等),因此,在普通的查询中不要用post_filter来替代filter;
  • 如果您向进一步了解post_filter,请参考《理解elasticsearch的post_filter》
  • 至此,带有范围限定的聚合操作实战就全部完成了,目前所有示例的结果都是默认排序的,接下来的章节将一起学习了解如何对聚合结果做排序。

欢迎关注阿里云开发者社区博客:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...
相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
2月前
|
自然语言处理 Java 网络架构
elasticsearch学习三:elasticsearch-ik分词器的自定义配置 分词内容
这篇文章是关于如何自定义Elasticsearch的ik分词器配置以满足特定的中文分词需求。
148 0
elasticsearch学习三:elasticsearch-ik分词器的自定义配置 分词内容
|
1月前
|
存储 SQL 监控
|
2月前
|
JSON Java 网络架构
elasticsearch学习四:使用springboot整合 rest 进行搭建elasticsearch服务
这篇文章介绍了如何使用Spring Boot整合REST方式来搭建和操作Elasticsearch服务。
140 4
elasticsearch学习四:使用springboot整合 rest 进行搭建elasticsearch服务
|
2月前
|
自然语言处理 搜索推荐 关系型数据库
elasticsearch学习六:学习 全文搜索引擎 elasticsearch的语法,使用kibana进行模拟测试(持续更新学习)
这篇文章是关于Elasticsearch全文搜索引擎的学习指南,涵盖了基本概念、命令风格、索引操作、分词器使用,以及数据的增加、修改、删除和查询等操作。
32 0
elasticsearch学习六:学习 全文搜索引擎 elasticsearch的语法,使用kibana进行模拟测试(持续更新学习)
|
2月前
|
Web App开发 JavaScript Java
elasticsearch学习五:springboot整合 rest 操作elasticsearch的 实际案例操作,编写搜索的前后端,爬取京东数据到elasticsearch中。
这篇文章是关于如何使用Spring Boot整合Elasticsearch,并通过REST客户端操作Elasticsearch,实现一个简单的搜索前后端,以及如何爬取京东数据到Elasticsearch的案例教程。
220 0
elasticsearch学习五:springboot整合 rest 操作elasticsearch的 实际案例操作,编写搜索的前后端,爬取京东数据到elasticsearch中。
|
2月前
|
自然语言处理 Java Maven
elasticsearch学习二:使用springboot整合TransportClient 进行搭建elasticsearch服务
这篇博客介绍了如何使用Spring Boot整合TransportClient搭建Elasticsearch服务,包括项目创建、Maven依赖、业务代码和测试示例。
119 0
elasticsearch学习二:使用springboot整合TransportClient 进行搭建elasticsearch服务
|
2月前
|
存储 JSON Java
elasticsearch学习一:了解 ES,版本之间的对应。安装elasticsearch,kibana,head插件、elasticsearch-ik分词器。
这篇文章是关于Elasticsearch的学习指南,包括了解Elasticsearch、版本对应、安装运行Elasticsearch和Kibana、安装head插件和elasticsearch-ik分词器的步骤。
203 0
elasticsearch学习一:了解 ES,版本之间的对应。安装elasticsearch,kibana,head插件、elasticsearch-ik分词器。
|
3月前
|
存储 自然语言处理 关系型数据库
ElasticSearch基础3——聚合、补全、集群。黑马旅游检索高亮+自定义分词器+自动补全+前后端消息同步
聚合、补全、RabbitMQ消息同步、集群、脑裂问题、集群分布式存储、黑马旅游实现过滤和搜索补全功能
ElasticSearch基础3——聚合、补全、集群。黑马旅游检索高亮+自定义分词器+自动补全+前后端消息同步
|
4月前
|
自然语言处理 Java 关系型数据库
ElasticSearch 实现分词全文检索 - 聚合查询 cardinality
ElasticSearch 实现分词全文检索 - 聚合查询 cardinality
149 1
|
6月前
|
SQL 安全 数据挖掘
Elasticsearch如何聚合查询多个统计值,如何嵌套聚合?并相互引用,统计索引中某一个字段的空值率?语法是怎么样的?
Elasticsearch聚合查询用于复杂数据分析,包括统计空值率。示例展示了如何计算字段`my_field`非空非零文档的百分比。查询分为三步:总文档数计数、符合条件文档数计数及计算百分比。聚合概念涵盖度量、桶和管道聚合。脚本在聚合中用于动态计算。常见聚合类型如`sum`、`avg`、`date_histogram`等。组合使用可实现多值统计、嵌套聚合和空值率计算。[阅读更多](https://zhangfeidezhu.com/?p=515)
306 0
Elasticsearch如何聚合查询多个统计值,如何嵌套聚合?并相互引用,统计索引中某一个字段的空值率?语法是怎么样的?