我们需要讨论的最后一个自然JSON数据类型是对象(object)——在其它语言中叫做hash、hashmap、dictionary 或者 associative array.
内部对象(inner objects)经常用于在另一个对象中嵌入一个实体或对象。例如,做为在tweet
文档中user_name
和user_id
的替代,我们可以这样写:
{
"tweet": "Elasticsearch is very flexible",
"user": {
"id": "@johnsmith",
"gender": "male",
"age": 26,
"name": {
"full": "John Smith",
"first": "John",
"last": "Smith"
}
}
}
内部对象的映射
Elasticsearch 会动态的检测新对象的字段,并且映射它们为 object
类型,将每个字段加到 properties
字段下
{
"gb": {
"tweet": { <1>
"properties": {
"tweet": { "type": "string" },
"user": { <2>
"type": "object",
"properties": {
"id": { "type": "string" },
"gender": { "type": "string" },
"age": { "type": "long" },
"name": { <3>
"type": "object",
"properties": {
"full": { "type": "string" },
"first": { "type": "string" },
"last": { "type": "string" }
}
}
}
}
}
}
}
}
<1> 根对象.
<2><3> 内部对象.
对user
和name
字段的映射与tweet
类型自己很相似。事实上,type
映射只是object
映射的一种特殊类型,我们将 object
称为根对象。它与其他对象一模一样,除非它有一些特殊的顶层字段,比如 _source
,_all
内部对象是怎样被索引的
Lucene 并不了解内部对象。 一个 Lucene 文件包含一个键-值对应的扁平表单。 为了让 Elasticsearch 可以有效的索引内部对象,将文件转换为以下格式:
{
"tweet": [elasticsearch, flexible, very],
"user.id": [@johnsmith],
"user.gender": [male],
"user.age": [26],
"user.name.full": [john, smith],
"user.name.first": [john],
"user.name.last": [smith]
}
内部栏位可被归类至name,例如"first"
。 为了区别两个拥有相同名字的栏位,我们可以使用完整路径,例如"user.name.first"
或甚至类型
名称加上路径:"tweet.user.name.first"
。注意: 在以上扁平化文件中,并没有栏位叫作user
也没有栏位叫作user.name
。 Lucene 只索引阶层或简单的值,而不会索引复杂的资料结构。
动态映射
当 Elasticsearch 处理一个位置的字段时,它通过【动态映射】来确定字段的数据类型且自动将该字段加到类型映射中。
有时这是理想的行为,有时却不是。或许你不知道今后会有哪些字段加到文档中,但是你希望它们能自动被索引。或许你仅仅想忽略它们。特别是当你使用 Elasticsearch 作为主数据源时,你希望未知字段能抛出一个异常来警示你。
幸运的是,你可以通过 dynamic
true
:自动添加字段(默认)false
:忽略字段strict
:当遇到未知字段时抛出异常dynamic
设置可以用在根对象或任何 object
对象上。你可以将 dynamic
默认设置为 strict
,而在特定内部对象上启用它:
PUT /my_index
{
"mappings": {
"my_type": {
"dynamic": "strict", <1>
"properties": {
"title": { "type": "string"},
"stash": {
"type": "object",
"dynamic": true <2>
}
}
}
}
}
<1> 当遇到未知字段时,my_type
<2> stash
通过这个映射,你可以添加一个新的可搜索字段到 stash
PUT /my_index/my_type/1
{
"title": "This doc adds a new field",
"stash": { "new_field": "Success!" }
}
但是在顶层做同样的操作则会失败:
PUT /my_index/my_type/1
{
"title": "This throws a StrictDynamicMappingException",
"new_field": "Fail!"
}
备注:将 dynamic
设置成 false
完全不会修改 _source
字段的内容。_source
+