Elasticsearch使用篇 - 词项聚合、稀有词项聚合、多词项聚合

terms aggregation

即词项分桶聚合。它是 Elasticsearch 最常用的聚合,类同于关系型数据库依据关键字段做 group。

  • size:返回的词项分桶数量,默认 10。阈值 65535。默认情况下,协调节点向每个分片请求 top size 数量的词项桶,并且在所有分片都响应后,将结果进行缩减并返回给客户端。如果实际词项桶的数量大于 size,则返回的词项桶可能会存在偏差并且不准确。

  • shard_size:每个分片返回的词项分桶数量,默认为 size * 1.5 + 10。shard_size 越大,结果越准确,但是最终计算结果的成本也越高(每个分片上的优先级队列会更大,并且节点与客户端之间的数据传输量也更大)。shard_size 不能比 size 小,否则 Elasticsearch 会覆盖该属性值,将其设置为和 size 一样的值。

  • min_doc_count:限制返回的词项分桶中对应文档的命中数量必须满足的最小值,默认 1。

  • shard_min_doc_count:限制每个分片返回的词项分桶中对应文档的命中数量必须满足的最小值,默认 0。必须小于 min_doc_count。建议为 min_doc_count / 分片数。

  • show_term_doc_count_error:显示词项分桶统计数据的错误信息,默认 false。用来显示聚合返回的每个词项的错误值,错误值表示文档计数在最差情况下的错误。这个错误值在决定 shard_size 参数值时非常有用。

  • order:指定排序规则。默认按照 doc_count 逆序排序。

  • missing:指定字段的值不存在时,给予文档的缺省值。默认会忽略。

修改返回的词项分桶的数量的阈值。

PUT _cluster/settings
{
  "transient": {
    "search.max_buckets": 10
  }
}

查询航班目的地最多的 Top 10 国家。

GET kibana_sample_data_flights/_search
{
  "size": 0,
  "aggs": {
    "DestCountry": {
      "terms": {
        "field": "DestCountry",
        "size": 10
      }
    }
  }
}

结果输出如下:

{
  "took" : 38,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10000,
      "relation" : "gte"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "DestCountry" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 3187,
      "buckets" : [
        {
          "key" : "IT",
          "doc_count" : 2371
        },
        {
          "key" : "US",
          "doc_count" : 1987
        },
        {
          "key" : "CN",
          "doc_count" : 1096
        },
        {
          "key" : "CA",
          "doc_count" : 944
        },
        {
          "key" : "JP",
          "doc_count" : 774
        },
        {
          "key" : "RU",
          "doc_count" : 739
        },
        {
          "key" : "CH",
          "doc_count" : 691
        },
        {
          "key" : "GB",
          "doc_count" : 449
        },
        {
          "key" : "AU",
          "doc_count" : 416
        },
        {
          "key" : "PL",
          "doc_count" : 405
        }
      ]
    }
  }
}

词项分桶聚合返回的 doc_count 值是近似的。可以使用参考如下两个指标来判断 doc_count 值是否是准确的。

  • sum_other_doc_count:查询结果中没有出现的所有词项的文档总数。

  • doc_count_error_upper_bound:查询结果中没有出现的词项的最大可能文档数。它的值是所有分片返回的最后一个词项的文档数量的和。当 show_term_doc_count_error 参数设置为 true,可以查看每个词项对应的文档数量的误差。这些误差只有当聚合结果按照文档数降序排序时才会被统计。此外,如果按照词项值本身排序、按照文档数升序或者按照子聚合结果排序都无法统计误差,doc_count_error_upper_bound 会返回 -1。

GET kibana_sample_data_flights/_search
{
  "size": 0,
  "aggs": {
    "DestCountry": {
      "terms": {
        "field": "DestCountry",
        "size": 10,
        "show_term_doc_count_error": true
      }
    }
  }
}

结果输出如下:

{
  "took" : 5,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10000,
      "relation" : "gte"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "DestCountry" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 3187,
      "buckets" : [
        {
          "key" : "IT",
          "doc_count" : 2371,
          "doc_count_error_upper_bound" : 0
        },
        {
          "key" : "US",
          "doc_count" : 1987,
          "doc_count_error_upper_bound" : 0
        },
        {
          "key" : "CN",
          "doc_count" : 1096,
          "doc_count_error_upper_bound" : 0
        },
        {
          "key" : "CA",
          "doc_count" : 944,
          "doc_count_error_upper_bound" : 0
        },
        {
          "key" : "JP",
          "doc_count" : 774,
          "doc_count_error_upper_bound" : 0
        },
        {
          "key" : "RU",
          "doc_count" : 739,
          "doc_count_error_upper_bound" : 0
        },
        {
          "key" : "CH",
          "doc_count" : 691,
          "doc_count_error_upper_bound" : 0
        },
        {
          "key" : "GB",
          "doc_count" : 449,
          "doc_count_error_upper_bound" : 0
        },
        {
          "key" : "AU",
          "doc_count" : 416,
          "doc_count_error_upper_bound" : 0
        },
        {
          "key" : "PL",
          "doc_count" : 405,
          "doc_count_error_upper_bound" : 0
        }
      ]
    }
  }
}

