欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

11.elasticsearch-meta-field元字段

程序员文章站 2022-07-09 18:50:24
...

1. meta-fields

es index中的元数据主要由这些

  1. _index: 索引名
  2. _type: type名 这个在6.0中已经过期了。
  3. _id: doc的id
  4. _source : doc文档的原始json
  5. _size: _source的字节长度
  6. _field_names: doc中的所有字段(只要某个字段再任意一篇文档中有非null值就算)
  7. _ignored: 这个记录了字段设置忽略格式错误的字段之后被ignore的情况
  8. _routing: 设置routing value
  9. _meta: application 识别的专用的meta data

2. 部分meta field详述

1. _index: 索引名

_index字段是一个虚拟的字段,他是es自己存储的,并没有存储在lucene当中。
所以你可以用_index字段做一些term查询,或者是一些可以被重写为term查询的查询,比如match,query_string,simple_query_string query 等。
但是不能支持正则,前缀查询等模糊匹配。

使用样例

GET _search
{
  "size": 10, 
  "aggs": {
    "indices": {
      "terms": {
        "field": "_index", 
        "size": 20
      }
    }
  },
  "sort": [
    {
      "_index": { 
        "order": "asc"
      }
    }
  ],
  "script_fields": {
    "index_name": {
      "script": {
        "source": "doc['_index']", 
        "lang": "painless"
        }
    }
  }
}

2. _type: type名

在6.0中已经过期了

3. _id: doc的id

这个 _id字段是es存储在每个doc中添加的一个字段_id,这个_id字段存储实际上只存储了倒排字典索引,没有存储doc-values,所以不太适合用来做agg,sort,会在内存中暂用大量空间。
如果想使用_id字段做agg,sort 建议再建一个字段存储_id的值,并开启doc-values 设置。
详细原理参考这里
_id字段值适合直接通过id来查询的场景。

PUT my_index/_doc/1
{
  "text": "Document with ID 1"
}

PUT my_index/_doc/2?refresh=true
{
  "text": "Document with ID 2"
}

GET my_index/_search
{
  "query": {
    "terms": {
      "_id": [ "1", "2" ] 
    }
  }
}

4. _source : doc文档的原始json

Elasticsearch中_source字段的主要目的是通过doc_id读取该文档的原始内容,所以只需要存储Store即可。他是query,get 查询时默认返回的字段。

_source其实是名为_source的虚拟Store Field。

Elasticsearch中使用_source字段可以实现以下功能:

  1. Update:部分更新时,需要从读取文档保存在_source字段中的原文,然后和请求中的部分字段合并为一个完整文档。如果没有_source,则不能完成部分字段的Update操作。
  2. Rebuild:最新的版本中新增了rebuild接口,可以通过Rebuild API完成索引重建,过程中不需要从其他系统导入全量数据,而是从当前文档的_source中读取。如果没有_source,则不能使用Rebuild API。
  3. Script:不管是Index还是Search的Script,都可能用到存储在Store中的原始内容,如果禁用了_source,则这部分功能不再可用。
  4. Summary:摘要信息也是来源于_source字段。

看到这里,突然想到 doc_valuesstore之间是不是会有区别呢
看到了在es的社区中有这样的答案
简而言之,两者提供的支持都是通过doc_id 找到对应的field的内容。
doc_values是为了快速访问而设计的,适用于sort,agg等场景中使用,因为这些查询中需要获取大量的某个field的值,所以速度必须快。
store则是为了优化field的存储而设计的,所以他的访问性能没有doc_values的好,但是存储上优化比较多,适合存储大量内容,他是用来在query匹配结束后用来返回给client结果之前获取对应的field的值,这个时候对应的结果筛选已经结束,相对对filed的访问量很小。
所以一般情况下是尽量不要在query中对store field执行script的(虽然是可以执行的),因为这样会比较慢。

同时,话说回来,_source 存储了所有的文档内容,在磁盘容量允许的情况下,建议不要关闭_source

PUT tweets
{
  "mappings": {
    "_source": {
      "enabled": false
    }
  }
}

同时,你也可以设置include,excluds设置 _source 不存储哪些数据

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" 
    }
  }
}


返回

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "logs",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.2876821,
        "_source" : {
          "meta" : {
            "other" : { },
            "name" : "Some metric"
          },
          "requests" : {
            "count" : 10
          }
        }
      }
    ]
  }
}

5. _size: _source的字节长度

_size 存储了 _source的字节长度
这个需要安装 mapper-size plugin

