天天看點

Elasticsearch學習-父子文檔

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

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

1、父子文檔

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

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

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

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

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

如下圖所示

1.2 插入資料

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

POST

http://localhost:9200/blog/blog/1/
{
    "title":"這是一篇文章",
    "body":"這是一篇文章,從哪裡說起呢? ... ...",
    "relation":"parent"
}           

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

http://localhost:9200/blog/blog/2?routing=1
{
    "name":"張三",
    "comment":"寫的不錯",
    "age":28,
    "date":"2020-05-04",
    "relation":{
        "name":"child",
        "parent":1
    }
}           
http://localhost:9200/blog/blog/3?routing=1
{
    "name":"李四",
    "comment":"寫的很好",
    "age":20,
    "date":"2020-05-04",
    "relation":{
        "name":"child",
        "parent":1
    }
}           
http://localhost:9200/blog/blog/4?routing=1
{
    "name":"王五",
    "comment":"這是一篇非常棒的文章",
    "age":31,
    "date":"2020-05-01",
    "relation":{
        "name":"child",
        "parent":1
    }
}           

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

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

1.3 查詢

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

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

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

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

查詢結果如下:

使用has_child來根據子文檔内容查詢父文檔,其實type就是建立文檔時,子文檔的辨別。

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

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

{
  "query": {
    "has_parent": {
      "parent_type":"parent",
      "query": {
        "match": {
          "title": "這是一篇文章"
        }
      }
    }
  }
}           
由于隻有一組父子文檔,效果不是很明顯,感興趣可以多造一些資料去體驗

聚合查詢與嵌套文檔類似,比較簡單,這裡在說明另外一種場景:祖輩和孫輩可以建立嗎?比如本文中的留言如果它也有子文檔,那麼可以根據文章查詢孫輩嗎?答案是可以的,隻需要在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