Mapping 之 Meta-Fields

该部分官方地址
每一个文档都有相关的元数据。创建索引的mapping的时候,可以对这些元数据类型自定义。

Identity meta-fields(标识符,意义就是让每个doc唯一存在)

_index

决定文档属于哪个索引。
这个字段在doc添加的时候就已经被确定了。_index用处主要在于多个索引查询时,可以用这个字段指定在哪个索引使用,_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": {
    "bool": {
      "must": [
        {
          "match": {
            "_index": "index_2" //指定索引
          }
        },
        {
          "match": {
            "text": "1"
          }
        }
      ]
    }
  }
}

_uid

6.0已经被弃用。
原因是uid是type和id的合写,_doc#1 表示type为_doc的第一个文档。
因为现在已经没有多个type了,type只有一个,所以就没有必要了。但是现在_uid仍然是可以使用的。

_type

6.0也已经弃用。
以前多个type时一个文档的的唯一表示需要uid那种,现在不需要,所以没有必要。但是现在在GET API这个依然很重要,只是对于doc来说,不在作为标识符了。

_id

每个文档现在就是用这个字段来唯一标识的。这个也是为什么能用GET和ids直接进行查询的原因。
而6.0以前其实当你用GET API时,其实用的是uid,现在则是真的在用_id进行查询。
另外要说的是,可以用id做聚合或者排序操作,但是这个需要使用大量内存加载数据,所以最好是将上面在Percolator type讲过的doc_values确定设置为true(一般默认为 true,二进制是false)。

Document source meta-fields(doc源,就是存储原始doc的数据)

_source

这个字段很有意思,在索引feed的时候,原始json文本的源数据会被放进index存储里面,但是这个字段并不会被放进倒排索引里,只是为了get和search这些取数据的展示。

禁用_source

虽然展示很方便,但是_source字段确实在索引中会造成存储开销。所以可以设置为_source。

PUT my_index
{
  "mappings": {
    "_doc": {
      "properties": {
        "source": {
          "enabled": false
        }
      }
    }
  }
}
禁用的后果

用户经常禁用_source字段而不考虑后果。如果_source字段不可用,则多个特性将不会被支持。
1.一些API不能用了,比如update和reindex的api
2.高亮你就看不到了
3.你不能通过观看_source 字段来修改你的查询式
4.通过_source字段自行修复损坏的索引的能力也没有了
反正如果磁盘没什么问题,最好不禁。

Including / Excluding fields from _source

比较好的解决方案,首先肯定要留下_source字段,然后使用includes/excludes参数(支持通配符表示),注意前后顺序是有意义的。

PUT logs
{
  "mappings": {
    "_doc": {
      "_source": {
        "includes": [
          "*.count",
          "meta.*"
        ],
        "excludes": [
          "meta.description",
          "meta.other.*"
        ]
      }
    }
  }
}

_size

需要安装mapper-size插件,然后重启es。
这个字段的意义存储_source字段的字节数。你可以过滤字节数大于多少的,也可以聚合什么的。
PUT my_index
{
"mappings": {
"my_type": {
"_size": {
"enabled": true
}
}
}
}

Indexing meta-fields

_all

6.0已经被声明弃用了,而是用一个约定的字段配合copy_to参数使用。

_all的功能:6.0以前

_all字段是一个特殊的字段,他把所有的字段连在一起变成大字符串,用空格做分隔符,es会对其进行分析和索引,但不会进行存储。这意味着他可以用来search,但不是进行retrieved。
all字段特别有用的时候是当你开始新接触一个数据集时,使用all检索可以快速帮助你使用起来,而不用了解具体某个字段,因为它实际上是在search整个文档。
我几个电脑上的ES版本最低都是6.1.2了,所以没办法用原来的_all字段了。
官网的代码是像下面这样的:

PUT my_index
{
  "mapping": {
    "user": {
      "_all": {
        "enabled": true   
      }
    }
  }
}

PUT /my_index/user/1      
{
  "first_name":    "John",
  "last_name":     "Smith",
  "date_of_birth": "1970-10-24"
}

GET /my_index/_search
{
  "query": {
    "match": {
      "_all": "john smith 1970"
    }
  }
}

要说明一点,这一点也是为什么可以被替换的原因。_all字段对待任何类型的字段都是一视同仁看作text的。比如date就被看作三个string,_all 字段就是一个text字段
all字段搜索就像一个过滤器,很适合探索新数据,但是其丧失了字段的目的(相关性丢了)。有时候相关性很重要。
此外,
all字段会占用额外的cpu来处理,并且会占用磁盘。
还有如何优化_all字段的使用,这些就不看了,因为都要被弃用,上面的这些已经够知道目的和机理了。

6.0以后专门创造个_all字段

利用copy_to参数,将有意义的字段全部复制到一个text字段里。

PUT myindex
{
  "mappings": {
    "mytype": {
      "properties": {
        "first_name": {
          "type":    "text",
          "copy_to": "full_name" 
        },
        "last_name": {
          "type":    "text",
          "copy_to": "full_name" 
        },
        "full_name": {
          "type":    "text"
        }
      }
    }
  }
}

PUT myindex/mytype/1
{
  "first_name": "John",
  "last_name": "Smith"
}

GET myindex/_search
{
  "query": {
    "match": {
      "full_name": "John Smith"
    }
  },
  "highlight": {
    "fields": {
       "*_name": { 
        "require_field_match": false  //这个要设置false
      }
    }
  }
}

fieldnames

fieldnames字段用来放一个文档里非null字段的所有字段,主要是用来配合exists查询。
只有doc_values和norms都关闭时,exists才会用_field_names,否则不会用。

_ignored

6.4.0字段才被添进去。
这个字段的应用场景就是有个字段其实你也控制不了他是什么类型,比如说登陆的账号,可能是email(Keyword),也可能是phone num(long),你可以在设置类型的同时声明ignore_malformed,这时候它就会被存进去_ignore字段。ignore_malformed和_ignore需要配合使用。

PUT my_index
{
  "mappings": {
    "_doc": {
      "properties": {
        "number_one": {
          "type": "integer",
          "ignore_malformed": true
        },
        "number_two": {
          "type": "integer"
        }
      }
    }
  }
}

Routing meta-field

_routing是为了决定将这个doc放在哪个分片,分片就是es5个分片就建立5个lucene索引,解决存储的数据总量超过单个索引的容量这个问题。下面这个公式用来计算会放在那个分片上,路由指定1就是在1这个分片上找。

shard_num = hash(_routing) % num_primary_shards

我的电脑上分片默认是5,这个可以在建索引的时候设置,如果不设置就是5
还有要说明可以在put文档的时候使用routing这个参数,如果不设置就默认是_id

PUT my_index/_doc/1?routing=user1&refresh=true 
{
  "title": "This is a document"
}
//利用_routing查询路由值为user1的doc 
GET my_index/_search
{
  "query": {
    "terms": {
      "_routing": [ "user1" ] 
    }
  }
}
//仅仅使用特定的分片上的doc,这样可以实现在同一个id在不同的分片上不一样
GET my_index/_search?routing=user1,user2 
{
  "query": {
    "match": {
      "title": "document"
    }
  }
}

//设置必须提供路由信息,下面put操作会报routing_missing_exception异常
PUT my_index2
{
  "mappings": {
    "_doc": {
      "_routing": {
        "required": true 
      }
    }
  }
}

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

Other meta-field

meta可以记录一些这个索引的基本信息,比如下面就记录这个myindex的对应Class信息,以及对应的版本

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

“Mapping 之 Meta-Fields”的一个回复

发表评论

电子邮件地址不会被公开。