4-2-Elasticsearch:Metadata fields - 元数据字段介绍

熊 0 阅读 日志平台

每个文档都有与之关联的元数据 , 例如_index和_id元数据字段。 创建映射时 , 可以自定义其中一些元数据字段的行为。比如我们创建如下的一个文档:

PUT test
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "message": {
        "type": "text"
      }
    }
  }
}
 
PUT test/_doc/1
{
  "id": "1234",
  "message": "This is so lovely"
}

上面的最后一个命令的返回信息如下:

{
  "_index" : "test",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

从上面的响应中 , 我们可以看出来_index字段为 test , 而 _id 为1。这个是上述文档的身份元数据字段:

1. 身份元数据字段

字段

含义

_index

文档所属的索引。

_id

文档的 ID。

2. 文档源元数据字段

字段

含义

_source

表示文档正文的原始 JSON。

_size

_source字段的大小(以字节为单位) , 由 mapper-size 插件提供。

要获得_size元数据 , 你必须按照上面表格中的链接按照mapper-size插件 , 并重新启动Elasticsearch。我们做如下的练习:

DELETE test
 
PUT test
{
  "mappings": {
    "_size": {
      "enabled": true
    },
    "properties": {
      "id": {
        "type": "keyword"
      },
      "message": {
        "type": "text"
      }
    }
  }
}
 
PUT test/_doc/1
{
  "id": "1234",
  "message": "This is so lovely"
}

在上面 , 我们在mappings里启动 _size。我们写入一个文档后 , 我们可以做如下的搜索:

GET test/_search?filter_path=**.hits
{
  "query": {
    "range": {
      "_size": {
        "gte": 10
      }
    }
  },
  "fields": [
    "_size"
  ]
}

上面的命令返回的结果为:

{
  "hits" : {
    "hits" : [
      {
        "_index" : "test",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "id" : "1234",
          "message" : "This is so lovely"
        },
        "fields" : {
          "_size" : [
            53
          ]
        }
      }
    ]
  }
}

从上面 , 我们可以看出来_size这个元数据以及_source所表达的源文件数据。

3. 文档计数元数据字段

字段

含义

_doc_count

当文档表示预聚合(pre-aggregation)数据时 , 用于存储文档计数的自定义字段。

桶聚合总是返回一个名为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 , 这是默认行为。

例子

以下创建索引 API请求创建具有以下字段映射的新索引:

PUT my_index
{
  "mappings" : {
    "properties" : {
      "my_histogram" : {
        "type" : "histogram"
      },
      "my_text" : {
        "type" : "keyword"
      }
    }
  }
}

以下 index 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 
}

请注意上面的_doc_count的定义。它必须是一个正整数 , 存储为生成每个直方图而聚合的文档数。

如果我们在my_index上运行以下术语聚合:

GET my_index/_search?filter_path=aggregations
{
  "size": 0,
  "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
        }
      ]
    }
  }
}

4. 索引元数据字段

字段

含义

_field_names

档中包含非空值的所有字段。

_ignored

由于 ignore_malformed 而在索引时被忽略的文档中的所有字段。

_field_names字段用于索引文档中包含除 null 之外的任何值的每个字段的名称。exists查询使用此字段来查找具有或不具有特定字段的任何非空值的文档。

现在_field_names字段仅索引禁用了doc_values 和 norms 的字段的名称。 对于启用了doc_values或norm的字段 , exists 查询仍然可用 , 但不会使用_field_names字段。

我们还是拿先前的例子来做展示:

DELETE test
 
PUT test
{
  "mappings": {
    "_size": {
      "enabled": true
    },
    "properties": {
      "id": {
        "type": "keyword",
        "doc_values": true
      },
      "message": {
        "type": "text",
        "norms": false
      }
    }
  }
}
 
PUT test/_doc/1
{
  "id": "1234",
  "message": "This is so lovely"
}

我们对上面的文档进行搜索:

GET test/_search?filter_path=**.hits
{
  "query": {
    "match": {
      "_field_names": "id"
    }
  }
}

由于id字段的doc_values是启动的 , 那么如下的查询:

GET test/_search?filter_path=**.hits
{
  "query": {
    "match": {
      "_field_names": "id"
    }
  }
}

