一、前言
使用MySQL做为存储,表与表之间有很多是一对多关系,比如订单和订单商品明细,客户和客户地址等等,但是因为ES本身是扁平化文档结构,一般不同索引之间是没有关系的,ES在处理这种关系时相比MySQL并不擅长,不过也提供了几种方式来支持这种关系,下面就以客户和客户地址(一个客户有多个地址)为例来讲述一下各种类型存储的优缺点,正好我们本周一个迭代要把客户数据迁移到ES中。
客户基本信息:first、last、code、email
客户地址信息:city、address
二、数组
ES中其实不存在专用的数组类型,默认情况任何字段都可以包含0个或多个值,不过数组中所有值都必须具有相同的数据类型。
1、基本类型数组
注:addr准备存入多个地址,这里定义为text即可,定义时并没有关键字来设置为数组类型。
注:可以放0或多个值,只要类型一致或可以强制转换就可以存入。
注:可以通过模糊查询查找到该DOC文档。
2、对象数组
注:这个其实就是ES中基本的Object类型
注:addr可以放内嵌对象。
注:对象数组查询结果存在边界问题,查city="Brisbane"并且
address="Ngungug"会把记录给查出来,像地址这里要求不严格的场景是没有什么问题,但是如果是订单内嵌产品列表,我要查出产品编码和价格是指定值的时候,其实是需要严格匹配数组中一个对象,而不是在整个数组中匹配。这个主要是因为ES对JSON对象数据是压扁了存储。
上面的数据实际内部的存储如下,这样存储是丢失了city与address之间映射关系。
三、嵌套
nested(嵌套)类型是object数据类型特殊版本,可以在对象中嵌套对象或者在字段中存储键值对。
1、定义嵌套结构
注:嵌套结构使用nested类型定义。
2、插入文档数据
注:嵌套结构中可以放多个地址信息,另外ES中的put和post指令区别,put需要指定文档ID作用在指定文档上,POST不需要指定文档ID,它是作用在集合上,这个概念源自HTTP协议,HTTP协议定义put操作是幂等的,而POST操作是非幂等的。
3、根据嵌套中内容去查询文档
如果查询换成如下,就不会查出数据,这个就是嵌套结构和对象数组的区别。
对象数据和嵌套存储的区别,使用命令
get _cat/indices?v 查看ES内部真实的文档数量。
可以看出使用nested结构 nested子文档在ES内部其实也是独立的子文档,只是在我们做查询时,ES内部帮我们做了Join处理,所以相对来讲nested在做查询时性能是不如普通内部对象。
四、父子文档
1、定义父子结构
注:使用join表示父子关联结构,relations里的custmoer是父文档,customerAddr是子文档。
2、插入父文档数据
注:这里join_field.name指定了该文档是父文档
3、插入子文档数据
注:这里join_field.name指定了该文档是子文档,parent指定了其父文档类型。请求中设置了routing确保了父子文档在相同的分片上。
4、查询
get customer_parent/_search{}
注:返回父子两个文档
get customer_parent/_doc/customer1
注:只返回父文档的数据
使用has_child查询 :根据子文档条件查询父文档内容
注:只返回父文档内容
使用has_parent查询:根据父文档条件查询子文档内容。
注:只返回子文档内容
五、ES一对多关系几种类型对比
注:我们的客户数据更新很少,大多数情况下是查询,所以最终采用的是nested结构。