1、Nested(嵌套类型)是个啥?
官方定义:官方释义:这个nested类型是object一种数据类型,允许对象数组以相互独立的方式进行索引
nested属于object类型的一种,是Elasticsearch中用于复杂类型对象数组的索引操作。Elasticsearch没有内部对象的概念,因此,ES在存储复杂类型的时候会把对象的复杂层次结果扁平化为一个键值对列表。
2、适用场景
字段值为复杂类型的情况,即字段值为非基本数据类型
3、案例
3.1 场景
假如我们有如下order索引,包含订单的商品列表
PUT /order/_doc/1 { "order_name": "xiaomi order", "desc": "shouji zhong de zhandouji", "goods_count": 3, "total_price": 12699, "goods_list": [ { "name": "xiaomi PRO MAX 5G", "price": 4999 }, { "name": "ganghuamo", "price": 19 }, { "name": "shoujike", "price": 1999 } ] } PUT /order/_doc/2 { "order_name": "Cleaning robot order", "desc": "shouji zhong de zhandouji", "goods_count": 2, "total_price": 12699, "goods_list": [ { "name": "xiaomi cleaning robot order", "price": 1999 }, { "name": "dishwasher", "price": 4999 } ] }
3.2 需求
查询订单商品中商品名称为dishwasher并且商品价格为1999的订单信息,尝试执行以下脚本
GET order/_search { "query": { "bool": { "must": [ { "match": { "goods_list.name": "dishwasher" // 条件一 } }, { "match": { "goods_list.price": 1999 // 条件二 } } ] } } }
3.3 结果
按照bool中must的查询逻辑,两个条件都符合的数据并不存在,然而执行查询后发现返回以下结果
"hits" : [ { "_index" : "order", "_type" : "_doc", "_id" : "2", "_score" : 1.7199211, "_source" : { "order_name" : "Cleaning robot order", "desc" : "shouji zhong de zhandouji", "goods_count" : 2, "total_price" : 12699, "goods_list" : [ { "name" : "xiaomi cleaning robot order", "price" : 1999 }, { "name" : "dishwasher", "price" : 4999 } ] } } ]
3.4 原因分析
可以看到上述结果元数据中出现了订单数据,这和预期结果不一致。
分析原因如下:
当字段值为复杂数据类型(Object、Geo-Point等)的时候,ES内部实际是以如下方式保存数据的:
{ "order_name": "Cleaning robot order", "desc": "shouji zhong de zhandouji", "goods_count": 2, "total_price": 12699, "goods_list.name":[ "alice", "cleaning", "robot", "order", "dishwasher" ], "goods_list.price":[ 1999, 4999 ] }
上述例子中goods_list中每个对象元素的属性值被扁平化存储在了数组中,此时已丢失了对应关系,因此无法保证搜索的准确。
3.5 解决方案
使用Nested类型
4、Nested用法
上述问题解决办法即对复杂类型使用Nested类型。在ES中嵌套类型不止Nested一种,但是只有Nested是单独的考点,因此其他的暂不需考虑
4.1 创建Mapping
在Mapping中为复杂类型指定Nested类型
PUT order { "mappings": { "properties": { "goods_list": { "type": "nested", "properties": { "name": { "type": "text" } } } } } }
4.2 写入数据
再次写入数据,此处省去此步骤代码。
4.3
执行查询,实际为query外层进行了一层嵌套。
GET /order/_search { "query": { "nested": { "path": "goods_list", "query": { "bool": { "must": [ { "match": { "goods_list.name": "dishwasher" } }, { "match": { "goods_list.price": 4999 } } ] } } } } }