3.4.2.7.Nested数据类型
创作人:李增胜
Nested 是 Object 的专用版本,允许对象数组以可以彼此独立查询的方式进行索引。
Elasticsearch 中其实是没有内部对象的概念,因此它将对象层次结构,简化为字段名称和值,以列表的形式展现。
首先来比较 Nested 与 Join 以及 Object 的区别:
小结:
Nested 类型使用场景:
1、含有 Object 数组。
2、需要对 Object 中的字段(至少两个及以上)同时进行查询,并维护这种关系。
Nested 类型允许相互独立地对对象数组进行索引和查询。如果需要维护数组中每个对象的关系,请使用 nested 数据类型。
以 B2B 电商行业的实际业务场景来举例说明,2B 行业的交易具有一定封闭性,只有签署合同、经常往来交易的会员,往往有更高资格的交易权、议价权。
定义商品索引,其中 groupPrice 标识分组价对象,对象里面包含了 boxLevelPrice 分组价格、level 分组级别。当前端业务线搜索时,传入用户所在组级别,即可查询对应的价格。
为了便于区分我们先定义为 Object 类型来观察下现象:
定义分组为 Object 类型
其中 groupPrice 为数组 Object 数据结构类型:
PUT goods_info_object { "mappings": { "properties": { "goodsName": { "type": "text", "analyzer": "ik_smart" }, "skuCode": { "type": "keyword" }, "brandName": { "type": "keyword" }, "shopCode": { "type": "keyword" }, "publicPrice": { "type": "float" }, "groupPrice": { "properties": { "boxLevelPrice": { "type": "keyword" }, "level": { "type": "keyword" } } } } } } #插入测试数据,为了便于阅读 JSON 格式进行了展开 POST goods_info_object/_bulk { "index": { "_id": 1 } } { "goodsName": "美国苹果", "skuCode": "skuCode1", "brandName": "美国苹果", "shopCode": "sc00001", "publicPrice": "8388.88", "groupPrice": [ { "boxLevelPrice": "4888.00", "level": "A" }, { "boxLevelPrice": "6888.00", "level": "B" } ] } { "index": { "_id": 2 } } { "goodsName": "山东苹果", "skuCode": "skuCode2", "brandName": "山东苹果", "shopCode": "sc00001", "publicPrice": "7388.88", "groupPrice": [ { "boxLevelPrice": "5888.00", "level": "A" }, { "boxLevelPrice": "4888.00", "level": "B" } ] } #检索A组且价格等于4888.00的商品 POST goods_info_object/_search { "query": { "bool": { "must": [ { "match": { "groupPrice.level": "A" } }, { "match": { "groupPrice.boxLevelPrice": "4888.00" } } ] } } } #返回: { "took" : 1, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 2, "relation" : "eq" }, "max_score" : 0.45840856, "hits" : [ { "_index" : "goods_info_object", "_type" : "_doc", "_id" : "1", "_score" : 0.45840856, "_source" : { "goodsName" : "美国苹果", "skuCode" : "skuCode1", "brandName" : "美国苹果", "shopCode" : "sc00001", "publicPrice" : "8388.88", "groupPrice" : [ { "boxLevelPrice" : "4888.00", "level" : "A" }, { "boxLevelPrice" : "6888.00", "level" : "B" } ] } }, { "_index" : "goods_info_object", "_type" : "_doc", "_id" : "2", "_score" : 0.45840856, "_source" : { "goodsName" : "山东苹果", "skuCode" : "skuCode2", "brandName" : "山东苹果", "shopCode" : "sc00001", "publicPrice" : "7388.88", "groupPrice" : [ { "boxLevelPrice" : "5888.00", "level" : "A" }, { "boxLevelPrice" : "4888.00", "level" : "B" } ] } } ] } }
我们查询的数据,要满足分组等级是 A 级且价格为 4888.00 的数据信息。
如下图所示,只有文档 1 是满足的,但是却查询到了 2 条,其中包括不符合条件的文档 2:
这是因为 Elasticsearch 中将 Object 数组打平了做存储导致,在 Elasticsearch 中,会将数据做如下存储:
{ "goodsName" : "山东苹果", "skuCode" : "skuCode2", "brandName" : "山东苹果", "shopCode" : "sc00001", "publicPrice" : "7388.88", "groupPrice.boxLevelPrice" :["5888.00","4888.00"], "groupPrice.level" :["A","B"] }
查询恰好 boxLevelPrice 为"4888.00" 并且 level 为"A"的文档 2 是能被检索到的,当需要对数组中两个字段进行查询时,就需要用 Nested 数据结构类型来解决此问题。
《Elastic Stack 实战手册》——三、产品能力——3.4.入门篇——3.4.2.Elasticsearch基础应用——3.4.2.7.Nested数据类型(下) https://developer.aliyun.com/article/1230843