天天看點

ES 6.x父子文檔

0、ES6.X 一對多、多對多的資料該如何存儲和實作呢?

引出問題:

“某頭條新聞APP”新聞内容和新聞評論是1對多的關系?

在ES6.X該如何存儲、如何進行高效檢索、聚合操作呢?

相信閱讀本文,你就能得到答案!

1、ES6.X 新類型Join 産生背景

  • Mysql中多表關聯,我們可以通過left join 或者Join等實作;
  • ES5.X版本,借助父子文檔實作多表關聯,類似資料庫中Join的功能;實作的核心是借助于ES5.X支援1個索引(index)下多個類型(type)。
  • ES6.X版本,由于每個索引下面隻支援單一的類型(type)。
  • 是以,ES6.X版本如何實作Join成為大家關注的問題。

幸好,ES6.X新推出了Join類型,主要解決類似Mysql中多表關聯的問題。

2、ES6.X Join類型介紹

仍然是一個索引下,借助父子關系,實作類似Mysql中多表關聯的操作。

3、ES6.X Join類型實戰

3.1 ES6.X Join類型 Mapping定義

Join類型的Mapping如下:

核心

  • 1) "my_join_field"為join的名稱。
  • 2)"question": "answer" 指:qustion為answer的父類。

1PUT my_join_index

2{

3  "mappings": {

4    "_doc": {

5      "properties": {

6        "my_join_field": {

7          "type": "join",

8          "relations": {

9            "question": "answer"

10          }

11        }

12      }

13    }

14  }

15}

3.2 ES6.X join類型定義父文檔

直接上以下簡化的形式,更好了解些。

如下,定義了兩篇父文檔。

文檔類型為父類型:"question"。

1PUT my_join_index/_doc/1?refresh

3  "text": "This is a question",

4  "my_join_field": "question"

5}

6PUT my_join_index/_doc/2?refresh

7{

8  "text": "This is another question",

9  "my_join_field": "question"

10}

3.3 ES6.X join類型定義子文檔

  • 路由值是強制性的,因為父檔案和子檔案必須在相同的分片上建立索引。
  • "answer"是此子文檔的加入名稱。
  • 指定此子文檔的父文檔ID:1。

1PUT my_join_index/_doc/3?routing=1&refresh

3  "text": "This is an answer",

4  "my_join_field": {

5    "name": "answer",

6    "parent": "1"

7  }

8}

9PUT my_join_index/_doc/4?routing=1&refresh

10{

11  "text": "This is another answer",

12  "my_join_field": {

13    "name": "answer",

14    "parent": "1"

15  }

16}

4、ES6.X Join類型限制

  1. 每個索引隻允許一個Join類型Mapping定義;
  2. 父文檔和子文檔必須在同一個分片上編入索引;這意味着,當進行删除、更新、查找子文檔時候需要提供相同的路由值。
  3. 一個文檔可以有多個子文檔,但隻能有一個父文檔。
  4. 可以為已經存在的Join類型添加新的關系。
  5. 當一個文檔已經成為父文檔後,可以為該文檔添加子文檔。

5、ES6.X Join類型檢索與聚合

5.1 ES6.X Join全量檢索

1GET my_join_index/_search

2{

3  "query": {

4    "match_all": {}

5  },

6  "sort": ["_id"]

7}

傳回結果如下:

1{

2  "took": 1,

3  "timed_out": false,

4  "_shards": {

5    "total": 5,

6    "successful": 5,

7    "skipped": 0,

8    "failed": 0

9  },

10  "hits": {

11    "total": 4,

12    "max_score": null,

13    "hits": [

14      {

15        "_index": "my_join_index",

16        "_type": "_doc",

17        "_id": "1",

18        "_score": null,

19        "_source": {

20          "text": "This is a question",

21          "my_join_field": "question"

22        },

23        "sort": [

24          "1"

25        ]

26      },

27      {

28        "_index": "my_join_index",

29        "_type": "_doc",

30        "_id": "2",

31        "_score": null,

32        "_source": {

33          "text": "This is another question",

34          "my_join_field": "question"

35        },

36        "sort": [

37          "2"

38        ]

39      },

40      {

41        "_index": "my_join_index",

42        "_type": "_doc",

43        "_id": "3",

44        "_score": null,

45        "_routing": "1",

46        "_source": {

47          "text": "This is an answer",

48          "my_join_field": {

49            "name": "answer",

50            "parent": "1"

51          }

52        },

53        "sort": [

54          "3"

55        ]

56      },

57      {

58        "_index": "my_join_index",

59        "_type": "_doc",

60        "_id": "4",

61        "_score": null,

62        "_routing": "1",

63        "_source": {

64          "text": "This is another answer",

65          "my_join_field": {

66            "name": "answer",

67            "parent": "1"

68          }

69        },

70        "sort": [

71          "4"

72        ]

73      }

74    ]

75  }

76}

