Elasticsearch學習-父子文檔


本文以Elasticsearch 6.8.4版本為例,介紹Elasticsearch父子文檔的使用。

image

上一篇文章介紹了Elasticsearch的嵌套文檔,這一篇來介紹另外一種關系文檔,父子文檔。

1、父子文檔

父子文檔在理解上來說,可以理解為一個關聯查詢,有些類似MySQL中的JOIN查詢,通過某個字段關系來關聯。

父子文檔與嵌套文檔主要的區別在於,父子文檔的父對象和子對象都是獨立的文檔,而嵌套文檔中都在同一個文檔中存儲,如下圖所示:

image

這里引用官網的話,對比嵌套文檔來說,父-子關系的主要優勢有:

  • 更新父文檔時,不會重新索引子文檔。
  • 創建,修改或刪除子文檔時,不會影響父文檔或其他子文檔。這一點在這種場景下尤其有用:子文檔數量較多,並且子文檔創建和修改的頻率高時。
  • 子文檔可以作為搜索結果獨立返回。

1.1 創建索引

這里還是以嵌套文檔的數據為例,假設數據如下:

[
    {
        "title":"這是一篇文章",
        "body":"這是一篇文章,從哪里說起呢? ... ..."
    },
    {
        "name":"張三",
        "comment":"寫的不錯",
        "age":28,
        "date":"2020-05-04"
    },
    {
        "name":"李四",
        "comment":"寫的很好",
        "age":20,
        "date":"2020-05-04"
    },
    {
        "name":"王五",
        "comment":"這是一篇非常棒的文章",
        "age":31,
        "date":"2020-05-01"
    }
]

創建索引名和type均為blog的索引,從上面數據可以看出,其實父文檔(博客內容)與子文檔分別用不同的字段來存儲對應的數據,不過在創建索引文檔的時候需要指定父子文檔的關系,即文章為parent,留言為child,創建索引語句如下:

PUT http://localhost:9200/blog/

{
  "mappings": {
    "blog": {
      "properties": {
        "date": {
          "type": "date"
        },
        "name": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        },
        "comment": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        },
        "age": {
          "type": "long"
        },
        "body": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        },
        "title": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        },
        "relation": {
          "type": "join",
          "relations": {
            "parent": "child"
          }
        }
      }
    }
  }
}

如下圖所示

image

1.2 插入數據

插入父文檔數據,需要指定上文索引結構中的relation為parent,如下:

POST http://localhost:9200/blog/blog/1/

{
    "title":"這是一篇文章",
    "body":"這是一篇文章,從哪里說起呢? ... ...",
    "relation":"parent"
}

插入子文檔,需要在請求地址上使用routing參數指定是誰的子文檔,並且指定索引結構中的relation關系,如下:

POST http://localhost:9200/blog/blog/2?routing=1

{
    "name":"張三",
    "comment":"寫的不錯",
    "age":28,
    "date":"2020-05-04",
    "relation":{
        "name":"child",
        "parent":1
    }
}

POST http://localhost:9200/blog/blog/3?routing=1

{
    "name":"李四",
    "comment":"寫的很好",
    "age":20,
    "date":"2020-05-04",
    "relation":{
        "name":"child",
        "parent":1
    }
}

POST http://localhost:9200/blog/blog/4?routing=1

{
    "name":"王五",
    "comment":"這是一篇非常棒的文章",
    "age":31,
    "date":"2020-05-01",
    "relation":{
        "name":"child",
        "parent":1
    }
}

插入完成后,如下圖所示。

image

從這里其實可以很明顯的看出與嵌套文檔的區別了,嵌套文檔只有一個文檔,而這里是有四個文檔。

1.3 查詢

普通查詢這里不進行贅述,關系查詢的話其實很好理解,大致分為兩種特殊情況:

  1. 根據父文檔查詢子文檔 has_child
  2. 根據子文檔查詢父文檔 has_parent

接下來我們來看如何進行關系查詢,首先看一下通過子文檔查詢父文檔,比如這樣的場景,查詢名稱是張三的人留言的文章,查詢語句如下:

{
  "query": {
    "has_child": {
      "type":"child",
      "query": {
        "match": {
          "name": "張三"
        }
      }
    }
  }
}

查詢結果如下:

image

使用has_child來根據子文檔內容查詢父文檔,其實type就是創建文檔時,子文檔的標識。

在使用子查父的時候,可以添加一些篩選條件來增強匹配的結果,比如最大匹配max_children和最小匹配min_children,這里有點類似should查詢的minimum_should_match,感興趣的可以去官網了解更多的細節。

到這里,其實對Elasticsearch特性了解的讀者就會知道如何根據父文檔查詢子文檔了,只需要注意一點,父查子type需要修改成parent_type,其余都與自查父類似,比如查詢標題為“這是一篇文章”的數據的留言內容,查詢語句如下:

{
  "query": {
    "has_parent": {
      "parent_type":"parent",
      "query": {
        "match": {
          "title": "這是一篇文章"
        }
      }
    }
  }
}

查詢結果如下:

image

由於只有一組父子文檔,效果不是很明顯,感興趣可以多造一些數據去體驗

聚合查詢與嵌套文檔類似,比較簡單,這里在說明另外一種場景:祖輩和孫輩可以創建嗎?比如本文中的留言如果它也有子文檔,那么可以根據文章查詢孫輩嗎?答案是可以的,只需要在has_child里面在嵌套一層has_child查詢即可。

1.4 使用建議

  1. 父子文檔都可以獨立返回,對於某些場景很適用,比如主表信息是一些基本不變的數據,而子表信息經常增刪改,並且子表信息經常有查詢場景,這樣就很適合使用父子文檔。
  2. 父子文檔需要在同一分片上,當然,我們無需做特殊處理,默認就會為我放入同一個分片,其實原理是這樣的,Elasticsearch會根據routing中的參數去看父文檔所在分片在哪,然后將對應文檔存儲進去。
  3. 父子文檔查詢效率相對嵌套文檔較低,官網說是5-10倍左右。

其余官網也給定了一些建議,具體可以查看官方文檔,地址:https://www.elastic.co/guide/cn/elasticsearch/guide/current/parent-child-performance.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM