元数据字段
edit元数据字段
edit每个文档都有与之关联的元数据,例如 _index
和 _id
元数据字段。在创建映射时,可以自定义其中一些元数据字段的行为。
身份元数据字段
edit文档源元数据字段
edit-
_source
- 表示文档正文的原始JSON。
-
_size
-
_source
字段的大小(以字节为单位),由mapper-size
插件提供。
文档计数元数据字段
edit-
_doc_count
- 用于存储文档计数时,当文档表示预聚合数据的字段。
索引元数据字段
edit-
_field_names
- 文档中包含非空值的所有字段。
-
_ignored
-
在索引时由于
ignore_malformed
而被忽略的文档中的所有字段。
路由元数据字段
edit-
_routing
- 自定义路由值,用于将文档路由到特定分片。
其他元数据字段
edit_doc_count
字段
edit桶聚合总是返回一个名为 doc_count
的字段,显示每个桶中聚合和分区的文档数量。doc_count
的值的计算非常简单。对于每个桶中收集的每个文档,doc_count
都会增加1。
虽然这种简单的方法在计算单个文档的聚合时是有效的,但它无法准确表示存储预聚合数据的文档(例如 histogram
或 aggregate_metric_double
字段),因为一个摘要字段可能代表多个文档。
为了在使用预聚合数据时正确计算文档数量,我们引入了一个名为 _doc_count
的元数据字段类型。_doc_count
必须始终是一个表示单个汇总字段中聚合文档数量的正整数。
当字段 _doc_count
被添加到文档中时,所有桶聚合将尊重其值并根据该字段的值增加桶 doc_count
。如果文档不包含任何 _doc_count
字段,则默认隐含 _doc_count = 1
。
-
一个
_doc_count
字段每个文档只能存储一个正整数。不允许嵌套数组。 -
如果一个文档不包含
_doc_count
字段,聚合器将增加1,这是默认行为。
示例
edit以下创建索引 API 请求创建了一个新的索引,并包含以下字段映射:
-
my_histogram
,一个用于存储百分位数据的histogram
字段 -
my_text
,一个用于存储直方图标题的keyword
字段
PUT my_index { "mappings" : { "properties" : { "my_histogram" : { "type" : "histogram" }, "my_text" : { "type" : "keyword" } } } }
以下索引 API 请求存储了两个直方图的预聚合数据:histogram_1
和 histogram_2
。
PUT my_index/_doc/1 { "my_text" : "histogram_1", "my_histogram" : { "values" : [0.1, 0.2, 0.3, 0.4, 0.5], "counts" : [3, 7, 23, 12, 6] }, "_doc_count": 45 } PUT my_index/_doc/2 { "my_text" : "histogram_2", "my_histogram" : { "values" : [0.1, 0.25, 0.35, 0.4, 0.45, 0.5], "counts" : [8, 17, 8, 7, 6, 2] }, "_doc_count": 62 }
如果我们对my_index
运行以下terms aggregation:
GET /_search { "aggs" : { "histogram_titles" : { "terms" : { "field" : "my_text" } } } }
我们将得到以下响应:
{ ... "aggregations" : { "histogram_titles" : { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets" : [ { "key" : "histogram_2", "doc_count" : 62 }, { "key" : "histogram_1", "doc_count" : 45 } ] } } }
_field_names
字段
edit_field_names
字段用于索引文档中包含除 null
以外的任何值的每个字段的名称。该字段曾被 exists
查询用来查找具有或不具有特定字段的任何非 null
值的文档。
现在,_field_names
字段仅索引那些已禁用 doc_values
和 norms
的字段的名称。对于启用了 doc_values
或 norm
的字段,exists
查询仍然可用,但不会使用 _field_names
字段。
禁用 _field_names
edit禁用 _field_names
不再可能。它现在默认启用,因为它不再带来曾经有的索引开销。
已移除对禁用 _field_names
的支持。在新索引上使用它将抛出错误。在8.0之前的索引上使用它仍然允许,但会发出弃用警告。
_ignored
字段
edit_ignored
字段索引并存储了文档中被忽略的每个字段的名称,当文档被索引时,这些字段被忽略。例如,当字段格式错误并且 ignore_malformed
被启用时,或者当 keyword
字段的值超过了其可选的 ignore_above
设置时,或者当达到 index.mapping.total_fields.limit
并且 index.mapping.total_fields.ignore_dynamic_beyond_limit
设置为 true
时。
此字段可以通过 term
、
terms
和 exists
查询进行搜索,并且作为搜索结果的一部分返回。
例如,以下查询匹配所有具有一个或多个被忽略字段的文档:
GET _search { "query": { "exists": { "field": "_ignored" } } }
同样,下面的查询会找到所有在索引时被忽略的@timestamp
字段的文档:
GET _search { "query": { "term": { "_ignored": "@timestamp" } } }
自8.15.0版本起,_ignored
字段也支持聚合操作。
例如,以下查询可以找到所有被忽略的字段:
GET _search { "aggs": { "ignored_fields": { "terms": { "field": "_ignored" } } } }
_id
字段
edit每个文档都有一个唯一的_id
,该ID被索引,因此可以使用GET API或ids
查询来查找文档。_id
可以在索引时分配,或者由Elasticsearch生成一个唯一的_id
。此字段在映射中不可配置。
在诸如 term
、terms
、match
和 query_string
的查询中,_id
字段的值是可访问的。
# Example documents PUT my-index-000001/_doc/1 { "text": "Document with ID 1" } PUT my-index-000001/_doc/2?refresh=true { "text": "Document with ID 2" } GET my-index-000001/_search { "query": { "terms": { "_id": [ "1", "2" ] } } }
在 |
_id
字段在聚合、排序和脚本中受到限制。
如果需要对 _id
字段进行排序或聚合,建议将 _id
字段的内容复制到另一个启用了 doc_values
的字段中。
_id
的大小限制为512字节,超过此大小的值将被拒绝。
_index
字段
edit在跨多个索引执行查询时,有时希望添加仅与某些索引的文档相关的查询子句。
_index
字段允许匹配文档所索引到的索引。
它的值可以在某些查询和聚合中访问,并且在排序或脚本编写时也可以使用:
PUT index_1/_doc/1 { "text": "Document in index 1" } PUT index_2/_doc/2?refresh=true { "text": "Document in index 2" } GET index_1,index_2/_search { "query": { "terms": { "_index": ["index_1", "index_2"] } }, "aggs": { "indices": { "terms": { "field": "_index", "size": 10 } } }, "sort": [ { "_index": { "order": "asc" } } ], "script_fields": { "index_name": { "script": { "lang": "painless", "source": "doc['_index']" } } } }
_index
字段实际上是暴露出来的——它不会作为真实字段添加到 Lucene 索引中。这意味着你可以在 term
或 terms
查询(或任何重写为 term
查询的查询,例如 match
、query_string
或 simple_query_string
查询)中使用 _index
字段,以及 prefix
和 wildcard
查询。然而,它不支持 regexp
和 fuzzy
查询。
对_index
字段的查询除了具体的索引名称外,还接受索引别名。
当指定一个远程索引名称时,例如 cluster_1:index_3
,查询必须包含分隔符字符 :
。例如,在 cluster_*:index_3
上的 wildcard
查询将匹配来自远程索引的文档。然而,在 cluster*index_1
上的查询只会匹配本地索引,因为没有分隔符。此行为与远程索引名称的通常解析规则一致。
_meta
字段
edit映射类型可以具有与其关联的自定义元数据。这些元数据完全不由Elasticsearch使用,但可以用于存储特定于应用程序的元数据,例如文档所属的类:
PUT my-index-000001 { "mappings": { "_meta": { "class": "MyApp::User", "version": { "min": "1.0", "max": "1.3" } } } }
这个 |
可以使用更新映射 API 在现有类型上更新 _meta
字段:
PUT my-index-000001/_mapping { "_meta": { "class": "MyApp2::User3", "version": { "min": "1.3", "max": "1.5" } } }
_routing
字段
edit文档通过以下公式路由到索引中的特定分片:
routing_factor = num_routing_shards / num_primary_shards shard_num = (hash(_routing) % num_routing_shards) / routing_factor
num_routing_shards
是索引设置 index.number_of_routing_shards
的值。num_primary_shards
是索引设置 index.number_of_shards
的值。
默认的 _routing
值是文档的 _id
。
可以通过为每个文档指定自定义的 routing
值来实现自定义路由模式。例如:
PUT my-index-000001/_doc/1?routing=user1&refresh=true { "title": "This is a document" } GET my-index-000001/_doc/1?routing=user1
在查询中可以访问_routing
字段的值:
在 |
数据流不支持自定义路由,除非它们是在模板中启用了allow_custom_routing
设置的情况下创建的。
使用自定义路由进行搜索
edit自定义路由可以减少搜索的影响。与其将搜索请求分发到索引中的所有分片,请求可以仅发送到与特定路由值(或多个值)匹配的分片:
使路由值成为必需
edit在使用自定义路由时,在索引、获取、 删除或更新文档时,提供路由值非常重要。
忘记路由值可能会导致文档被索引到多个分片上。作为一种安全措施,可以配置_routing
字段,使自定义的routing
值成为所有CRUD操作的必需项:
使用自定义路由的唯一ID
edit当索引文档指定自定义的_routing
时,_id
在整个索引的所有分片中并不保证唯一性。实际上,如果使用不同的_routing
值进行索引,具有相同_id
的文档可能会最终位于不同的分片上。
确保索引中的ID唯一性是用户的责任。
路由到索引分区
edit可以配置索引,使得自定义路由值将指向分片的一个子集,而不是单个分片。这有助于在减少搜索影响的同时,降低集群不平衡的风险。
这是通过在索引创建时提供索引级别设置 index.routing_partition_size
来完成的。
随着分区大小的增加,数据将更均匀地分布,但代价是每次请求需要搜索更多的分片。
当此设置存在时,计算分片的公式变为:
routing_value = hash(_routing) + hash(_id) % routing_partition_size shard_num = (routing_value % num_routing_shards) / routing_factor
也就是说,_routing
字段用于计算索引中的一组分片,然后使用 _id
从该组中选择一个分片。
要启用此功能,index.routing_partition_size
的值应大于 1 且小于 index.number_of_shards
。
一旦启用,分区索引将具有以下限制:
-
不能在其中创建具有
join
字段关系的映射。 -
索引中的所有映射都必须将
_routing
字段标记为必需。
_source
字段
editThe _source
字段包含在索引时传递的原始 JSON 文档主体。_source
字段本身未被索引(因此不可搜索),但它被存储以便在执行 fetch 请求时返回,例如 get 或 search。
如果磁盘使用对你很重要,那么请考虑以下选项:
-
使用合成
_source
,它在检索时重建源内容,而不是将其存储在磁盘上。这减少了磁盘使用,但代价是Get和Search查询中访问_source
的速度较慢。 -
完全禁用
_source
字段。这减少了磁盘使用,但禁用了依赖于_source
的功能。
合成 _source
edit合成 _source
仅对 TSDB 索引(将 index.mode
设置为 time_series
的索引)正式发布。对于其他索引,合成 _source
处于技术预览阶段。技术预览中的功能可能会在未来的版本中更改或移除。Elastic 将努力修复任何问题,但技术预览中的功能不受官方 GA 功能支持 SLA 的约束。
尽管非常方便,但源字段占用了磁盘上相当大的空间。与其完全按照发送的方式将源文档存储在磁盘上,Elasticsearch可以在检索时即时重建源内容。通过将索引设置index.mapping.source.mode
的值设置为synthetic
来启用此功能:
PUT idx { "settings": { "index": { "mapping": { "source": { "mode": "synthetic" } } } } }
虽然这种即时重建通常比直接保存源文档并在查询时加载它们要慢,但它节省了大量的存储空间。当不需要时,可以通过不在查询中加载_source
字段来避免额外的延迟。
支持的字段
edit所有字段类型都支持合成 _source
。根据实现细节,字段类型在使用合成 _source
时具有不同的属性。
大多数字段类型使用现有数据构建合成的_source
,最常见的是doc_values
和存储字段。对于这些字段类型,不需要额外的空间来存储_source
字段的内容。由于doc_values
的存储布局,生成的_source
字段与原始文档相比会经历修改。
对于所有其他字段类型,字段的原始值按原样存储,与非合成模式下的_source
字段存储方式相同。在这种情况下,没有进行任何修改,_source
中的字段数据与原始文档中的数据相同。同样,使用ignore_malformed
或ignore_above
的错误格式字段值也需要按原样存储。这种方法的存储效率较低,因为除了用于索引字段所需的其他数据(如doc_values
)外,还需要存储用于_source
重建的数据。
合成 _source
修改
edit当启用了合成 _source
时,检索到的文档与原始 JSON 相比会经历一些修改。
数组移动到叶子字段
edit合成的 _source
数组被移动到叶子节点。例如:
PUT idx/_doc/1 { "foo": [ { "bar": 1 }, { "bar": 2 } ] }
将变为:
{ "foo": { "bar": [1, 2] } }
这可能导致某些数组消失:
PUT idx/_doc/1 { "foo": [ { "bar": 1 }, { "baz": 2 } ] }
将变为:
{ "foo": { "bar": 1, "baz": 2 } }
字段按映射命名
edit合成源名称字段,如它们在映射中的命名。当与动态映射一起使用时,默认情况下,名称中带有点 (.
) 的字段会被解释为多个对象,而字段名称中的点在禁用子对象
的对象中会被保留。例如:
PUT idx/_doc/1 { "foo.bar.baz": 1 }
将变为:
{ "foo": { "bar": { "baz": 1 } } }
这影响了在脚本中如何引用源内容。例如,以原始源形式引用脚本将返回null:
"script": { "source": """ emit(params._source['foo.bar.baz']) """ }
相反,源引用需要与映射结构保持一致:
"script": { "source": """ emit(params._source['foo']['bar']['baz']) """ }
或简单地
"script": { "source": """ emit(params._source.foo.bar.baz) """ }
以下字段API是首选的,因为除了对映射结构不敏感外,它们还会在可用时使用doc值,并且仅在需要时才回退到合成源。这减少了源合成,这是一个缓慢且代价高昂的操作。
"script": { "source": """ emit(field('foo.bar.baz').get(null)) """ } "script": { "source": """ emit($('foo.bar.baz', null)) """ }
按字母顺序排序
edit合成的 _source
字段按字母顺序排序。
JSON RFC 将对象定义为
“一个由零个或多个名称/值对组成的无序集合”,因此应用程序不应该关心顺序,但在没有合成 _source
的情况下,原始顺序被保留,一些应用程序可能会违反规范,根据顺序执行某些操作。
最小化源代码修改
edit可以通过额外的存储成本来避免对特定对象或字段进行合成源修改。
这是通过参数 synthetic_source_keep
控制的,具有以下选项:
-
none
: 合成源与原始源如上所述不同(默认)。 -
arrays
: 相应字段或对象的数组保留原始元素顺序和重复元素。 此类数组的合成源片段不保证与原始源完全匹配,例如数组[1, 2, [5], [[4, [3]]], 5]
可能按原样显示或以等效格式显示,如[1, 2, 5, 4, 3, 5]
。确切格式 可能会在未来发生变化,以减少此选项的存储开销。 -
all
: 记录单例实例和相应字段或对象数组的源。当 应用于对象时,捕获所有子对象和子字段的源。此外,捕获数组的原始源并按原样显示在合成源中。
例如:
PUT idx_keep { "settings": { "index": { "mapping": { "source": { "mode": "synthetic" } } } }, "mappings": { "properties": { "path": { "type": "object", "synthetic_source_keep": "all" }, "ids": { "type": "integer", "synthetic_source_keep": "arrays" } } } }
PUT idx_keep/_doc/1 { "path": { "to": [ { "foo": [3, 2, 1] }, { "foo": [30, 20, 10] } ], "bar": "baz" }, "ids": [ 200, 100, 300, 100 ] }
返回原始源,不进行数组去重和排序:
{ "path": { "to": [ { "foo": [3, 2, 1] }, { "foo": [30, 20, 10] } ], "bar": "baz" }, "ids": [ 200, 100, 300, 100 ] }
捕获数组源的选项可以在索引级别应用,通过将index.mapping.synthetic_source_keep
设置为arrays
。这适用于索引中的所有对象和字段,除了那些明确将synthetic_source_keep
设置为none
的对象和字段。在这种情况下,存储开销会随着每个文档源中存在的数组的数量和大小自然增长。
支持无存储开销的合成源的字段类型
edit以下字段类型支持使用来自doc_values
或存储字段的数据合成源,并且不需要额外的存储空间来构建_source
字段。
如果您启用了ignore_malformed
或ignore_above
设置,那么需要额外的存储空间来存储这些类型中被忽略的字段值。
禁用_source
字段
edit尽管非常方便,但源字段确实会在索引中产生存储开销。出于这个原因,可以按如下方式禁用它:
PUT my-index-000001 { "mappings": { "_source": { "enabled": false } } }
在禁用_source
字段之前请三思
用户常常在未考虑后果的情况下禁用_source
字段,然后为此感到后悔。如果_source
字段不可用,那么许多功能将不受支持:
-
update
、update_by_query
和reindex
API。 - 在 Kibana Discover 应用程序中,字段数据将不会显示。
- 即时 高亮。
- 能够从一个 Elasticsearch 索引重新索引到另一个索引,无论是为了更改映射或分析,还是为了将索引升级到新的主要版本。
- 通过查看索引时使用的原始文档来调试查询或聚合的能力。
- 可能在将来,自动修复索引损坏的能力。
如果磁盘空间是一个问题,可以增加
压缩级别 而不是禁用 _source
。
从_source
中包含/排除字段
edit一个仅限专家使用的功能是能够在文档被索引之后、但在存储_source
字段之前,修剪_source
字段的内容。
从 _source
中移除字段与禁用 _source
有类似的缺点,特别是你无法将文档从一个 Elasticsearch 索引重新索引到另一个索引。建议考虑使用 source filtering 替代。
可以使用includes
/excludes
参数(也接受通配符),如下所示:
PUT logs { "mappings": { "_source": { "includes": [ "*.count", "meta.*" ], "excludes": [ "meta.description", "meta.other.*" ] } } } PUT logs/_doc/1 { "requests": { "count": 10, "foo": "bar" }, "meta": { "name": "Some metric", "description": "Some metric description", "other": { "foo": "one", "baz": "two" } } } GET logs/_search { "query": { "match": { "meta.other.foo": "one" } } }
_tier
字段
edit在跨多个索引执行查询时,有时希望针对位于给定数据层节点上的索引(data_hot
、data_warm
、data_cold
或 data_frozen
)。
_tier
字段允许匹配文档所索引到的索引的 tier_preference
设置。
首选值在某些查询中是可访问的:
PUT index_1/_doc/1 { "text": "Document in index 1" } PUT index_2/_doc/2?refresh=true { "text": "Document in index 2" } GET index_1,index_2/_search { "query": { "terms": { "_tier": ["data_hot", "data_warm"] } } }
通常,查询会使用terms
查询来列出感兴趣的层级,但您可以在任何重写为term
查询的查询中使用_tier
字段,例如match
、query_string
、term
、terms
或simple_query_string
查询,以及prefix
和wildcard
查询。然而,它不支持regexp
和fuzzy
查询。
索引的 tier_preference
设置是一个以逗号分隔的层级名称列表,按优先顺序排列,即托管索引的首选层级首先列出,后面可能跟随许多备用选项。查询匹配仅考虑第一个优先级(列表的第一个值)。