5.2 ES6.X 基于父文檔查找子文檔

3    "query": {

4        "has_parent" : {

5            "parent_type" : "question",

6            "query" : {

7                "match" : {

8                    "text" : "This is"

9                }

10            }

12    }

13}

傳回結果:

2  "took": 0,

11    "total": 2,

12    "max_score": 1,

17        "_id": "3",

18        "_score": 1,

19        "_routing": "1",

20        "_source": {

21          "text": "This is an answer",

22          "my_join_field": {

23            "name": "answer",

24            "parent": "1"

25          }

26        }

27      },

28      {

29        "_index": "my_join_index",

30        "_type": "_doc",

31        "_id": "4",

32        "_score": 1,

33        "_routing": "1",

34        "_source": {

35          "text": "This is another answer",

36          "my_join_field": {

37            "name": "answer",

38            "parent": "1"

39          }

40        }

41      }

42    ]

43  }

44}

5.3 ES6.X 基于子文檔查找父文檔

3"query": {

4        "has_child" : {

5            "type" : "answer",

8                    "text" : "This is question"

11    "total": 1,

22        }

23      }

24    ]

25  }

26}

5.4 ES6.X Join聚合操作實戰

以下操作含義如下:

  • 1)parent_id是特定的檢索方式,用于檢索屬于特定父文檔id=1的,子文檔類型為answer的文檔的個數。
  • 2)基于父文檔類型question進行聚合;
  • 3)基于指定的field處理。

3  "query": {

4    "parent_id": {

5      "type": "answer",

6      "id": "1"

7    }

8  },

9  "aggs": {

10    "parents": {

11      "terms": {

12        "field": "my_join_field#question",

13        "size": 10

14      }

15    }

16  },

17  "script_fields": {

18    "parent": {

19      "script": {

20         "source": "doc['my_join_field#question']"

21      }

22    }

23  }

24}

12    "max_score": 0.13353139,

18        "_score": 0.13353139,

20        "fields": {

21          "parent": [

22            "1"

23          ]

24        }

25      },

26      {

27        "_index": "my_join_index",

28        "_type": "_doc",

29        "_id": "4",

30        "_score": 0.13353139,

31        "_routing": "1",

32        "fields": {

33          "parent": [

34            "1"

35          ]

36        }

37      }

38    ]

39  },

40  "aggregations": {

41    "parents": {

42      "doc_count_error_upper_bound": 0,

43      "sum_other_doc_count": 0,

44      "buckets": [

45        {

46          "key": "1",

47          "doc_count": 2

48        }

49      ]

50    }

51  }

52}

6、ES6.X Join 一對多實戰

6.1 一對多定義

如下,一個父文檔question與多個子文檔answer,comment的映射定義。

1PUT join_ext_index

6        "my_join_field": {

9            "question": ["answer", "comment"]  

6.2 一對多對多定義

實作如下圖的祖孫三代關聯關系的定義。

1question

2    /    \

3   /      \

4comment  answer

5           |

6           |

7          vote

1PUT join_multi_index

9            "question": ["answer", "comment"],  

10            "answer": "vote"

11          }

12        }

13      }

14    }

孫子文檔導入資料,如下所示:

1PUT join_multi_index/_doc/3?routing=1&refresh

3  "text": "This is a vote",

4  "my_join_field": {

5    "name": "vote",

6    "parent": "2"

7  }

8}

注意:

7、小結

螃蟹在剝我的殼,筆記本在寫我,漫天的我落在楓葉上雪花上,而你在想我。

--章懷柔

繼續閱讀