sudo bin/elasticsearch-plugin install mapper-size

使用样例

PUT my_index
{
  "mappings": {
    "_size": {
      "enabled": true
    }
  }
}

PUT my_index/_doc/1
{
  "text": "This is a document"
}

PUT my_index/_doc/2
{
  "text": "This is another document"
}


GET my_index/_search
{
  "query": {
    "range": {
      "_size": { 
        "gt": 10
      }
    }
  },
  "aggs": {
    "sizes": {
      "terms": {
        "field": "_size", 
        "size": 10
      }
    }
  },
  "sort": [
    {
      "_size": { 
        "order": "desc"
      }
    }
  ],
  "script_fields": {
    "size": {
      "script": "doc['_size']"  
    }
  }
}

6. _field_names: 当前doc中的所有非空字段

是用来支持 exist查询的,但是对于有doc_values或者norm的字段,exist查询不会再使用_field_names

7. _ignored: 这个记录了字段设置忽略格式错误的字段之后被ignore的情况

这个字段主要是配合 ignore_malformed 这个mapping param 使用
ignore_malformed 会让一个和mapping中定义的type不一致的数据也写入到索引中去
对于一个field,如果设置了 "ignore_malformed": true, 则对于那些类型不符的数据只会存储到_source中,但是不会进行index,这样的话整个doc还是正常写入的,只有当前的field无法进行搜索。

如果一个doc因为某个field触发了ignore_malformed 规则,会产生相应的标记,对应的doc中会被添加进去一个 _ignore的field,然后就可以根据这个来查找了。


PUT my_index
{
    "mappings" : {
      "properties" : {
        "requests" : {
          "type" : "text"
        },
        "number":{
          "type": "integer",
          "ignore_malformed": true
        }
      }
    }
}

PUT my_index/_doc/1
{
  "requests":"hahaha",
  "number":"5"
  
}


PUT my_index/_doc/2
{
  "requests":"hahaha",
  "number":6
  
}



PUT my_index/_doc/3
{
  "requests":"hahaha",
  "number":"a"
  
}


这三个doc的写入都不会报错,第一个会按照数字存储。

然后可以进行下面的查询


GET my_index/_search
{
  "query": {
    "exists": {
      "field": "_ignored"
    }
  }
}

返回

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_ignored" : [
          "number"
        ],
        "_source" : {
          "requests" : "hahaha",
          "number" : "a"
        }
      }
    ]
  }
}

可以看到该文档有一个_ignored 字段
即使通过match_all的查询也是可以看到这个字段的。只有那些有malformed 字段的才会有这个字段。

8. _routing: 设置routing value

1. routing的作用

这个字段很重要,每个doc会被发送到哪个shard其实都是有计算规则的。
默认的计算规则为

shard_num = hash(_routing) % num_primary_shards

_routing 的默认值是doc 的 _id 字段,也就是每个doc进来之后默认是按照id进行路由分配到不同的shard的。
你也可以自己制定路由的方式。

2. _routing的使用方式

在index,get,update,delete 的时候都可以指定_routing规则。

PUT my_index/_doc/1?routing=user1&refresh=true 
{
  "title": "This is a document"
}

GET my_index/_doc/1?routing=user1

GET my_index/_search?routing=user1,user2 
{
  "query": {
    "match": {
      "title": "document"
    }
  }
}

在query中是可以使用_routing字段的

GET my_index/_search
{
  "query": {
    "terms": {
      "_routing": [ "user1" ] 
    }
  }
}

3. 可以设置强制使用routing

PUT my_index2
{
  "mappings": {
    "_routing": {
      "required": true 
    }
  }
}


put操作会报错

PUT my_index2/_doc/1 
{
  "text": "No routing value provided"
}

4. 使用uniq_id作为自定义routing

当你使用自定的_routing param进行index的时候,索引中所有的doc的_id字段是不做唯一保证的(只能在同一个shard上面保证),所以你要自己来控制id在索引中的唯一性。

这里里面可以回忆一下join field, 父子文档都要用相同的routing才行,因为要存储到同一个分片当中。

9. _meta: application 识别的专用的meta data

_meta field对于es来说目前没有任何地方用到,只是方便外部业务使用方来记录一下自己的数据,而且这个数据只能存储在mapping中,并不会存储在每个doc当中。
比如下面。


PUT my_index
{
  "mappings": {
    "_meta": { 
      "class": "MyApp::User",
      "version": {
        "min": "1.0",
        "max": "1.3"
      }
    }
  }
}

GET my_index