排序

默认按照 doc_count 逆序排序。不推荐按照 doc_count 升序排序或者在子聚合中排序,这会增加统计文档数量的错误。但是如果在单一分片或者聚合使用的字段在索引时用做路由键,这两种情况下却是准确的。

_count:按照数量排序,默认的排序方式。

_key:按照词项排序。

_term: 按照词项排序。

按照文档数量的升序排序。

GET kibana_sample_data_flights/_search
{
  "size": 0,
  "aggs": {
    "DestCountry": {
      "terms": {
        "field": "DestCountry",
        "size": 10,
        "show_term_doc_count_error": true,
        "order": {
          "_count": "asc"
        }
      }
    }
  }
}

按照 key 的字母顺序升序排序。

GET kibana_sample_data_flights/_search
{
  "size": 0,
  "aggs": {
    "DestCountry": {
      "terms": {
        "field": "DestCountry",
        "size": 10,
        "show_term_doc_count_error": true,
        "order": {
          "_key": "asc"
        }
      }
    }
  }
}

查询航班飞行最短的 Top 10 国家。

GET kibana_sample_data_flights/_search
{
  "size": 0,
  "aggs": {
    "DestCountry": {
      "terms": {
        "field": "DestCountry",
        "size": 10,
        "order": {
          "min_FlightTimeMin": "desc"
        }
      },
      "aggs": {
        "min_FlightTimeMin": {
          "min": {
            "field": "FlightTimeMin"
          }
        }
      }
    }
  }
}
GET kibana_sample_data_flights/_search
{
  "size": 0,
  "aggs": {
    "DestCountry": {
      "terms": {
        "field": "DestCountry",
        "size": 10,
        "order": {
          "stats_FlightTimeMin.max": "desc"
        }
      },
      "aggs": {
        "stats_FlightTimeMin": {
          "stats": {
            "field": "FlightTimeMin"
          }
        }
      }
    }
  }
}

词项嵌套分桶

嵌套深度建议不要超过三层。

GET kibana_sample_data_flights/_search
{
  "size": 0,
  "aggs": {
    "DestCountry": {
      "terms": {
        "field": "DestCountry",
        "size": 10,
        "show_term_doc_count_error": true
      },
      "aggs": {
        "OriginCountry": {
          "terms": {
            "field": "OriginCountry",
            "size": 10
          }
        }
      }
    }
  }
}

脚本方式

GET kibana_sample_data_flights/_search
{
  "size": 0,
  "aggs": {
    "DestCountry": {
      "terms": {
        "script": {
          "source": """
            doc['DestCountry'].value + "-DEMO";
          """,
          "lang": "painless"
        },
        "size": 10
      }
    }
  }
}

结果输出如下:

{
  "took" : 56,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10000,
      "relation" : "gte"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "DestCountry" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 3187,
      "buckets" : [
        {
          "key" : "IT-DEMO",
          "doc_count" : 2371
        },
        {
          "key" : "US-DEMO",
          "doc_count" : 1987
        },
        {
          "key" : "CN-DEMO",
          "doc_count" : 1096
        },
        {
          "key" : "CA-DEMO",
          "doc_count" : 944
        },
        {
          "key" : "JP-DEMO",
          "doc_count" : 774
        },
        {
          "key" : "RU-DEMO",
          "doc_count" : 739
        },
        {
          "key" : "CH-DEMO",
          "doc_count" : 691
        },
        {
          "key" : "GB-DEMO",
          "doc_count" : 449
        },
        {
          "key" : "AU-DEMO",
          "doc_count" : 416
        },
        {
          "key" : "PL-DEMO",
          "doc_count" : 405
        }
      ]
    }
  }
}

词项分桶键值过滤

支持精确键值过滤与模糊匹配方式(通过正则表达式)过滤。个人发现 Elasticsearch 7.14 版本模糊匹配方式实际操作中不生效。

  • include:包括指定的词项分桶值。
  • exclude:不包括指定的词项分桶值。
GET kibana_sample_data_flights/_search
{
  "size": 0,
  "aggs": {
    "DestCountry": {
      "terms": {
        "field": "DestCountry",
        "size": 10,
        "show_term_doc_count_error": true,
        "include": ["US", "IT", "CN"]
      }
    }
  }
}

结果输出如下:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10000,
      "relation" : "gte"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "DestCountry" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "IT",
          "doc_count" : 2371,
          "doc_count_error_upper_bound" : 0
        },
        {
          "key" : "US",
          "doc_count" : 1987,
          "doc_count_error_upper_bound" : 0
        },
        {
          "key" : "CN",
          "doc_count" : 1096,
          "doc_count_error_upper_bound" : 0
        }
      ]
    }
  }
}

词项分桶分区聚合