返回:

{
  "hits" : {
    "hits" : [ ]
  }
}

我们再查询:

GET test/_search?filter_path=**.hits
{
  "query": {
    "match": {
      "_field_names": "message"
    }
  }
}

返回:

{
  "hits" : {
    "hits" : [
      {
        "_index" : "test",
        "_id" : "1",
        "_score" : 0.2876821,
        "_source" : {
          "id" : "1234",
          "message" : "This is so lovely"
        }
      }
    ]
  }
}

我们可以使用如下的查询:

GET test/_search?filter_path=**.hits
{
  "query": {
    "exists": {
      "field": "message"
    }
  }
}
 
GET test/_search?filter_path=**.hits
{
  "query": {
    "exists": {
      "field": "id"
    }
  }
}

上面的两个凌乱都将返回:

{
  "hits" : {
    "hits" : [
      {
        "_index" : "test",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "id" : "1234",
          "message" : "This is so lovely"
        }
      }
    ]
  }
}

5. 路由元数据字段

字段

含义

_routing

将文档路由到特定分片的自定义路由值。

使用以下公式将文档路由到索引中的特定分片:

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。 自定义路由模式可以通过为每个文档指定自定义路由值来实现。 例如:

PUT my-index-000001/_doc/1?routing=user1&refresh=true 
{
  "title": "This is a document"
}
 
GET my-index-000001/_doc/1?routing=user1

在上面 , 我们使用user1作为路由值而不是文档的_id 值。当我们想更新 , 获取或者删除该文档时 , 我们需要使用同样的路由值。

_routing字段的值可在查询中访问 ,

GET my-index-000001/_search?filter_path=**.hits
{
  "query": {
    "terms": {
      "_routing": [ "user1" ] 
    }
  }
}

上面的命令的结果为:

{
  "hits" : {
    "hits" : [
      {
        "_index" : "my-index-000001",
        "_id" : "1",
        "_score" : 1.0,
        "_routing" : "user1",
        "_source" : {
          "title" : "This is a document"
        }
      }
    ]
  }
}

6. 使用自定义路由搜索

自定义路由可以减少搜索的影响。 不必将搜索请求大面积地发送到索引中的所有分片 , 而是可以将请求仅发送到与特定路由值(或值)匹配的分片:

GET my-index-000001/_search?routing=user1,user2 
{
  "query": {
    "match": {
      "title": "document"
    }
  }
}

此搜索请求将仅在与user1和user2路由值关联的分片上执行。

7. 使路由值成为必需

使用自定义路由时 , 在索引、获取、删除或更新文档时提供路由值非常重要。

忘记路由值可能导致文档在多个分片上被索引。 作为保障 , 可以配置_routing字段以使所有CRUD操作都需要自定义路由值:

PUT my-index-000002
{
  "mappings": {
    "_routing": {
      "required": true 
    }
  }
}
 
PUT my-index-000002/_doc/1 
{
  "text": "No routing value provided"
}

在上面索引中 , 我们定义_routing是必须的。在下面的命令中 , 由于我们在请求中没有指定 _routing参数 , 那么它将抛出 routing_missing_exception错误。

8. 其它元数据字段

字段

含义

_meta

应用程序特定的元数据。

_tier

文档所属索引的当前数据层首选项。

9. _tier 字段

在跨多个索引执行查询时 , 有时需要针对给定数据层(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"] 
    }
  }
}

在上面的查询中 , 我们对data_hot及 data_warm数据层中的数据进行统计。

通常 , 查询将使用术语查询来列出感兴趣的层(tier) , 但你可以在任何重写为术语查询的查询中使用 _tier 字段 , 例如 match、query_string、term、terms 或 simple_query_string 查询 , 以及 前缀和通配符查询。 但是 , 它不支持正则表达式和模糊查询。

索引的 tier_preference 设置是按优先顺序排列的层名称的逗号分隔列表 , 即首先列出托管索引的首选层 , 然后是可能的许多后备选项。 查询匹配只考虑第一个偏好(列表的第一个值)。


参考链接

Elasticsearch:Metadata fields - 元数据字段介绍_elasticsearch metadata-CSDN博客