首页 > 其他分享 >Elasticsearch之join关联查询及使用场景 | 京东云技术团队

Elasticsearch之join关联查询及使用场景 | 京东云技术团队

时间:2023-05-25 11:32:07浏览次数:58  
标签:join coupon 查询 Elasticsearch activity 文档 京东 id

在Elasticsearch这样的分布式系统中执行类似SQL的join连接是代价是比较大的,然而,Elasticsearch却给我们提供了基于水平扩展的两种连接形式 。这句话摘自Elasticsearch官网,从“然而”来看,说明某些场景某些情况下我们还是可以使用的

一、join总述

1、关系类比

在关系型数据库中,以MySQL为例,尤其B端类系统且数据量不是特别大的场景,我们经常用到join关键字对有关系的两张或者多张表进行关联查询。但是当数据量达到一定量级时,查询性能就是经常困扰的问题。由于es可以做到数亿量级的秒查(具体由分片数量决定),这时候把数据同步到es是我们可以使用解决方案之一。

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

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

2、使用场景

如果把关系数据库原有关联的两张表,同步到es后,通常情况下,我们业务开发中会有两种查询诉求的场景

场景1

诉求:展示子表维度的明细数据(包含父表和子表中字段的条件)

方案:对于此种查询诉求,我们可以把原来关联的父子表打成父子表字段混合在一起的大宽表,既能满足查询条件,又有查询性能的保障,也是常用存储方案之一

场景2

诉求:展示父表维度的明细数据(包含父表和子表中字段的条件)

方案:然而,对于此种查询诉求,需要通过子表的条件来查询出父表的明细结果,场景1的宽表存储方案是子表明细数据,而最终我们要的是父表明细数据,显然对于场景1的存储方案是不能满足的。如果非要使用场景1的存储方案,我们还要对宽表结果进行一次groupby或者collapse操作来得到父表结果。

这个时候我们就可以使用es提供的join功能来完成场景2的诉求查询,同时它也满足场景1的诉求查询

3、使用限制

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

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

(2)父子文档(数据)必须存储在同一个分片中,通过关联父文档ID关联

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

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

4、性能问题

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

不过,在笔者使用的过程中,在5个分片的前提下,且父表十万量级,子表数据量在千万量级的情况下,关联查询的耗时还是在100ms内完成的,对于B端许多场景还是可以接受的。

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

二、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子类型名称,名称均为自命名

{
	"mappings": {
		"properties": {
			"activity_coupon_field": {
				"type": "join",
				"relations": {
					"activity": "coupon"
				}
			},
			"activity_id": {
				"type": "keyword"
			},
			"activity_name": {
				"type": "keyword"
			},
			"coupon_id": {
				"type": "long"
			},
			"coupon_amount": {
				"type": "long"
			}
		}
	}
}

三、插入数据

1、插入父文档

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

PUT /coupon/_doc/activity_100
 
{
	"activity_id": 100,
	"activity_name": "年货节5元促销优惠券",
	"activity_coupon_field": {
		"name": "activity"
	}
}

2、插入子文档

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

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

PUT /coupon/_doc/coupon_12345678?routing=activity_id_100
 
{
	"coupon_id": 12345678,
	"coupon_amount": "5",
	"activity_id": 100,
	"activity_coupon_field": {
		"name": "coupon",
		"parent": "activity_id_100" //父ID
	}
}

四、关联查询

1、has\_parent查询(父查子)

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

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

{
	"query": {
		"bool": {
			"must": [{
				"parent_type": "activity",
				"has_parent": {
					"query": {
						"bool": {
							"must": [{
								"term": {
									"status": {
										"value": 1
									}
								}
							}, {
								"wildcard": {
									"activity_name": {
										"wildcard": "*年货节*"
									}
								}
							}]
						}
					}
				}
			}]
		}
	}
}

2、has\_child查询(子查父)

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

例如:查询coupon\_id=12345678在那个存在于哪个券活动中

{
	"query": {
		"bool": {
			"must": [{
				"has_child": {
					"type": "coupon",
					"query": {
						"bool": {
							"must": [{
								"term": {
									"coupon_id": {
										"value": 12345678
									}
								}
							}]
						}
					}
				}
			}]
		}
	}
}

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

以上文中如有不正之处欢迎留言指正

作者:京东零售 李振乾