很多时候需要统计的分桶数量太多,导致一次运行很慢。可以借助分区机制,在客户端进行合并。对所有可能的分桶进行分区。

partition:分区编号。从 0 开始。

num_partitions:分区数量。

GET kibana_sample_data_flights/_search
{
  "size": 0,
  "aggs": {
    "DestCountry": {
      "terms": {
        "field": "DestCountry",
        "size": 10,
        "show_term_doc_count_error": true,
        "include": {
          "partition": 2,
          "num_partitions": 5
        }
      }
    }
  }
}

Elasticsearch 是一个基于 Lucene 的分布式、RESTful 搜索和分析引擎,其核心检索机制围绕**倒排索引(Inverted Index)**和**分布式查询处理**展开。以下是其检索机制和使用方法的详细说明: --- ### **1. Elasticsearch 检索机制** #### **(1)倒排索引(Inverted Index)** - **核心原理**: - 将文档(Document)拆分为**(Term)**,并记录每个出现在哪些文档中(类似字典的“→文档列表”映射)。 - 例如:文档1包含“苹果 香蕉”,文档2包含“苹果 橙子”,倒排索引为: ``` 苹果 → [文档1, 文档2] 香蕉 → [文档1] 橙子 → [文档2] ``` - **优势**: - 快速定位包含特定的文档,避免全表扫描。 - 支持高效布尔查询(AND/OR/NOT)。 #### **(2)分布式查询处理** - **分片(Shard)**: - 索引(Index)被划分为个分片(默认5个主分片),分布在集群的不同节点上。 - 查询时,协调节点(Coordinating Node)将请求广播到所有相关分片,并行处理后合并结果。 - **流程**: 1. 用户发送查询请求到任意节点(协调节点)。 2. 协调节点确定查询涉及的分片,并转发请求。 3. 各分片本地执行查询,返回结果(含文档ID和评分)。 4. 协调节点合并结果,按相关性排序后返回。 #### **(3)相关性评分(TF-IDF & BM25)** - **TF-IDF**: - 频(TF):在文档中出现的频率。 - 逆文档频率(IDF):在所有文档中的稀有程度(常见权重低)。 - **BM25(默认算法)**: - 改进TF-IDF,考虑文档长度、频率饱和度等因素,评分更精准。 - **示例**: - 查询“苹果 手机”时,同时包含两个的文档评分更高。 #### **(4)实时性与近实时(NRT)** - **倒排索引不可变**: - 新增文档写入新索引段(Segment),定期合并(Merge)到主索引。 - **近实时(NRT)**: - 文档写入后约1秒可被搜索(通过`refresh_interval`配置,默认1秒)。 - 完全持久化需`flush`操作(将内存数据刷到磁盘)。 --- ### **2. Elasticsearch 使用方法** #### **(1)基础操作** ##### **① 索引文档** ```json PUT /products/_doc/1 { "name": "iPhone 13", "price": 799, "description": "高性能智能手机", "tags": ["苹果", "手机"] } ``` - **说明**: - `products`:索引名(类似数据库表)。 - `_doc`:类型(7.x+版本默认单类型)。 - `1`:文档ID(可省略,自动生成)。 ##### **② 简单查询** ```json GET /products/_search { "query": { "match": { "name": "iPhone" } } } ``` - **返回结果**: ```json { "hits": { "hits": [ { "_id": "1", "_score": 0.2876821, // BM25评分 "_source": { "name": "iPhone 13", "price": 799 } } ] } } ``` ##### **③ 布尔查询(AND/OR/NOT)** ```json GET /products/_search { "query": { "bool": { "must": [ { "match": { "tags": "苹果" } } ], "filter": [ { "range": { "price": { "lte": 1000 } } } // 价格≤1000 ] } } } ``` #### **(2)高级功能** ##### **① 全文检索(分析文本)** - **分器(Analyzer)**: - 默认使用`standard`分器(按空格分,小写化)。 - 自定义分器示例: ```json PUT /my_index { "settings": { "analysis": { "analyzer": { "my_analyzer": { "type": "custom", "tokenizer": "standard", "filter": ["lowercase", "asciifolding"] // 小写+去除重音 } } } } } ``` ##### **② 聚合查询(Aggregation)** ```json GET /products/_search { "size": 0, // 不返回文档,仅聚合结果 "aggs": { "avg_price": { "avg": { "field": "price" } }, "tags_count": { "terms": { "field": "tags.keyword" } // 对精确值聚合 } } } ``` - **结果**: ```json { "aggregations": { "avg_price": { "value": 799 }, "tags_count": { "buckets": [ { "key": "苹果", "doc_count": 1 }, { "key": "手机", "doc_count": 1 } ] } } } ``` ##### **③ 高亮显示(Highlight)** ```json GET /products/_search { "query": { "match": { "description": "智能" } }, "highlight": { "fields": { "description": {} } } } ``` - **返回结果**: ```json { "hits": { "hits": [ { "_source
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值