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
                }
              ]
            }
          }
        }
      ]
    }
}

參考:

  1. https://www.cnblogs.com/licongyu/p/5557693.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章