元数据字段
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和reindexAPI。 - 在 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 设置是一个以逗号分隔的层级名称列表,按优先顺序排列,即托管索引的首选层级首先列出,后面可能跟随许多备用选项。查询匹配仅考虑第一个优先级(列表的第一个值)。