当前位置:   article > 正文

Elasticsearch之join关联查询_es关联查询

es关联查询

目录

一、join总述

1、关系类比

2、使用限制

3、性能问题

二、Mapping

1、举例说明

 2、mapping释义

三、插入数据

1、插入父文档

2、插入子文档

四、关联查询

1、has_parent查询(父查子)

3、has_child查询(子查父)

目录

一、join总述

1、关系类比

2、使用限制

3、性能问题

二、Mapping

1、举例说明

 2、mapping释义

三、插入数据

1、插入父文档

2、插入子文档

四、关联查询

1、has_parent查询(父查子)

2、parent_id查询(父查子)

3、has_child查询(子查父)


在Elasticsearch这样的分布式系统中执行类似SQL的join连接是代价是非常大的。然而,Elasticsearch却给我们提供了基于水平扩展的两种连接形式


一、join总述

1、关系类比

在关系型数据库中,以MySQL为例,我们经常用到join关键字对有关系的两张或者多张表进行关联查询。但是当数据量达到一定量级时,查询性能就是经常困扰的问题。

由于es可以做到数亿量级的秒查(具体由分片数量决定),这时候把数据同步到es是我们可以使用解决方案之一。

那么不禁有疑问问了,由于业务场景的决定,之前必须关联查询的两张表还能做到进行关联吗?

答案是可以的,es也提供了类似于关系型数据库的关联查询,但是它又与关系型数据的关联查询有明显的区别与限制。

2、使用限制

由于es属于分布式文档型数据库,数据自然是存在于多个分片之上的。Join字段自然不能像关系型数据库中的join使用。在es中为了保证良好的查询性能,最佳的实践是将数据模型设置为非规范化文档,通过字段冗余构造宽表,即存储在一个索引中。

(1)父子文档(数据)必须存储在同一index中

(2)父子文档(数据)必须存储在同一个分片中

(3)一个index中只能包含一个join字段,但是可以有多个关系

(4)同一个index中,一个父关系可以对应多个子关系,一个子关系只对应一个父关系

3、性能问题

当然执行了join查询固然性能会受到一定程度的影响。对于带has_child/has_parent而言,其查询性能会随着指向唯一父文档的匹配子文档的数量增加而降低。开篇第一句摘自es官网描述,从ES官方的描述来看join关联查询对性能的损耗是极大的。

不过,在笔者使用的过程中,在6个分片的前提下,且子表数据量在千万量级的情况下,关联查询的耗时还是在秒内的,许多场景还是可以接受的。

建议我们在使用前,根据分片的多少和预估未来数据量的大小提前做好性能测试,防止以后数量达到一定程度时,性能有明显下降,那个时候再改存储方案得不偿失。


二、Mapping

1、举例说明

这里以优惠券活动与优惠券明细为例,在一个优惠券活动中可以发放几千万的优惠券,所以券活动与券明细是一对多的关系。

券活动表字段

字段说明
activity_id活动ID
activity_name活动名称

券明细表字段

字段说明
coupon_id券ID
coupon_amount券面额
activity_id外键-活动ID

 2、mapping释义

join类型的字段主要用来在同一个索引中构建父子关联关系。通过relations定义一组父子关系,每个关系都包含一个父级关系名称和一个或多个子级关系名称

activity_coupon_field是一个关联字段,内部定义了一组join关系,该字段为自命名

type指定关联关系是join,固定写法

relations定义父子关系,activity父类型名称,coupon子类型名称,名称均为自命名

  1. {
  2. "mappings": {
  3. "properties": {
  4. "activity_coupon_field": {
  5. "type": "join",
  6. "relations": {
  7. "activity": "coupon"
  8. }
  9. },
  10. "activity_id": {
  11. "type": "keyword"
  12. },
  13. "activity_name": {
  14. "type": "keyword"
  15. },
  16. "coupon_id": {
  17. "type": "long"
  18. },
  19. "coupon_amount": {
  20. "type": "long"
  21. }
  22. }
  23. }
  24. }

三、插入数据

1、插入父文档

在put父文档数据的时候,我们通常按照某种规则指定文档ID,方便子文档数据变更时易于得到父文档ID。比如这里我们用activity_id的值:activity_100来作为父id

  1. PUT /coupon/_doc/activity_100
  2. {
  3. "activity_id": 100,
  4. "activity_name": "年货节5元促销优惠券",
  5. "activity_coupon_field": {
  6. "name": "activity"
  7. }
  8. }

2、插入子文档

上边已经指定了父文档ID,而子表中已经包含有activity_id,所以很容易得到父文档ID

put子文档数据时候,必须指定父文档ID,就是父文档中的_id,这样父子数据才建立了关联关系。与此同时还要指定routing字段为父文档ID,这样保证了父子数据在同一分片上。

  1. PUT /coupon/_doc/coupon_711235?routing=activity_id_100
  2. {
  3. "coupon_id": 711235,
  4. "coupon_amount": "5",
  5. "activity_id": 100,
  6. "activity_coupon_field": {
  7. "name": "coupon",
  8. "parent": "activity_id_100" //父ID
  9. }
  10. }

四、关联查询

1、has_parent查询(父查子)

根据父文档条件字段查询符合条件的子文档数据

例如:查询包含“年货节”活动字样,且已经被领取过的券

  1. {
  2. "query": {
  3. "bool": {
  4. "must": [{
  5. "has_parent": {
  6. "parent_type": "activity",
  7. "query": {
  8. "bool": {
  9. "must": [{
  10. "term": {
  11. "status": {
  12. "value": 1
  13. }
  14. }
  15. }, {
  16. "wildcard": {
  17. "activity_name": {
  18. "wildcard": "*年货节*"
  19. }
  20. }
  21. }]
  22. }
  23. }
  24. }
  25. }]
  26. }
  27. }
  28. }

2、parent_id查询(父查子)

根据父文档ID查询,返回满足条件的的子文档记录

例如:查询父文档ID=activity_9899下所有的券信息

  1. {
  2. "query": {
  3. "parent_id": {
  4. "type": "coupon",
  5. "id": "activity_9899"
  6. }
  7. }
  8. }

3、has_child查询(子查父)

根据子文档条件字段符合条件的父文档数据

例如:查询coupon_id=711235在那个存在于哪个券活动中

  1. {
  2. "query": {
  3. "bool": {
  4. "must": [{
  5. "has_child": {
  6. "type": "coupon",
  7. "query": {
  8. "bool": {
  9. "must": [{
  10. "term": {
  11. "coupon_id": {
  12. "value": 711235
  13. }
  14. }
  15. }]
  16. }
  17. }
  18. }
  19. }]
  20. }
  21. }
  22. }

参考:Joining queries | Elasticsearch Guide [7.9] | Elastic

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

闽ICP备14008679号