wordpress网站底部版权代码,如何创建一个站点,微信怎么自建小程序商店,网页设计是干嘛的在使用关系数据库进行开发的过程中#xff0c;你可能会经常使用外键来表示父表和子表之间的关联关系#xff0c;在Elasticsearch中#xff0c;有哪些方法可以用来让开发者解决索引之间一对多和多对多的关联关系的问题呢
1 使用对象数组存在的问题
你可以很方便地把一个对象…在使用关系数据库进行开发的过程中你可能会经常使用外键来表示父表和子表之间的关联关系在Elasticsearch中有哪些方法可以用来让开发者解决索引之间一对多和多对多的关联关系的问题呢
1 使用对象数组存在的问题
你可以很方便地把一个对象以数组的形式放在索引的字段中。下面的请求将建立一个订单索引里面包含对象字段“goods”它用来存放订单包含的多个商品的数据从而在订单和商品之间建立起一对多的关联。
PUT order-obj-array
{mappings: {properties: {orderid: {type: integer},buyer: {type: keyword},order_time: {type: date,format: yyyy-MM-dd HH:mm:ss},goods: {properties: {goodsid: {type: integer},goods_name: {type: keyword},price: {type: double},produce_time: {type: date,format: yyyy-MM-dd HH:mm:ss}}}}}
}现在向这个索引中添加一条订单数据里面包含两个商品的数据。
PUT order-obj-array/_doc/1
{orderid: 1,buyer: tom,order_time: 2020-11-04 00:00:00,goods: [{goodsid: 1,goods_name: milk,price: 5.2,produce_time: 2020-10-04 00:00:00},{goodsid: 2,goods_name: juice,price: 8.2,produce_time: 2020-10-12 00:00:00}]
}这样做虽然可以把商品数据关联到订单数据中但是在做多条件搜索的时候会出现问题比如下面的布尔查询相关代码其中包含两个简单的match搜索条件。
POST order-obj-array/_search
{query: {bool: {must: [{match: {goods.goods_name: juice}},{match: {goods.produce_time: 2020-10-04 00:00:00}}]}}
}从业务的角度讲由于“juice”的生产日期是“2020-10-12 00:00:00”所以这一搜索不应该搜到订单数据然而实际上却能搜到代码如下。
hits : {total : {value : 1,relation : eq},max_score : 1.3616575,hits : [{_index : order-obj-array,_type : _doc,_id : 1,_score : 1.3616575,_source : {orderid : 1,buyer : tom,order_time : 2020-11-04 00:00:00,goods : [{goodsid : 1,goods_name : milk,price : 5.2,produce_time : 2020-10-04 00:00:00},{goodsid : 2,goods_name : juice,price : 8.2,produce_time : 2020-10-12 00:00:00}]}}]}之所以会产生这种效果是因为Elasticsearch在保存对象数组的时候会把数据展平产生类似下面代码的效果。 goods.goods_name : [ milk, juice ],goods.produce_time : [ 2020-10-04 00:00:00, 2020-10-12 00:00:00 ]这导致的直接后果是你无法将每个商品的数据以独立整体的形式进行检索使得检索结果存在错误。
2、在索引中使用join字段
PUT order-join
{settings: {number_of_shards: 5,number_of_replicas: 1},mappings: {properties: {orderid: {type: integer},buyer: {type: keyword},order_time: {type: date,format: yyyy-MM-dd HH:mm:ss},goodsid: {type: integer},goods_name: {type: keyword},price: {type: double},produce_time: {type: date,format: yyyy-MM-dd HH:mm:ss},my_join_field: {type: join,relations: {order: goods}}}}
}可以看出这个映射包含订单父文档和商品子文档的全部字段并且在末尾添加了一个名为my_join_field的join字段。在relations属性中定义了一对父子关系order是父关系的名称goods是子关系的名称。
由于父文档和子文档被写进了同一个索引在添加索引数据的时候需要指明是在为哪个关系添加文档。先添加一个父文档它是一条订单数据在这条数据中把join字段的关系名称指定为order表明它是一个父文档。
PUT order-join/_doc/1
{orderid: 1,buyer: tom,order_time: 2020-11-04 00:00:00,my_join_field: {name:order}
}然后为该订单数据添加两个子文档也就是商品数据。
PUT order-join/_doc/2?routing1
{goodsid: 1,goods_name: milk,price: 5.2,produce_time: 2020-10-04 00:00:00,my_join_field: {name: goods,parent: 1}
}
PUT order-join/_doc/3?routing1
{goodsid: 2,goods_name: juice,price: 8.2,produce_time: 2020-10-12 00:00:00,my_join_field: {name: goods,parent: 1}
}在添加子文档时有两个地方需要注意。一是必须使用父文档的主键作为路由值由于订单数据的主键是1因此这里使用1作为路由值这能确保子文档被分发到父文档所在的分片上。如果路由值设置错误搜索的时候就会出现问题。
二是在join字段my_join_field中要把name设置为goods表示它是一个子文档parent要设置为父文档的主键类似于一个外键。由于join字段中每个子文档是独立添加的你可以对某个父文档添加、删除、修改某个子文档嵌套对象则无法实现这一点。由于写入数据时带有路由值如果要修改主键为3的子文档修改时也需要携带路由值代码如下。
POST order-join/_update/3?routing1
{doc: {price: 18.2}
}2.2 join字段的搜索
由于join类型把父、子文档都写入了同一个索引因此如果你需要单独检索父文档或者子文档只需要用简单的term查询就可以筛选出它们。
POST order-join/_search
{query: {term: {my_join_field: goods}}
}可见整个搜索过程与普通的索引过程没有什么区别。但是包含join字段的索引支持一些用于检索父子关联的特殊搜索方式。例如以父搜子允许你使用父文档的搜索条件查出子文档以子搜父允许你使用子文档的搜索条件查出父文档父文档主键搜索允许使用父文档的主键值查出与其存在关联的所有子文档。接下来逐个说明。
2.3.以父搜子
以父搜子指的是使用父文档的条件搜索子文档例如你可以用订单的购买者数据作为条件搜索相关的商品数据。
POST order-join/_search
{query: {has_parent: {parent_type: order,query: {term: {buyer: {value: tom}}}}}
}在这个请求体中把搜索类型设置为has_parent表示这是一个以父搜子的请求参数parent_type用于设置父关系的名称在查询条件中使用term query检索了购买者tom的订单但是返回的结果是tom的与订单关联的商品列表如下所示。
hits : [{_index : order-join,_type : _doc,_id : 2,_score : 1.0,_routing : 1,_source : {goodsid : 1,goods_name : milk,price : 5.2,produce_time : 2020-10-04 00:00:00,my_join_field : {name : goods,parent : 1}}},{_index : order-join,_type : _doc,_id : 3,_score : 1.0,_routing : 1,_source : {goodsid : 2,goods_name : juice,price : 18.2,produce_time : 2020-10-12 00:00:00,my_join_field : {name : goods,parent : 1}}}]需要记住以父搜子的时候提供的查询条件用于筛选父文档返回的结果是对应的子文档。如果需要在搜索结果中把父文档也一起返回则需要加上inner_hits参数。
POST order-join/_search
{query: {has_parent: {parent_type: order,query: {term: {buyer: {value: tom}}},inner_hits: {}}}
}2.4以子搜父
以子搜父跟以父搜子相反提供子文档的查询条件会返回父文档的数据。例如
POST order-join/_search
{query: {has_child: {type: goods,query: {match_all: {}}}}
}上面的请求把搜索类型设置为has_child在参数type中指明子关系的名称它会返回所有子文档对应的父文档。但是如果一个父文档没有子文档则其不会出现在搜索结果中。相关代码如下。
hits : [{_index : order-join,_type : _doc,_id : 1,_score : 1.0,_source : {orderid : 1,buyer : tom,order_time : 2020-11-04 00:00:00,my_join_field : {name : order}}}]你还可以根据子文档匹配搜索结果的数目来限制返回结果例如
POST order-join/_search
{query: {has_child: {type: goods,query: {match_all: {}},max_children: 1}}
}上述代码表示如果子文档在query参数中指定的搜索结果数量大于1就不返回它对应的父文档。你还可以使用min_children参数限制子文档匹配数目的下限。
3.5父文档主键搜索
父文档主键搜索只需要提供父文档的主键就能返回该父文档所有的子文档。例如你可以提供订单的主键返回该订单所有的子文档。
POST order-join/_search
{query: {parent_id: {type: goods,id: 1}}
}其中type用于指定子文档的关系名称id表示父文档的主键该查询请求会搜出订单号为1的所有商品的数据如下所示。
3 join字段的聚集
join字段有两种专门的聚集方式一种是children聚集它可用于统计每个父文档的子文档数据另一种是parent聚集它可用于统计每个子文档的父文档数据。
3.1. children聚集
你可以在一个父文档的聚集中嵌套一个children聚集这样就可以在父文档的统计结果中加入子文档的统计结果。为了演示效果下面再添加两条测试数据。
POST order-join/_doc/4
{orderid: 4,buyer: mike,order_time: 2020-12-04 00:00:00,my_join_field: {name:order}
}
POST order-join/_doc/5?routing4
{goodsid: 5,goods_name: milk,price: 3.6,produce_time: 2020-11-04 00:00:00,my_join_field: {name: goods,parent: 4}
}然后发起一个聚集请求统计出每个购买者购买的商品名称和数量。
POST order-join/_search
{query: {match_all: {}},aggs: {orders: {terms: {field: buyer,size: 10},aggs: {goods_data: {children: {type: goods},aggs: {goods_name: {terms: {field: goods_name,size: 10}}}}}}}
}可以看到这个请求首先对buyer做了词条聚集它会得到每个购买者的订单统计数据为了获取每个购买者购买的商品详情在词条聚集中嵌套了一个children聚集在其中指定了子文档的关系名然后继续嵌套一个词条聚集统计每个商品的数据得到每个购买者的商品列表。结果如下。
aggregations : {orders : {doc_count_error_upper_bound : 0,sum_other_doc_count : 0,buckets : [{key : mike,doc_count : 1,goods_data : {doc_count : 1,goods_name : {doc_count_error_upper_bound : 0,sum_other_doc_count : 0,buckets : [{key : milk,doc_count : 1}]}}},{key : tom,doc_count : 1,goods_data : {doc_count : 2,goods_name : {doc_count_error_upper_bound : 0,sum_other_doc_count : 0,buckets : [{key : juice,doc_count : 1},{key : milk,doc_count : 1}]}}}]}}3.2. parent聚集
parent聚集跟children聚集相反你可以在子文档的聚集中嵌套一个parent聚集就能得到每个子文档数据对应的父文档统计数据。例如
POST order-join/_search
{aggs: {goods: {terms: {field: goods_name,size: 10},aggs: {goods_data: {parent: {type: goods},aggs: {orders: {terms: {field: buyer,size: 10}}}}}}}
}上面的请求首先在goods_name字段上对子文档做了词条聚集会得到每个商品的统计数据为了查看每个商品的购买者统计数据在词条聚集中嵌套了一个parent聚集需注意该聚集需要指定子关系的名称而不是父关系的名称。最后在parent聚集中又嵌套了一个词条聚集以获得每种商品的购买者统计数据结果如下。
aggregations : {goods : {doc_count_error_upper_bound : 0,sum_other_doc_count : 0,buckets : [{key : milk,doc_count : 2,goods_data : {doc_count : 2,orders : {doc_count_error_upper_bound : 0,sum_other_doc_count : 0,buckets : [{key : mike,doc_count : 1},{key : tom,doc_count : 1}]}}},{key : juice,doc_count : 1,goods_data : {doc_count : 1,orders : {doc_count_error_upper_bound : 0,sum_other_doc_count : 0,buckets : [{key : tom,doc_count : 1}]}}}]}最后来总结一下join字段在解决父子关联时的优缺点。它允许单独更新或删除子文档嵌套对象则做不到建索引时需要先写入父文档的数据然后携带路由值写入子文档的数据由于父、子文档在同一个分片上join关联查询的过程没有网络开销可以快速地返回查询结果。但是由于join字段会带来一定的额外内存开销建议使用它时父子关联的层级数不要大于2它在子文档的数量远超过父文档的时比较适用。
3.3 在应用层关联数据
所谓在应用层关联数据实际上并不使用任何特别的字段直接像关系数据库一样在建模时使用外键字段做父子关联做关联查询和统计时需要多次发送请求。这里还是以订单和商品为例需要为它们各建立一个索引然后在商品索引中添加一个外键字段orderid来指向订单索引代码如下。
PUT orders
{mappings: {properties: {orderid: {type: integer},buyer: {type: keyword},order_time: {type: date,format: yyyy-MM-dd HH:mm:ss}}}
}
PUT goods
{mappings: {properties: {goodsid: {type: integer},goods_name: {type: keyword},price: {type: double},produce_time: {type: date,format: yyyy-MM-dd HH:mm:ss},orderid: {type: integer}}}
}然后向两个索引中添加数据。
PUT orders/_doc/1
{orderid: 1,buyer: tom,order_time: 2020-11-04 00:00:00
}
PUT goods/_bulk
{index:{_id:1}}
{goodsid:1,goods_name:milk,price:5.2,produce_time:2020-10-04 00:00:00,orderid:1}
{index:{_id:2}}
{goodsid:2,goods_name:juice,price:8.2,produce_time:2020-10-12 00:00:00,orderid:1}此时如果你想获得以父搜子的效果就得发送两次请求例如搜索tom的所有订单以及它们包含的商品先使用term查询tom的所有订单数据。
POST orders/_search
{query: {term: {buyer: {value: tom}}}
}然后使用搜索结果返回的orderid去搜索商品索引。
POST goods/_search
{query: {terms: {orderid: [1]}}
}可以看到这样做也能达到目的但是如果第一次搜索返回的orderid太多就会引起性能下降甚至出错。总之在应用层关联数据的优点是操作比较简单缺点是请求次数会变多如果用于二次查询的条件过多也会引起性能下降在实际使用时需要根据业务逻辑来进行权衡。 文章转载自: http://www.morning.lgcqj.cn.gov.cn.lgcqj.cn http://www.morning.qprtm.cn.gov.cn.qprtm.cn http://www.morning.brhxd.cn.gov.cn.brhxd.cn http://www.morning.wqsjx.cn.gov.cn.wqsjx.cn http://www.morning.bqwrn.cn.gov.cn.bqwrn.cn http://www.morning.rpljf.cn.gov.cn.rpljf.cn http://www.morning.sjli222.cn.gov.cn.sjli222.cn http://www.morning.nmngq.cn.gov.cn.nmngq.cn http://www.morning.juju8.cn.gov.cn.juju8.cn http://www.morning.jwcmq.cn.gov.cn.jwcmq.cn http://www.morning.cbynh.cn.gov.cn.cbynh.cn http://www.morning.kzhxy.cn.gov.cn.kzhxy.cn http://www.morning.yqsr.cn.gov.cn.yqsr.cn http://www.morning.knnc.cn.gov.cn.knnc.cn http://www.morning.jftl.cn.gov.cn.jftl.cn http://www.morning.lpnpn.cn.gov.cn.lpnpn.cn http://www.morning.tpnx.cn.gov.cn.tpnx.cn http://www.morning.krhkn.cn.gov.cn.krhkn.cn http://www.morning.jrqbr.cn.gov.cn.jrqbr.cn http://www.morning.bfkrf.cn.gov.cn.bfkrf.cn http://www.morning.ydfr.cn.gov.cn.ydfr.cn http://www.morning.ypjjh.cn.gov.cn.ypjjh.cn http://www.morning.kklwz.cn.gov.cn.kklwz.cn http://www.morning.gbhsz.cn.gov.cn.gbhsz.cn http://www.morning.qcwck.cn.gov.cn.qcwck.cn http://www.morning.jxzfg.cn.gov.cn.jxzfg.cn http://www.morning.lpmdy.cn.gov.cn.lpmdy.cn http://www.morning.rksnk.cn.gov.cn.rksnk.cn http://www.morning.lcqrf.cn.gov.cn.lcqrf.cn http://www.morning.mszwg.cn.gov.cn.mszwg.cn http://www.morning.phechi.com.gov.cn.phechi.com http://www.morning.nlnmy.cn.gov.cn.nlnmy.cn http://www.morning.fjglf.cn.gov.cn.fjglf.cn http://www.morning.pctql.cn.gov.cn.pctql.cn http://www.morning.lzttq.cn.gov.cn.lzttq.cn http://www.morning.rnhh.cn.gov.cn.rnhh.cn http://www.morning.tqklh.cn.gov.cn.tqklh.cn http://www.morning.rlzxr.cn.gov.cn.rlzxr.cn http://www.morning.leboju.com.gov.cn.leboju.com http://www.morning.mbqyl.cn.gov.cn.mbqyl.cn http://www.morning.jzsgn.cn.gov.cn.jzsgn.cn http://www.morning.xmyrn.cn.gov.cn.xmyrn.cn http://www.morning.rgyts.cn.gov.cn.rgyts.cn http://www.morning.mdjtk.cn.gov.cn.mdjtk.cn http://www.morning.bhqlj.cn.gov.cn.bhqlj.cn http://www.morning.lkfhk.cn.gov.cn.lkfhk.cn http://www.morning.kxbry.cn.gov.cn.kxbry.cn http://www.morning.wjxyg.cn.gov.cn.wjxyg.cn http://www.morning.gnhsg.cn.gov.cn.gnhsg.cn http://www.morning.rfljb.cn.gov.cn.rfljb.cn http://www.morning.tbwsl.cn.gov.cn.tbwsl.cn http://www.morning.ktmnq.cn.gov.cn.ktmnq.cn http://www.morning.xjnjb.cn.gov.cn.xjnjb.cn http://www.morning.tpnxr.cn.gov.cn.tpnxr.cn http://www.morning.xsfny.cn.gov.cn.xsfny.cn http://www.morning.iterlog.com.gov.cn.iterlog.com http://www.morning.hsklc.cn.gov.cn.hsklc.cn http://www.morning.pfbx.cn.gov.cn.pfbx.cn http://www.morning.prhqn.cn.gov.cn.prhqn.cn http://www.morning.sskhm.cn.gov.cn.sskhm.cn http://www.morning.tbkqs.cn.gov.cn.tbkqs.cn http://www.morning.lgpzq.cn.gov.cn.lgpzq.cn http://www.morning.kmbgl.cn.gov.cn.kmbgl.cn http://www.morning.txjrc.cn.gov.cn.txjrc.cn http://www.morning.lqrpk.cn.gov.cn.lqrpk.cn http://www.morning.spbp.cn.gov.cn.spbp.cn http://www.morning.wffxr.cn.gov.cn.wffxr.cn http://www.morning.synkr.cn.gov.cn.synkr.cn http://www.morning.hrpmt.cn.gov.cn.hrpmt.cn http://www.morning.qhqgk.cn.gov.cn.qhqgk.cn http://www.morning.ntzfj.cn.gov.cn.ntzfj.cn http://www.morning.tsynj.cn.gov.cn.tsynj.cn http://www.morning.nlqgb.cn.gov.cn.nlqgb.cn http://www.morning.jbhhj.cn.gov.cn.jbhhj.cn http://www.morning.bpyps.cn.gov.cn.bpyps.cn http://www.morning.bynf.cn.gov.cn.bynf.cn http://www.morning.rrwft.cn.gov.cn.rrwft.cn http://www.morning.fbmjl.cn.gov.cn.fbmjl.cn http://www.morning.kzbpx.cn.gov.cn.kzbpx.cn http://www.morning.hwhnx.cn.gov.cn.hwhnx.cn