• 嵌套-对象
    • 嵌套对象

    嵌套-对象

    嵌套对象

    事实上在Elasticsearch中,创建丶删除丶修改一个文档是是原子性的,因此我们可以在一个文档中储存密切关联的实体。举例来说,我们可以在一个文档中储存一笔订单及其所有内容,或是储存一个Blog文章及其所有回应,藉由传递一个comments阵列:

    1. PUT /my_index/blogpost/1
    2. {
    3. "title": "Nest eggs",
    4. "body": "Making your money work...",
    5. "tags": [ "cash", "shares" ],
    6. "comments": [ <1>
    7. {
    8. "name": "John Smith",
    9. "comment": "Great article",
    10. "age": 28,
    11. "stars": 4,
    12. "date": "2014-09-01"
    13. },
    14. {
    15. "name": "Alice White",
    16. "comment": "More like this please",
    17. "age": 31,
    18. "stars": 5,
    19. "date": "2014-10-22"
    20. }
    21. ]
    22. }

    <1> 如果我们依靠动态映射,comments栏位会被自动建立为一个object栏位。

    因为所有内容都在同一个文档中,使搜寻时并不需要连接(join)blog文章与回应,因此搜寻表现更加优异。

    问题在於以上的文档可能会如下所示的匹配一个搜寻:

    1. GET /_search
    2. {
    3. "query": {
    4. "bool": {
    5. "must": [
    6. { "match": { "name": "Alice" }},
    7. { "match": { "age": 28 }} <1>
    8. ]
    9. }
    10. }
    11. }

    <1> Alice是31岁,而不是28岁!

    造成跨对象配对的原因如同我们在对象阵列中所讨论到,在于我们优美结构的JSON文档在索引中被扁平化为下方的 键-值 形式:

    1. {
    2. "title": [ eggs, nest ],
    3. "body": [ making, money, work, your ],
    4. "tags": [ cash, shares ],
    5. "comments.name": [ alice, john, smith, white ],
    6. "comments.comment": [ article, great, like, more, please, this ],
    7. "comments.age": [ 28, 31 ],
    8. "comments.stars": [ 4, 5 ],
    9. "comments.date": [ 2014-09-01, 2014-10-22 ]
    10. }

    Alice31 以及 John2014-09-01 之间的关联已经无法挽回的消失了。
    object类型的栏位用于储存单一对象是非常有用的。
    从搜寻的角度来看,对於排序一个对象阵列来说关联是不需要的东西。

    这是嵌套对象被设计来解决的问题。 藉由映射commments栏位为nested类型而不是object类型,
    每个嵌套对象会被索引为一个隐藏分割文档,例如:

    1. { <1>
    2. "comments.name": [ john, smith ],
    3. "comments.comment": [ article, great ],
    4. "comments.age": [ 28 ],
    5. "comments.stars": [ 4 ],
    6. "comments.date": [ 2014-09-01 ]
    7. }
    8. { <2>
    9. "comments.name": [ alice, white ],
    10. "comments.comment": [ like, more, please, this ],
    11. "comments.age": [ 31 ],
    12. "comments.stars": [ 5 ],
    13. "comments.date": [ 2014-10-22 ]
    14. }
    15. { <3>
    16. "title": [ eggs, nest ],
    17. "body": [ making, money, work, your ],
    18. "tags": [ cash, shares ]
    19. }

    <1> 第一个嵌套对象

    <2> 第二个嵌套对象

    <3> 根或是父文档

    藉由分别索引每个嵌套对象,对象的栏位中保持了其关联。 我们的查询可以只在同一个嵌套对象都匹配时才回应。

    不仅如此,因嵌套对象都被索引了,连接嵌套对象至根文档的查询速度非常快—几乎与查询单一文档一样快。

    这些额外的嵌套对象被隐藏起来,我们无法直接访问他们。 为了要新增丶修改或移除一个嵌套对象,我们必须重新索引整个文档。
    要牢记搜寻要求的结果并不是只有嵌套对象,而是整个文档。