理解Es的DSL语法(二):聚合

前一篇已经系统介绍过查询语法,详细可直接看上一篇文章(理解DSL语法(一)),本篇主要介绍DSL中的另一部分:聚合

理解Es中的聚合

虽然Elasticsearch 是一个基于 Lucene 的搜索引擎,但也提供了聚合(aggregations)的功能,允许用户对数据进行统计和分析。聚合可以按照不同的维度对数据进行分组和汇总,从而得到有意义的统计信息。这也是Es很多场景下被当作分析工具使用的原因。

聚合语法

使用上来讲,es的聚合就相当于SQL中的group by,在DSL中主要使用aggs关键字和size关键字来控制:

{
  "size":0,
  "aggs":{
    "TestName":{  //自定义的聚合名称
         "term":{ //聚合类型关键字,根据聚合类型来
              "field":"title"  //需要聚合的字段
           }
     }
  }
}

这里着重说一下size关键字,如果单纯进行聚合,而不需要实际数据,最好这里size设置为0,设置size为0在进行聚合时,会默认触发Es的缓存机制,能够很有效的提升性能

当然聚合也可以搭配查询query使用,即对查询的数据进行聚合,例如我们对最近一天的文章,聚合一下标题:

{
  "query":{
     "bool":{
       "filter":[
            {
              "range":{ 
                 "create_time":{
                     "gte":"now - 1d",
                     "lte":"now"
                  }
              }
            }

        ]
    }
  }
  "size":0,
  "aggs":{
    "TestName":{  //自定义的聚合名称
         "term":{ //聚合类型关键字,根据聚合类型来
              "field":"title"  //需要聚合的字段
           }
     }
  }
}

这里Es收到请求后,会先根据query中的条件去检索满足创建时间在近一天内的所有文档,然后对这些文档进行桶聚合,以title字段为桶,将title内容一致的文档放入桶内。

聚合的种类

总的来看,Es的聚合可以分为四类,即Bucketing Aggregations、Metric Aggregations、Matrix Aggregations、Pipeline Aggregations。

Bucketing Aggregations

将数据分桶,类似于 SQL 中的 GROUP BY。例如,可以根据某个字段的不同值将数据分组,然后对每个分组进行统计,对于字段和内容都有一定的限制。

常用的聚合关键字有:

关键字描述适用字段类型
TermsTerms 聚合根据指定字段的确切值将文档分组。它类似于 SQL 中的 GROUP BY 语句。keyword 
Histogram直方图聚合将数值字段划分为指定间隔的桶,并计算每个桶中的文档数量。

数值类型(

integerfloatdouble 、 long)

Date Histogram日期直方图聚合类似于直方图聚合,但它专门用于日期字段,允许你根据时间间隔(如天、周、月等)来分组数据date
Range范围聚合允许你根据指定的范围将数据分组,每个范围定义了上界和下界。数值类型

integerfloatdouble 、 long)

和date
IP Range IP 范围聚合允许你根据 IP 地址的范围将数据分组。ip
Date Range日期范围聚合是范围聚合的日期版本,专门用于日期字段。date
Filter/Filters过滤器聚合根据一个或多个过滤器条件将数据分组,每个过滤器条件定义了一个桶。可以应用于任何类型的字段,但通常与布尔查询结合使用来定义过滤器条件。
Nested 嵌套聚合应用于嵌套字段,它允许你根据嵌套对象中的字段值对嵌套文档进行分组。object或nested

详细的可查阅ElasticSearch的官网,这里仅列出常用的,我们假设Es中存在以下一个数据集合:

[
  {"name": "Book A", "category": "Fiction", "price": 9.99, "publish_date": "2020-01-01"},
  {"name": "Book B", "category": "Science", "price": 15.00, "publish_date": "2021-06-15"},
  {"name": "Book C", "category": "Fiction", "price": 12.50, "publish_date": "2022-03-10"},
  {"name": "Book D", "category": "Education", "price": 8.50, "publish_date": "2019-09-20"},
  {"name": "Book E", "category": "Science", "price": 20.00, "publish_date": "2023-01-05"}
]

