当前位置:   article > 正文

ElasticSearch父子关联文档实现关系型数据库join操作_es 父子关联

es 父子关联

1. 非规范化数据

比如mysql描述订单以及订单详情 :  order(id, order_no, amount)    ->  order_detail(id, order_id, commodity, price) , 在关系型数据库中一个订单对应多个订单详情,详情表通过order_id与订单表关联。

那么在es中可以通过冗余数据描述这种关系, 索引如下:

  1. PUT order {
  2.     "mappings": {
  3.         "order": {                                 --> 指定文档名(订单表)
  4.             "properties": {                        --> 指定字段以及类型
  5.                 "id": {
  6.                     "type": "integer"
  7.                 },
  8.                 "order_no": {
  9.                     "type": "long"
  10.                 },
  11.                 "amount": {
  12.                     "type": "double"
  13.                 },
  14.                 "order_detail": {                 --> 描述订单详情
  15.                     "properties": {
  16.                         "id": {
  17.                             "type": "integer"
  18.                         },
  19.                         "order_id": {
  20.                             "type": "integer"
  21.                         },
  22.                         "commodity": {
  23.                             "type": "text"
  24.                         },
  25.                         "price": {
  26.                             "type": "double"
  27.                         }
  28.                     }
  29.                 }
  30.             }
  31.         }
  32.     }
  33. }

该索引就是把订单以及订单详情冗余在一起。订单详情可以理解成java实体对象中的集合对象。

2. 父子文档关联

父子文档关联类似于join的操作,通过建立索引的时候描述文档之间的关系

父-子关系文档 在实质上类似于 nested model :允许将一个对象实体和另外一个对象实体关联起来。而这两种类型的主要区别是:在 nested objects 文档中,所有对象都是在同一个文档中,而在父-子关系文档中,父对象和子对象都是完全独立的文档。

父-子关系的主要作用是允许把一个 type 的文档和另外一个 type 的文档关联起来,构成一对多的关系:一个父文档可以对应多个子文档 。与 nested objects 相比,父-子关系的主要优势有:

更新父文档时,不会重新索引子文档。
创建,修改或删除子文档时,不会影响父文档或其他子文档。这一点在这种场景下尤其有用:子文档数量较多,并且子文档创建和修改的频率高时。
子文档可以作为搜索结果独立返回。
Elasticsearch 维护了一个父文档和子文档的映射关系,得益于这个映射,父-子文档关联查询操作非常快。但是这个映射也对父-子文档关系有个限制条件:父文档和其所有子文档,都必须要存储在同一个分片中。

父-子文档ID映射存储在 Doc Values 中。当映射完全在内存中时, Doc Values 提供对映射的快速处理能力,另一方面当映射非常大时,可以通过溢出到磁盘提供足够的扩展能力

建立索引:

  1. PUT order
  2. {
  3.   "mappings": {
  4.     "order": {            --> 父文档
  5.       "properties": {     --> 父文档字段属性
  6.         "id": {
  7.           "type": "integer"
  8.         },
  9.         "order_no": {
  10.           "type": "long"
  11.         },
  12.         "amount": {
  13.           "type": "double"
  14.         }
  15.       }
  16.     },
  17.     "order_detail": {    --> 子文档
  18.       "_parent": {       --> 指定子文档的父亲
  19.         "type": "order"
  20.       },
  21.       "properties": {
  22.         "id": { "type": "integer" },
  23.         "order_id": { "type": "integer" },
  24.         "commodity": { "type": "text" },
  25.         "price": { "type": "double" }
  26.       }
  27.     }
  28.   }
  29. }


创建父文档:

  1. PUT /order/order/1        --> PUT /索引/文档/唯一标识(不写默认生成)
  2. {
  3.   "id": "1",
  4.   "order_no": "123456",
  5.   "amount": "20"
  6. }
  7. 创建子文档:
  8. PUT /order/order_detail/1?parent=1      -->  在创建子文档的时候需要使用parent=?指定父文档是谁!!!该处指定父文档为标识为1的order
  9. {
  10.   "id": "1",
  11.   "order_id": "1",
  12.   "commodity": "小米",
  13.   "price": "15"
  14. }
  15. PUT order/order_detail/2?parent=1
  16. {
  17.   "id": "2",
  18.   "order_id": "1",
  19.   "commodity": "番茄",
  20.   "price": "5"
  21. }
  22. 查询父文档,并显示所有子文档:
  23. GET order/order/_search
  24. {
  25.   "query": {
  26.     "has_child": {
  27.       "type": "order_detail",
  28.       "query": {
  29.         "match_all": {}
  30.       },
  31.       "inner_hits": {}            --> 显示所有子文档
  32.     }
  33.   }
  34. }


查询结果:

  1. {
  2.   "took": 2,
  3.   "timed_out": false,
  4.   "_shards": {
  5.     "total": 5,
  6.     "successful": 5,
  7.     "skipped": 0,
  8.     "failed": 0
  9.   },
  10.   "hits": {
  11.     "total": 1,
  12.     "max_score": 1,
  13.     "hits": [
  14.       {
  15.         "_index": "order",
  16.         "_type": "order",
  17.         "_id": "1",
  18.         "_score": 1,
  19.         "_source": {
  20.           "id": "1",
  21.           "order_no": "123456",
  22.           "amount": "20"
  23.         },
  24.         "inner_hits": {
  25.           "order_detail": {
  26.             "hits": {
  27.               "total": 2,
  28.               "max_score": 1,
  29.               "hits": [
  30.                 {
  31.                   "_type": "order_detail",
  32.                   "_id": "1",
  33.                   "_score": 1,
  34.                   "_routing": "1",
  35.                   "_parent": "1",
  36.                   "_source": {
  37.                     "id": "1",
  38.                     "order_id": "1",
  39.                     "commodity": "小米",
  40.                     "price": "15"
  41.                   }
  42.                 },
  43.                 {
  44.                   "_type": "order_detail",
  45.                   "_id": "2",
  46.                   "_score": 1,
  47.                   "_routing": "1",
  48.                   "_parent": "1",
  49.                   "_source": {
  50.                     "id": "2",
  51.                     "order_id": "1",
  52.                     "commodity": "番茄",
  53.                     "price": "5"
  54.                   }
  55.                 }
  56.               ]
  57.             }
  58.           }
  59.         }
  60.       }
  61.     ]
  62.   }
  63. }


复杂父子文档聚合查询:  

  1. GET order/order/_search
  2. {
  3.   "size": 0,                  
  4.   "aggs": {
  5.     "sum_amount": {              -->指定聚合文档order,求amount字段sum值,并取名为sum_amount
  6.       "sum": {
  7.         "field": "amount"
  8.       }
  9.     },
  10.     "detail": {
  11.       "children": {              --> 指定子文档为order_detail
  12.         "type": "order_detail"
  13.       },
  14.       "aggs": {                  --> 子文档聚合操作,求子文档price字段sum值,并取名为sum_price
  15.         "sum_price": {
  16.           "sum": {
  17.             "field": "price"
  18.           }
  19.         }
  20.       }
  21.     }
  22.   }
  23. }


查询结果:

  1. {
  2.   "took": 0,
  3.   "timed_out": false,
  4.   "_shards": {
  5.     "total": 5,
  6.     "successful": 5,
  7.     "skipped": 0,
  8.     "failed": 0
  9.   },
  10.   "hits": {
  11.     "total": 1,            --> order文档一共一条记录
  12.     "max_score": 0,
  13.     "hits": []
  14.   },
  15.   "aggregations": {
  16.     "sum_amount": {        --> 父文档sum(amount)结果
  17.       "value": 20
  18.     },
  19.     "detail": {            --> 子文档
  20.       "doc_count": 2,      --> 子文档一共两条记录
  21.       "sum_price": {       --> 子文档sum(price)结果
  22.         "value": 20
  23.       }
  24.     }
  25.   }
  26. }


 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/580241
推荐阅读
相关标签
  

闽ICP备14008679号