ES 父子文檔
父子文檔的特點
1.父/子文檔是完全獨立的。
2.父文檔更新不會影響子文檔。
3.子文檔更新不會影響父文檔或者其它子文檔。
父子文檔的映射與索引
1.父子關係 type 的建立必須在索引新建或 update-mapping 時候確定好
PUT /company
{
"mappings": {
"branch": {}, //父文檔 type
"employee": {
"_parent": {
"type": "branch" //子文檔 type
}
}
}
}
2.父文檔的索引和普通文檔索引一樣。
POST /company/branch/_bulk
{ "index": { "_id": "london" }}
{ "name": "London Westminster", "city": "London", "country": "UK" }
3.子文檔索引必須指定其對應的父文檔 ID,作用:
- 建立父子文檔之間的關聯
- 確保子文檔能夠被索引到父文檔所在分片(parent id 作爲 route)
PUT /company/employee/1?parent=london //指定 id = london 的父文檔
{
"name": "Alice Smith",
"dob": "1970-10-24",
"hobby": "hiking"
}
4.如果要更改文檔的父文檔,不能僅僅 update 或者 reindex 舊文檔(新的父文檔可能在不同分片上),需要先刪除舊文檔再重新索引。
父子關係應用
看到 parent-child 關係,我們很容易想到的是像 SQL 那樣的各種 JOIN 操作——比如查詢某個文檔並一併取回所有的父或子文檔等。
然而,ES 中不支持類似的 JOIN 查詢。即便 child aggregation 也不能做到像 SQL 那樣的 JOIN 操作!
在 ES 中的 parent-child 關係基本可以理解爲是一個過濾條件,如下:
//查詢某文檔,只有該文檔有"父文檔"且滿足一定條件纔算匹配
{"has_parent": { //文檔是否有 parent
"type": "branch", //其 parent 所在 type 必須是 branch
"query": { //其 parent 必須滿足以下 query 條件
"match": {
"country": "UK"
}
}
} //如果滿足以上條件,hit 該文檔
}
//查詢某文檔,只有該文檔有"子文檔"且滿足一定條件纔算匹配
{
"has_child": { //文檔是否有 child
"type": "employee", //其 child所在 type 必須是 employee
"query": { //其 parent 必須滿足以下 query 條件
"match": {
"name": "Alice Smith"
}
}
} //如果滿足以上條件,hit 該文檔
}
1.has_child:基於子文檔的內容,查找父文檔
//請求 GET /company/branch/_search
{
"query": {
"has_child": { //基於 child 的內容,查詢滿足條件的 parent 文檔
"type": "employee",
"query": { //在 child 中執行 match query操作
"match": {
"name": "Alice Smith"
}
}
}
}
}
//結果
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "company",
"_type": "branch", //注意!!!返回的是 parent 的文檔
"_id": "london",
"_score": 1,
"_source": {
"name": "London Westminster",
"city": "London",
"country": "UK"
}
}
]
}
}
2.has_parent:基於父文檔的內容,查找子文檔
//請求 GET /company/employee/_search
{
"query": {
"has_parent": { //基於 parent 的內容,查詢滿足條件的 child 文檔
"type": "branch",
"query": { //在 parent 中執行 match query 查詢
"match": {
"country": "UK"
}
}
}
}
}
//結果
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "company",
"_type": "employee", //注意!!!返回的是 child 的文檔
"_id": "1",
"_score": 1,
"_routing": "london",
"_parent": "london",
"_source": {
"name": "Alice Smith",
"dob": "1970-10-24",
"hobby": "hiking"
}
}
]
}
}
3.children aggregation:對關聯的 child 文檔進行聚合操作
//請求 GET /company/branch/_search
{
"size" : 0,
"aggs": {
"country": {
"terms": {
"field": "country" //以不同的 country 來分組(桶分)
},
"aggs": {
"employees": {
"children": { //children aggregation,子 type 爲 employee
"type": "employee"
},
"aggs": {
"hobby": {
"terms": {
"field": "hobby" //以不同的 hobby 來分組(桶分)
}
}
}
}
}
}
}
}
//結果
"aggregations": {
"country": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [ //country 聚合結果
{
"key": "uk",
"doc_count": 2,
"employees": { //children aggregation 聚合
"doc_count": 1,
"hobby": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [ //hobby 聚合結果
{
"key": "hiking",
"doc_count": 1
}
]
}
}
}
]
}
}
參考: