eager_global_ordinals编辑

什么是全局序数?编辑

为了支持聚合和其他需要基于每个文档查找字段值的操作,Elasticsearch 使用一种称为 文档值 的数据结构。基于词条的字段类型(例如 keyword)使用序数映射存储其文档值,以实现更紧凑的表示形式。此映射的工作原理是根据词条的字典顺序为每个词条分配一个递增的整数或_序数_。该字段的文档值仅存储每个文档的序数,而不是原始词条,并使用单独的查找结构在序数和词条之间进行转换。

在聚合期间使用时,序数可以极大地提高性能。例如,terms 聚合仅依赖序数将文档收集到分片级别的桶中,然后在跨分片组合结果时将序数转换回其原始词条值。

每个索引段都定义了自己的序数映射,但聚合会收集整个分片中的数据。因此,为了能够将序数用于分片级操作(如聚合),Elasticsearch 创建了一个称为_全局序数_的统一映射。全局序数映射建立在段序数之上,并通过维护从全局序数到每个段的本地序数的映射来工作。

如果搜索包含以下任何组件,则将使用全局序数

  • keywordipflattened 字段上的某些桶聚合。这包括上面提到的 terms 聚合,以及 compositediversified_samplersignificant_terms
  • text 字段上的桶聚合,需要启用 fielddata
  • 来自 join 字段的父文档和子文档上的操作,包括 has_child 查询和 parent 聚合。

全局序数映射使用堆内存作为 字段数据缓存 的一部分。对高基数字段进行聚合可能会使用大量内存并触发 字段数据断路器

加载全局序数编辑

必须先构建全局序数映射,然后才能在搜索期间使用序数。默认情况下,映射是在第一次需要全局序数时在搜索期间加载的。如果您正在优化索引速度,这是正确的方法,但如果搜索性能是优先事项,则建议在将在聚合中使用的字段上预先加载全局序数

response = client.indices.put_mapping(
  index: 'my-index-000001',
  body: {
    properties: {
      tags: {
        type: 'keyword',
        eager_global_ordinals: true
      }
    }
  }
)
puts response
PUT my-index-000001/_mapping
{
  "properties": {
    "tags": {
      "type": "keyword",
      "eager_global_ordinals": true
    }
  }
}

启用 eager_global_ordinals 后,将在 刷新 分片时构建全局序数 - Elasticsearch 始终在公开对索引内容的更改之前加载它们。这会将构建全局序数的成本从搜索转移到索引时间。Elasticsearch 还会在创建分片的副本时预先构建全局序数,例如在增加副本数量或将分片重新定位到新节点时。

可以通过更新 eager_global_ordinals 设置随时禁用预先加载

response = client.indices.put_mapping(
  index: 'my-index-000001',
  body: {
    properties: {
      tags: {
        type: 'keyword',
        eager_global_ordinals: false
      }
    }
  }
)
puts response
PUT my-index-000001/_mapping
{
  "properties": {
    "tags": {
      "type": "keyword",
      "eager_global_ordinals": false
    }
  }
}

避免全局序数加载编辑

通常,全局序数在其加载时间和内存使用方面不会造成很大的开销。但是,在具有大分片的索引上,或者如果字段包含大量唯一词条值,则加载全局序数的成本可能会很高。因为全局序数为分片上的所有段提供统一映射,所以当新段变得可见时,也需要完全重建它们。

在某些情况下,可以完全避免全局序数加载

  • termssamplersignificant_terms 聚合支持参数 execution_hint,该参数有助于控制如何收集桶。它默认为 global_ordinals,但可以设置为 map 以直接使用词条值。
  • 如果分片已通过 强制合并 到单个段,则其段序数对于分片已经是_全局_的。在这种情况下,Elasticsearch 不需要构建全局序数映射,并且使用全局序数不会产生额外的开销。请注意,出于性能原因,您应该只强制合并您以后永远不会再写入的索引。