并针对该数据集,进行相关的聚合样例:

 Terms Aggregation聚合

查看有多少种category以及每种的文档数量。

示例:

{
   "size":0,
    "aggs": {
        "genres": {
            "terms": {
                "field": "category"  // genre必须为keyword类型
                "size":3         //根据文档数量倒叙展示条数,默认不填写则仅展示10个
            }
        }
    }
}

//输出:
{
  "category": {
    "buckets": [
      {"key": "Fiction", "doc_count": 2},
      {"key": "Science", "doc_count": 2},
      {"key": "Education", "doc_count": 1}
    ]
  }
}
Histogram Aggregation 聚合

按价格区间聚合书籍

{
  "size":0,
  "aggs": {
    "price_distribution": {
      "histogram": {
        "field": "price",
        "interval": 5  //以5元为一个段
      }
    }
  }
}

//输出:
{
  "aggregations": {
    "price_distribution": {
      "buckets": [
        { "key": 5, "doc_count": 1 },
        { "key": 10, "doc_count": 2 },
        { "key": 15, "doc_count": 2 }
      ]
    }
  }
}
Date Histogram Aggregation 聚合

按年份查看出版书籍的数量

{
  "size":0,
  "aggs": {
    "books_over_time": {
      "date_histogram": {
        "field": "publish_date",
        "calendar_interval": "year" //查询区间可以指定单位
      }
    }
  }
}

//输出

{
  "aggregations": {
    "books_over_time": {
      "buckets": [
        { "key_as_string": "2019", "doc_count": 1 },
        { "key_as_string": "2020", "doc_count": 1 },
        { "key_as_string": "2021", "doc_count": 1 },
        { "key_as_string": "2022", "doc_count": 1 },
        { "key_as_string": "2023", "doc_count": 1 }
      ]
    }
  }
}

其中对于date_histogram使用较多,这里单独列一下关于date_histogram的相关参数

  • calendar_interval:按照日历时间间隔(如年、季度、月、周、日等)来创建桶。

  • fixed_interval:按照固定时间间隔(如1小时、5分钟等)来创建桶,不考虑日历界限。

  • min_doc_count:设置为 0 或更大的值,以忽略那些文档计数小于该值的桶。

  • extended_bounds:允许聚合查询返回超出正常查询范围之外的桶,例如在直方图的开始或结束之前添加额外的桶。

  • order:指定桶的排序方式,可以是 asc(升序)或 desc(降序)。

  • format:自定义日期格式,用于指定桶的 key 值的日期格式。

  • time_zone:指定时区来应用到聚合上,特别是对于固定间隔的聚合。

  • pre_zonepost_zone:与 extended_bounds 结合使用,指定额外桶的时区。

{
  "size": 0,
  "aggs": {
    "publish_monthly": {
      "date_histogram": {
        "field": "publish_date",
        "calendar_interval": "month",  // 每月一个桶
        "min_doc_count": 1,            // 只包括至少有一个文档的桶
        "extended_bounds": {
          "min": "2019-01-01",
          "max": "2023-12-31"
        },  // 设置聚合的最小和最大界限
        "order": "desc",              // 桶按降序排序
        "format": "yyyy-MM",          // 桶 key 的格式
        "time_zone": "Europe/Berlin" // 使用柏林时区
      }
    }
  }
}

Range Aggregation聚合

查看价格区间内书籍的数量

{
  "size":0,
  "aggs": {
    "price_ranges": {
      "range": {
        "field": "price",
        "ranges": [
          { "from": 0, "to": 10 },
          { "from": 10, "to": 20 }
        ]
      }
    }
  }
}

