3.2.1.2.复合数据类型

分类

数据类型

Array 数组型

支持数组形式,不需要一个专有的字段数据类型

Object 对象型

object数据类型:表现形式其实就是单一的JSON对象

Nested 嵌套型

nested数据类型:表现形式是多个Object型组成的一个数组

Array 数组型

Elasticsearch中,没有特定的array类型。默认情况下,任何字段都可以包含0个或者更多值,但是,所有array中的值必须具有相同的数据类型,例如:

  • 字符串数组:[“one”, “two”]

  • 整数数组:[1,2]

  • 数组的数组:[1, [2, 3]],等价于[1,2,3]

  • 对象数组:[ { "name": "Mary", "age": 12 }, { "name": "John", "age": 10 }]

注意

对象 数组并不能像你期望的那样工作:你不能独立于数组中的其它对象来查询每一个对象。如果想达到这个目的,你应该使用 nest 数据类型代替 object 数据类型

当自动添加一个字段,array的第一个值决定了字段的类型。所有接下来的值必须使用相同的数据类型或者必须至少能将他们转换为与它相同的类型

数组不支持混合的数据类型:[10, “some string”]

数组可以包含null值,这些值可以由配置的null_value替换或完全跳过。一个空的array []被视为不存在的字段-无值的字段。

在文档中使用

array类型不需要提前做任何配置,天生就支持。

PUT my_index/my_type/1
{
  "message": "some arrays in this document...",
  "tags":  [ "elasticsearch", "wow" ],     #1
  "lists": [                               #2
    {
      "name": "prog_list",
      "description": "programming list"
    },
    {
      "name": "cool_list",
      "description": "cool stuff list"
    }
  ]
}

PUT my_index/my_type/2                      #3
{
  "message": "no arrays in this document...",
  "tags":  "elasticsearch",
  "lists": {
    "name": "prog_list",
    "description": "programming list"
  }
}

GET my_index/_search                          #4
{
  "query": {
    "match": {
      "tags": "elasticsearch"
    }
  }
}

1

tags 字段会动态添加为一个 string 字段

2

lists 字段动态添加为一个 object 字段

3

第二个文档不包含 arrays,但是可以索隐为相同字段

4

这个查询,在 tags 字段查找 elasticsearch,会同时匹配到这2个文档

多值字段和倒排索引

事实上,所有字段类型天生支持多值字段源于 LuenceLucene 设计为一个全文检索引擎。为了在一个大的文本快中查找特定单词,Lucene将文本标记为特定的术语,将每一个术语分别添加到倒排索引中。

这意味着即使是一个简单的文本也必须默认支持多值。当其它数据类型如数字或者日期被添加的时,他们使用和strings一样的数据结构,因此自然变为多值。

Object 对象型

JSON文档本质上是分层的:文档包含内部对象,内部对象本身还包含内部对象。

curl -XPUT 'localhost:9200/my_index/my_type/1?pretty' -d'
{   #1
  "region": "US",
  "manager": {  #2
    "age":     30,
    "name": {   #3
      "first": "John",
      "last":  "Smith"
    }
  }
}'

1

外层的文档是 JSON 对象

2

包含称为manager的内部对象

3

manager对象还包含一个内部对象称为name

在内部,这个文档被索引为一个简单的、扁平的键值对列表,如下所示:

{
  "region":             "US",
  "manager.age":        30,
  "manager.name.first": "John",
  "manager.name.last":  "Smith"
}

上面文档的显式映射可以长这样:

curl -XPUT 'localhost:9200/my_index?pretty' -d'
{
  "mappings": {
    "my_type": {    # 1
      "properties": {
        "region": {
          "type": "keyword"
        },
        "manager": {    # 2
          "properties": {
            "age":  { "type": "integer" },
            "name": {   # 3
              "properties": {
                "first": { "type": "text" },
                "last":  { "type": "text" }
              }
            }
          }
        }
      }
    }
  }
}'

1

映射的类型是一个对象类型,具有一个properties字段

2

manager字段是一个内部object字段

3

manager.name字段是manager字段中的一个内部object字段

不需要显式地将字段类型设置为object类型,因为这是默认的类型。

object字段的参数

参数

说明

1

新属性是否应动态添加到现有对象。接受 true(默认),false 和 strict

2

是否应该对对象字段给出的JSON值进行解析和索引(true,默认)或完全忽略(false)

3

为对象中的所有属性设置默认的include_in_all值,对象本身没有添加到 _all 字段。

4

对象内的字段,可以是任何数据类型,包括对象。可以将新属性添加到现有对象。

注意

