這篇是介紹field data types的第四篇,也會是field type最後一篇
主要介紹object, array以及nested
object field type
JSON本身就是個可以包含階層性的
直接看範例
Reqeust
PUT my-index-000008/_doc/1
{
"region": "US",
"manager": { (1)
"age": 30,
"name": { (2)
"first": "John",
"last": "Smith"
}
}
}
(1): 其中 key manager
的 value 為 json object
(2): name
也是包含了 object
另外說明, object
field type 的資料,是會被 flat(攤平) 成 key-value pairs,
以上述新增的範例而言會是以如下方式建立索引
{
"region": "US",
"manager.age": 30,
"manager.name.first": "John",
"manager.name.last": "Smith"
}
上述範例新增後,es自動建立的index的mapping會是如何?
查看mapping
GET my-index-000008/_mapping
Response
properties
,我們在最上層定義 fields 時,其實就會用到了,如果現在是object,也就是會含有 sub-fields 時,也會需要使用 properties
,如上圖所示, manager
下在定義 age
和 name
field 之前會需要先用 properties
,以此類推, manager.name
也含有 properties
manager
field為什麼沒有定義他的 field type,實際上 manager
是 object
field type,畢竟有 sub-fields (inner properties), object
是 dafault,所以就不需要額外設定 (一般在建立object時,也都直接用 properties
針對 sub-fields 定義,不會額外定義 "type": "object"
)Field capabilities API
可以讓查看indices下的指定fields的能力(capabilities)
Request
GET /_field_caps?fields=<fields>
POST /_field_caps?fields=<fields>
GET /<target>/_field_caps?fields=<fields>
POST /<target>/_field_caps?fields=<fields>
為什麼要突然介紹這個API呢? 因為我想用這個來驗證和查看上述index
查看 index my-index-000008
的 manager為前綴的fields (使用上述第三種)
GET my-index-000008/_field_caps?fields=manager*
Response
在上圖可看到 manager
這邊有顯示 "type" : "object"
Arrays
在es,沒有所謂的 array
data type,每一個 field
是可以包含0或多個值得,
但是所有的值必須是同一個 data type
例如:
定義 string
field data type,可以輸入 ["one", "two"]
[Note]
- array內包含了不同data types,則是不允許的,例如:
[10, "some string"]
- 在新增document時,如果field的values為 empty array,則此field是不會被建立至mapping的
直接使用 example 來介紹
PUT my-index-000009/_doc/1
{
"message": "some arrays in this document...",
"tags": [ (1)
"elasticsearch",
"wow"
],
"lists": [ (2)
{
"name": "prog_list",
"description": "programming list"
},
{
"name": "cool_list",
"description": "cool stuff list"
}
]
}
PUT my-index-000009/_doc/2
{
"message": "no arrays in this document...",
"tags": "elasticsearch", (3)
"lists": { (4)
"name": "prog_list",
"description": "programming list"
}
}
(1): 會根據此 tags
產生出 string
field data type
(1): 此 lists
產生出 object
field data type
(3)(4): 沒有使用 array ,但是 field data type 符合,所以成功新增 document
用search是否可以搜尋array和非array單純string的document?
GET my-index-000009/_search
{
"query": {
"match": {
"tags": "elasticsearch"
}
}
}
Response
正確,兩筆document都可以被搜出來
nested field type
是 object
data type 中的一個版本,可以允許 array of objects中,objects之間彼此是獨立的
實際上就是,一般的 object
是會把 ojbect的階層解析為 key-value pair,
可能還是很難懂,直接使用範例
Request
PUT my-index-000010/_doc/1
{
"group": "fans",
"user": [ (1)
{
"first": "John",
"last": "Smith"
},
{
"first": "Alice",
"last": "White"
}
]
}
(1): 此 user
會是 object
field data type
而上述範例es會轉化為
{
"group": "fans",
"user.first": ["alice", "john"],
"user.last": ["smith", "white"]
}
其實上面介紹
object
field type 有提到,
只是上面範例是用 object,這邊用 array of objects
回歸正題,
es把object的階層性轉化為 "user.first"
和 "user.last"
multi-value fields,
分別用來儲存 user[i].first
和 user[i].last
的值,
會發現,這樣會讓原本存在在同一object的關係消失了,
以上述為例,即為 Alice
和 White
的關係不存在了
驗證: 搜尋 user.first
為 Alice
且 user.last
為Smith
GET my-index-000010/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"user.first": "Alice"
}
},
{
"match": {
"user.last": "Smith"
}
}
]
}
}
}
Response
如上圖所示,是會搜尋得到的,即使當時新增的 Alice
和 Smith
是不在同一個object的,
但因為es的攤平(flat),所以object內的資料的關係消失了
那要如何保留這種關係,也就是維持每一個object在array內的獨立性呢?
沒錯,就是使用 nested data type
題外話,依照目前es預設設定 dynamic field mapping: true
,
也就是自動判斷field的data type,是不會有 nested
data type這個選項的,
如果有興趣關於JSON的data type會對應到es判定的data type可參考reference
所以如下範例是會先
建立index且明確指定mapping
PUT my-index-000011
{
"mappings": {
"properties": {
"user": {
"type": "nested"
}
}
}
}
輸入跟剛剛一樣的範例document
PUT my-index-000011/_doc/1
{
"group": "fans",
"user": [
{
"first": "John",
"last": "Smith"
},
{
"first": "Alice",
"last": "White"
}
]
}
驗證: 搜尋 user.first
為 Alice
且 user.last
為Smith
補充:搜尋 nested
field type 需使用 nested query
GET my-index-000011/_search
{
"query": {
"nested": {
"path": "user",
"query": {
"bool": {
"must": [
{
"match": {
"user.first": "Alice"
}
},
{
"match": {
"user.last": "Smith"
}
}
]
}
}
}
}
}
Response
是正確的,因為 Alice
和 Smith
卻是不在同一object
驗證: 搜尋 user.first
為 Alice
且 user.last
為White
GET my-index-000011/_search
{
"query": {
"nested": {
"path": "user",
"query": {
"bool": {
"must": [
{
"match": {
"user.first": "Alice"
}
},
{
"match": {
"user.last": "White"
}
}
]
}
}
}
}
}
Response
正確,Alice
和 White
在同一組有被搜出來了
小小新手,如有理解錯誤或寫錯再請不吝提醒或糾正
Field data types
Field capabilities API
Dynamic field mapping