//输出
{
  "aggregations": {
    "price_ranges": {
      "buckets": [
        { "from": 0, "to": 10, "doc_count": 2 },
        { "from": 10, "to": 20, "doc_count": 3 }
      ]
    }
  }
}
Filters Aggregation聚合

同时筛选 Fiction 和 Science 类别的书籍,并分别计算数量。

{
  "size":0,
  "aggs": {
    "category_filters": {
      "filters": {
        "filters": {
          "Fiction": {
            "term": {
              "category.keyword": "Fiction"
            }
          },
          "Science": {
            "term": {
              "category.keyword": "Science"
            }
          }
        }
      }
    }
  }
}
//输出
{
  "aggregations": {
    "category_filters": {
      "buckets": {
        "Fiction": { "doc_count": 2 },
        "Science": { "doc_count": 2 }
      }
    }
  }
}

这里特殊说明一下,针对以上场景,也可以使用:

{
 "query": {
  "bool": {
   "filter": [
     {
      "terms": {
      "category": ["Fiction", "Science"]
     }
    }
   ]
  }
 },
 "size": 0,
 "aggs": {
   "category": {
    "terms": {
      "field": "category"
    }
  }
 }
}

不同的是,使用这种聚合,Es的需要进行两次操作,即:先根据query条件,进行数据查询,再对查询结果进行聚合,而Filters聚合则只有一次操作。在相同场景下,考虑性能的话,使用 filters 聚合可能在某些情况下更有效率,因为它可以利用 Elasticsearch 的缓存机制,特别是当这些特定的过滤条件经常被查询时。

Composite Aggregation聚合

按 category 和 publish_date 的每个月份组合聚合书籍。

{
  "size": 0,
  "aggs": {
    "category_date_composite": {
      "composite": {
        "sources": [
          { "category": { "terms": { "field": "category.keyword" } } },
          { "date": { "date_histogram": { "field": "publish_date", "calendar_interval": "month" } } }
        ],
        "size": 10
      }
    }
  }
}
//输出
{
  "composite_of_category_and_date": {
    "buckets": [
      {"key": {"category": "Fiction", "date": "2020-01"}, "doc_count": 1},
      {"key": {"category": "Fiction", "date": "2022-03"}, "doc_count": 1},
      {"key": {"category": "Science", "date": "2021-06"}, "doc_count": 1},
      {"key": {"category": "Science", "date": "2023-01"}, "doc_count": 1}
    ]
  }
}

Metric Aggregations

对数据进行数学运算,如计算平均值、总和、最小值、最大值等。此类大多对数字类型的字段进行聚合。

关键字描述
Sum Aggregation计算数值字段的总和
Avg Aggregation

计算数值字段的平均值

Min Aggregation

找出数值字段中的最小值

Max Aggregation

找出数值字段中的最大值

Stats Aggregation

返回字段的多个统计度量,包括最小值、最大值、平均值和总和。

Cardinality Aggregation

计算字段中唯一值的近似数量,对于大数据集非常有用,因为它比value_count更高效。

一般配合桶查询使用,对标的是SQL中的SUM、MAX等数学函数

Cardinality Aggregation

查看一共有多少文档:

{
  "size":0,
  "aggs": {
    "countALl": {
      "cardinality": {
        "field": "_id"
      }
    }
  }
}

//输出
{
  "aggregations": {
    "countALl": {
      "value": 3
    }
  }
}

Min/Max Aggregation

//查看书籍最贵的价格
{
  "size":0,
  "aggs": {
    "maximum_price": {
      "max": {
        "field": "price"
      }
    }
  }
}
//输出:
{
  "aggregations": {
    "maximum_price": {
      "value": 20.0
    }
  }
}


//查看书籍最便宜的价格
{
  "size":0,
  "aggs": {
    "min_price": {
      "min": {
        "field": "price"
      }
    }
  }
}
//输出
//输出:
{
  "aggregations": {
    "min_price": {
      "value": 5.0
    }
  }
}

Sum/Avg Aggregation