内容来源:京东云开发者社区

标签:join,coupon,查询,Elasticsearch,activity,文档,京东,id
From: https://blog.51cto.com/u_15714439/6346271

相关文章

  • elasticsearch在启动后出现[transport.netty][solr001] exception caught on transpor
    elasticsearch在启动后出现如下错误:[2019-04-18T09:29:57,850][WARN][o.e.t.n.Netty4Transport ][xHaZmSP]exceptioncaughtontransportlayer[[id:0xe6246f88,L:/127.0.0.1:9300-R:/127.0.0.1:9493]],closingconnectionjava.io.IOException:杩滅▼涓绘満寮鸿揩鍏......
  • 【ElasticSearch】关于es跨域的问题
    本文目录一、使用es的head插件二、其他说明一、使用es的head插件在使用es的head插件时,默认的9100,需要访问es的默认端口9200时,会出现跨域问题,此时只需要修改一下es的配置文件即可。在elasticsearch.yml中添加开启跨域的配置:http.cors.enabled:truehttp.cors.allow-origin:"*"说明......
  • elasticsearch/es搜索服务器介绍
    目录1、ElasticSearch介绍1.1原理与应用2、ElasticaSearch的的安装使用2.1安装2.2配置文件2.3启动ES2.4head插件安装1、ElasticSearch介绍我们先来看下百度百科的介绍:ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTfulwe......
  • 使用canal同步mysql数据到elasticsearch
    官方去下载canal包https://github.com/alibaba/canal/releases/tag/canal-1.1.6分为deployer、admin、adapter三个模块。deployer是数据库数据同步服务端。adapter是适配同步到不同终端,可以是es,hbase,redis其它数据库等。admin是一个配置管理中心,但是吧又没有配置adapter的界面,a......
  • 淘宝京东1688拼多多商品详情API接口,关键词搜索,按图搜索,店铺所有商品
    商品详情API接口数据:淘宝提供了商品的基本信息,包括商品名称、描述、规格、价格、销量、库存等信息。此外,也可以通过淘宝提供的API接口来获取商品的图片、评价、物流信息等详细数据。item_get-获得京东商品详情请求参数(API接口接入点击上方API)请求参数:num_iid=10558877110参......
  • 京东数科java一面【过】
    自我介绍实习经历【聊了挺多】集合方面Collection【list(写时复制)/set/Queue(阻塞队列)】Map【HashTable/HashMap/ConcorrentHashMap】synchronized对象头原理的过程A系统1WTBS,B系统300TBS,问解决方法技术角度:读写分离、Kong层、加服务器业务角度:加锁、加进度条AQS是什么原理Volat......
  • 开发者福利来了 | 京东云全系核心产品公开比价:我们承诺,买贵就赔!
    今天我们官宣一件大事:京东云开启中国云市场的首次公开比价活动,承诺“买贵就赔”!比价活动的底气,来源于京东云对技术降本的不懈追求——京东二十年来大规模的场景实践,推动京东云持续加大自研技术投入,提高资源利用率,进而最大化降低成本。今年3月,京东云负责人在京东云城市峰会广州站......
  • Linux下Elasticsearch集群搭建
    在每台服务器上安装ES,此处略过,如需要请查看过往文章。集群的搭建主要是修改每个节点的配置文件(elasticsearch.yml)#集群名称cluster.name:veolia-es-cluster#节点名称node.name:es02#是否作为主节点(每个节点都配置true)node.master:truenode.data:true#IPnetwor......
  • 开发者福利来了 | 京东云全系核心产品公开比价:我们承诺,买贵就赔!
    今天我们官宣一件大事:京东云开启中国云市场的首次公开比价活动,承诺“买贵就赔”!比价活动的底气,来源于京东云对技术降本的不懈追求——京东二十年来大规模的场景实践,推动京东云持续加大自研技术投入,提高资源利用率,进而最大化降低成本。今年3月,京东云负责人在京东云城市峰会广州站上......
  • java将wkt面数据转geojson和elasticsearch的shape数据
    wkt面数据转geojsonimportcom.alibaba.fastjson.JSONException;importcom.alibaba.fastjson.JSONObject;importorg.locationtech.jts.geom.Coordinate;importorg.locationtech.jts.geom.Geometry;importorg.locationtech.jts.io.ParseException;importorg.location......