11.elasticsearch-meta-field元字段
文章目录
1. meta-fields
es index中的元数据主要由这些
- _index: 索引名
- _type: type名 这个在6.0中已经过期了。
- _id: doc的id
- _source : doc文档的原始json
- _size: _source的字节长度
- _field_names: doc中的所有字段(只要某个字段再任意一篇文档中有非null值就算)
- _ignored: 这个记录了字段设置忽略格式错误的字段之后被ignore的情况
- _routing: 设置routing value
- _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字段可以实现以下功能:
- Update:部分更新时,需要从读取文档保存在_source字段中的原文,然后和请求中的部分字段合并为一个完整文档。如果没有_source,则不能完成部分字段的Update操作。
- Rebuild:最新的版本中新增了rebuild接口,可以通过Rebuild API完成索引重建,过程中不需要从其他系统导入全量数据,而是从当前文档的_source中读取。如果没有_source,则不能使用Rebuild API。
- Script:不管是Index还是Search的Script,都可能用到存储在Store中的原始内容,如果禁用了_source,则这部分功能不再可用。
- Summary:摘要信息也是来源于_source字段。
看到这里,突然想到 doc_values
和 store
之间是不是会有区别呢
看到了在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