//对库内书籍价格求和
{
  "aggs": {
    "all_price": {
      "sum": {
        "field": "price"
      }
    }
  }
}

//输出:
{
  "aggregations": {
    "all_price": {
      "value": 13.398
    }
  }
}



//对库内书籍价格求均值
{
  "aggs": {
    "average_price": {
      "avg": {
        "field": "price"
      }
    }
  }
}

//输出
{
  "aggregations": {
    "average_price": {
      "value": 13.398
    }
  }
}

Stats Aggregation

查看价格的综合统计

{
  "size":0,
  "aggs": {
    "price_stats": {
      "stats": {
        "field": "price"
      }
    }
  }
}

//输出:
{
  "aggregations": {
    "price_stats": {
      "count": 5,
      "min": 8.5,
      "max": 20.0,
      "avg": 13.398,
      "sum": 66.99
    }
  }
}

聚合嵌套

语法格式为:

{
  "size":0,
  "aggs":{
      "One":{  // 一层桶名称
         "terms":{
            "field":"fielda"
          },
        "aggs":{  //一层桶下二层聚合
            
          } 
       }
   }
}

以书籍书籍为例,查看每类书籍的平均价格,则可以先对书籍类型进行terms聚合,再在terms桶内,获取桶内书籍的平均价格:

//DSL
{
  "size": 0,
  "aggs": {
    "categories": {
      "terms": {
        "field": "keyword"
      },
      "aggs": {
        "average_price": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}

//输出结果
{
  "aggregations": {
    "categories": {
      "buckets": [
        {
          "key": "Fiction",
          "doc_count": 2,
          "average_price": {
            "value": 11.245
          }
        },
        {
          "key": "Science",
          "doc_count": 2,
          "average_price": {
            "value": 17.5
          }
        },
        {
          "key": "Education",
          "doc_count": 1,
          "average_price": {
            "value": 8.5
          }
        }
      ]
    }
  }
}

也可以查看发布年限,每年里发布书籍的总价格:

{
  "size": 0,
  "aggs": {
    "publish_years": {
      "date_histogram": {
        "field": "publish_date",
        "calendar_interval": "year"
      },
      "aggs": {
        "total_price": {
          "sum": {
            "field": "price"
          }
        }
      }
    }
  }
}

//输出
{
  "aggregations": {
    "publish_years": {
      "buckets": [
        {
          "key_as_string": "2019",
          "key": 1577836800000,
          "doc_count": 1,
          "total_price": {
            "value": 8.5
          }
        },
        {
          "key_as_string": "2020",
          "key": 1609459200000,
          "doc_count": 1,
          "total_price": {
            "value": 9.99
          }
        },
        {
          "key_as_string": "2021",
          "key": 1609459200000,
          "doc_count": 1,
          "total_price": {
            "value": 15.0
          }
        },
        {
          "key_as_string": "2022",
          "key": 1640995200000,
          "doc_count": 1,
          "total_price": {
            "value": 12.5
          }
        },
        {
          "key_as_string": "2023",
          "key": 1672531200000,
          "doc_count": 1,
          "total_price": {
            "value": 20.0
          }
        }
      ]
    }
  }
}

### 回答1: Elasticsearch DSL语法是一种用于构建Elasticsearch查询的Python库。它提供了一种简单而强大的方式来构建复杂的查询和聚合操作。DSL语法使用Python的面向对象语法来构建查询,使得代码易于阅读和维护。它支持各种查询类型,包括全文搜索、范围查询、过滤器、聚合等。DSL语法还提供了一些方便的方法来处理查询结果,如分页、排序、高亮等。总之,Elasticsearch DSL语法是一个非常有用的工具,可以帮助开发人员更轻松地构建和执行Elasticsearch查询。 ### 回答2: Elasticsearch DSL是一个基于Python的模块,它允许用户以更加方便的方式与Elasticsearch交互。DSL提供了一种更加简洁和可读的语法,减少了编写Elasticsearch查询的复杂性。DSL语法旨在尽可能地呈现Elasticsearch查询的结构。 DSL的主要语法包括以下几个方面: 1.索引:在DSL中,用户需要指定要查询的索引。例如,要查询名为“movies”的索引,用户应该使用以下语法:Index('movies')。 2.查询:设置检索的查询条件。在DSL中,用户可以使用各种查询类型来设置这些条件,例如term,match,range等。例如,要查询字段“title”等于“The Godfather”的文档,用户可以使用以下代码: from elasticsearch_dsl import Search from elasticsearch_dsl.query import Term s = Search().filter(Term(title='The Godfather')) 3.聚合:查询结果的聚合DSL可以处理的另一个重要方面。用户可以使用各种聚合类型来获得有关查询结果的统计信息,例如总数,平均值,最大值等。例如,要统计字段“rating”的平均值,用户可以使用以下代码: from elasticsearch_dsl import Search from elasticsearch_dsl.aggs import Avg s = Search().agg(Avg('avg_rating', field='rating')) 4.排序:DSL中的排序允许用户根据指定的字段对查询结果进行排序。用户可以使用“sort”方法来设置排序规则,如以下代码所示: from elasticsearch_dsl import Search s = Search().sort('rating') 总之,Elasticsearch DSL语法提供了更强大的、更方便的方式与Elasticsearch进行交互。无论是搜索、聚合还是排序,DSL都可以帮助用户更加简单地构建复杂的查询。 ### 回答3: Elasticsearch DSL(Domain-Specific Language)是 Elasticsearch Python 客户端库实现的一种流畅的Python语法查询语句。Elasticsearch DSL 使Python开发人员能够以简单、易读的方式与 Elasticsearch 进行交互,更加方便地构建复杂的查询语句和聚合操作。下面我将从 dsl 查询语句的特点、基本语法和示例等方面进行详细说明。 Elasticsearch DSL查询语句的特点: 1.以Python方式编写查询语法,更加清晰易读; 2.类似于SQL语句的查询结构,更容易学习和使用; 3.高效的性能和精确的结果,提高了开发效率和用户体验; 4.可以轻松地与Python中的其他库进行集成,增加了开发的灵活性和可扩展性。 Elasticsearch DSL查询语句的基本语法: 1.创建一个查询: from elasticsearch_dsl import Search client = Elasticsearch() # 创建 Elasticsearch 客户端对象 search = Search(using=client) 2.匹配所有文档: search = Search(using=client, index="index_name").query("match_all") 3.匹配查询: search = Search(using=client, index="index_name").query("match", field="value") 4.范围查询: search = Search(using=client, index="index_name").query("range", field={"gte": 10, "lte":20}) 5.多个条件查询: search = Search(using=client, index="index_name").query("bool", must=[Q("match", title="python"), Q("match", content="elasticsearch")]) 6.结果排序和分页查询: search = Search(using=client, index="index_name").query("match", title="python").sort("-date").[0:10] Elasticsearch DSL查询语句示例: 1.查询内容为"python"的文章列表,并按发布时间倒序排序进行分页: s = Search().query("match", title="python").sort("-date").[0:10] response = s.execute() for hit in response: print(hit.title) 2.将通配符查询添加到筛选器列表中: search = Search().filter("wildcard", title="p*").query("match", body="python") response = search.execute() print("Total hits: ", response.hits.total.value) 3.使用子查询搜索不同版本的一个索引: s = Search(index="my-index").query( "bool", must_not=[Q("match", title="python")], should=[Q("match", title="java"), Q("match", title="ruby")] )执行 response = s.execute() print(response.hits.total.value) 总结:Elasticsearch DSL提供了Python化的语法来方便用户进行 Elasticsearch 操作。通过简单的语句即可实现复杂的查询,提高了开发效率和用户体验,开发人员可以很快学会并使用 Elasticsearch DSL
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值