如果你需要索引"对象的数组"而不是"单个的对象",可以使用nested数据类型。

Nested 嵌套型

nested类型是一种对象类型的特殊版本,它允许索引对象数组,独立地索引每个对象。

如何使对象数组变扁平

内部类对象数组并不以你预料的方式工作。Lucene没有内部对象的概念,所以Elasticsearch将对象层次扁平化,转化成字段名字和值构成的简单列表。比如,以下的文档:

curl -XPUT 'localhost:9200/my_index/my_type/1?pretty' -d'
{
  "group" : "fans",
  "user" : [    # 1
    {
      "first" : "John",
      "last" :  "Smith"
    },
    {
      "first" : "Alice",
      "last" :  "White"
    }
  ]
}'

1

user字段作为对象动态添加

在内部被转化成如下格式的文档:

{
  "group" :        "fans",
  "user.first" : [ "alice", "john" ],
  "user.last" :  [ "smith", "white" ]
}

user.firstuser.last 扁平化为多值字段,alice 和 white 的关联关系丢失了。导致这个文档错误地匹配对 alice 和 smith 的查询

curl -XGET 'localhost:9200/my_index/_search?pretty' -d'
{
  "query": {
    "bool": {
      "must": [
        { "match": { "user.first": "Alice" }},
        { "match": { "user.last":  "Smith" }}
      ]
    }
  }
}'

返回的两条数据

{
  "took": 18,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.51623213,
    "hits": [
      {
        "_index": "range_index",
        "_type": "my_type",
        "_id": "1",
        "_score": 0.51623213,
        "_source": {
          "group": "fans",
          "user": [
            {
              "first": "John",
              "last": "Smith"
            },
            {
              "first": "Alice",
              "last": "White"
            }
          ]
        }
      }
    ]
  }
}

使用nested字段对应object数组

如果你需要索引对象数组,并且保持数组中每个对象的独立性,你应该使用nested对象类型而不是object类型。nested对象将数组中每个对象作为独立隐藏文档来索引,这意味着每个嵌套对象都可以独立被搜索:

curl -XPUT 'localhost:9200/my_index?pretty' -d'
{
  "mappings": {
    "my_type": {
      "properties": {
        "user": {
          "type": "nested"  # 1
        }
      }
    }
  }
}'
curl -XPUT 'localhost:9200/my_index/my_type/1?pretty' -d'
{
  "group" : "fans",
  "user" : [
    {
      "first" : "John",
      "last" :  "Smith"
    },
    {
      "first" : "Alice",
      "last" :  "White"
    }
  ]
}'
curl -XGET 'localhost:9200/my_index/_search?pretty' -d'
{
  "query": {
    "nested": {
      "path": "user",
      "query": {
        "bool": {
          "must": [
            { "match": { "user.first": "Alice" }},
            { "match": { "user.last":  "Smith" }}   # 2
          ]
        }
      }
    }
  }
}'
curl -XGET 'localhost:9200/my_index/_search?pretty' -d'
{
  "query": {
    "nested": {
      "path": "user",
      "query": {
        "bool": {
          "must": [
            { "match": { "user.first": "Alice" }},
            { "match": { "user.last":  "White" }}   # 3
          ]
        }
      },
      "inner_hits": {   # 4
        "highlight": {
          "fields": {
            "user.first": {}
          }
        }
      }
    }
  }
}'

1

user字段映射为nested类型而不是objec t类型

2

该查询没有匹配,因为AliceSmith不在同一个嵌套类中

3

该查询有匹配,因为AliceWhite在同一个嵌套类中

4

inner_hits可以高亮匹配的嵌套文档

嵌套文档可以:

nested字段参数

参数

说明

dynamic

新属性是否应动态添加到现有对象。接受 true (默认), false 和 strict。

include_in_all

为对象中的所有属性设置默认的include_in_all值,对象本身没有添加到 _all 字段。

properties

对象内的字段,可以是任何数据类型,包括对象。可以将新属性添加到现有对象。

注意 因为嵌套文档是作为单独的文档被索引的,所以嵌套文档只能被 nested 查询、nested / reverse_nested或者 nested inner hits 访问。 比如,一个 string 字段包含嵌套文档,嵌套文档中 index_options 设置为 offsets 以使用 postings highlighter,这些偏移量在主要的高亮阶段是不可用的。必须通过 nested inner hits 来进行高亮操作。

限制nested字段的数量

索引一个包含 100 个 nested字段的文档实际上就是索引 101 个文档,每个嵌套文档都作为一个独立文档来索引。为了防止过度定义嵌套字段的数量,每个索引可以定义的嵌套字段被限制在 50 个。

Last updated