Object 类型
在设计索引mapping时,在某些业务下,需要设计的对象中包含对象,俗称内部对象,此时就可以使用Object类型来存储对象.
以下定义了店铺对象,包含店铺名称、店铺编码、供应商信息,另外供应商信息中又包含供应商编码、供应商名称。同时供应商信息还包含自身的对象属性所在区域,所在区域又包含省和市,这种定义才能满足查询店铺信息、查询供应商所有店铺信息,以及查询某地区的所有店铺信息等等场景。
#定义mapping
PUT my_shop_0425
{
"settings": {
"index": {
"number_of_shards": 1,
"number_of_replicas": 1
}
},
"mappings": {
"properties": {
"shopName": {
"type": "text",
"analyzer": "ik_smart"
},
"shopCode": {
"type": "keyword"
},
"supplier": {
"properties": {
"supplier_code": {
"type": "keyword"
},
"supplier_name": {
"type": "text",
"analyzer": "ik_smart"
},
"area": {
"properties": {
"province": {
"type": "keyword"
},
"city": {
"type": "keyword"
}
}
}
}
}
}
}
}
#插入测试数据
POST my_shop_0425/_bulk
{"index":{"_id":1}}
{"shopName":"苹果热销店铺","shopCode":"sc001","supplier":{"supplier_code":"001","supplier_name":"南京农村电商领导者","area":{"province":"江苏省","city":"南京市"}}}
{"index":{"_id":2}}
{"shopName":"美的热销店铺","shopCode":"sc002","supplier":{"supplier_code":"001","supplier_name":"南京农村电商领导者","area":{"province":"江苏省","city":"南京市"}}}
{"index":{"_id":3}}
{"shopName":"金沙酒热销店铺","shopCode":"sc003","supplier":{"supplier_code":"002","supplier_name":"山东农村电商领导者","area":{"province":"江苏省","city":"南京市"}}}
{"index":{"_id":4}}
{"shopName":"华为热销店铺","shopCode":"sc004","supplier":{"supplier_code":"002","supplier_name":"山东农村电商领导者","area":{"province":"山东省","city":"青岛市"}}}
2家供应商
南京农村电商领导者 店铺:苹果热销店铺+美的热销店铺
山东农村电商领导者 店铺:金沙酒热销店铺+华为热销店铺
查询供应商001对应的所有店铺:
POST my_shop_0425/_search
{
"query": {
"match": {
"supplier.supplier_code": "001"
}
}
}
#返回
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 0.6931471,
"hits" : [
{
"_index" : "my_shop_0425",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.6931471,
"_source" : {
"shopName" : "苹果热销店铺",
"shopCode" : "sc001",
"supplier" : {
"supplier_code" : "001",
"supplier_name" : "南京农村电商领导者",
"area" : {
"province" : "江苏省",
"city" : "南京市"
}
}
}
},
{
"_index" : "my_shop_0425",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.6931471,
"_source" : {
"shopName" : "美的热销店铺",
"shopCode" : "sc002",
"supplier" : {
"supplier_code" : "001",
"supplier_name" : "南京农村电商领导者",
"area" : {
"province" : "江苏省",
"city" : "南京市"
}
}
}
}
]
}
}
#查询销售区域在南京的所有店铺
#查询销售区域在南京的所有店铺
POST my_shop_0425/_search
{
"query": {
"match": {
"supplier.area.city": "南京市"
}
}
}
#返回
{
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 0.35667494,
"hits" : [
{
"_index" : "my_shop_0425",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.35667494,
"_source" : {
"shopName" : "苹果热销店铺",
"shopCode" : "sc001",
"supplier" : {
"supplier_code" : "001",
"supplier_name" : "南京农村电商领导者",
"area" : {
"province" : "江苏省",
"city" : "南京市"
}
}
}
},
{
"_index" : "my_shop_0425",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.35667494,
"_source" : {
"shopName" : "美的热销店铺",
"shopCode" : "sc002",
"supplier" : {
"supplier_code" : "001",
"supplier_name" : "南京农村电商领导者",
"area" : {
"province" : "江苏省",
"city" : "南京市"
}
}
}
},
{
"_index" : "my_shop_0425",
"_type" : "_doc",
"_id" : "3",
"_score" : 0.35667494,
"_source" : {
"shopName" : "金沙酒热销店铺",
"shopCode" : "sc003",
"supplier" : {
"supplier_code" : "002",
"supplier_name" : "山东农村电商领导者",
"area" : {
"province" : "江苏省",
"city" : "南京市"
}
}
}
}
]
}
}
Join 类型
Join 类型是一种特殊的类型,类似父子结构,一个子文档只能由一个父文档,一个父文档可以有多个子文档。
#定义索引,my_goods_sale为售卖的上信息,my_goods_comment为商品的评价信息
PUT my_goods_hot_sale
{
"mappings": {
"properties": {
"my_id": {
"type": "keyword"
},
"my_join_field": {
"type": "join",
"relations": {
"my_goods_sale": "my_goods_comment"
}
}
}
}
}
#添加商品售卖ID为1的信息
PUT my_goods_hot_sale/_doc/1?refresh
{
"my_id": "1",
"text": "This is a my_goods_sale",
"my_join_field": {
"name": "my_goods_sale"
}
}
#添加商品售卖ID为2的信息
PUT my_goods_hot_sale/_doc/2?refresh
{
"my_id": "2",
"text": "This is another my_goods_sale",
"my_join_field": {
"name": "my_goods_sale"
}
}
#添加商品售卖的评价3,父商品为1
PUT my_goods_hot_sale/_doc/3?routing=1&refresh
{
"my_id": "3",
"text": "This is an comment",
"my_join_field": {
"name": "my_goods_comment",
"parent": "1"
}
}
#添加商品售卖的评价4,父商品为1
PUT my_goods_hot_sale/_doc/4?routing=1&refresh
{
"my_id": "4",
"text": "This is another comment",
"my_join_field": {
"name": "my_goods_comment",
"parent": "1"
}
}
- 根据父文档查询子文档
GET my_goods_hot_sale/_search
{
"query": {
"has_parent": {
"parent_type": "my_goods_sale",
"query": {
"match": {
"text": "my_goods_sale"
}
}
}
}
}
- 根据子文档查询父文档
GET my_goods_hot_sale/_search
{
"query": {
"has_child": {
"type": "my_goods_comment",
"query": {
"match_all": {}
}
}
}
}
Nested 类型
nested 是 object 的专用版本,允许对象数组以可以彼此独立查询的方式进行索引。
ES 中其实是没有内部对象的概念,因此它将对象层次结构简化为字段名称和值,以列表的形式展现。
首先来比较 nester 与 parent/child 以及 Object 的区别
以 B2B 电商行业的实际业务场景来举例说明,2B 行业的交易具有一定封闭性,只有签署合同、经常往来交易的会员往往有更高资格的交易权、议价权。
定义商品索引,其中 groupPrice 标识分组价对象,对象里面包含了 boxLevelPrice 分组价格、level 分组级别,当前端业务线搜索时,传入用户所在组级别,即可查询对应的价格。为了便于区分我们先定义为 Object 类型来观察下现象:
定义分组为 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"
}
}
}
}
}
}
#插入测试数据
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"
}
]
}
}
]
}
}
显然返回的数据不是我们期望的,这是因为 ES 中将 Object 数组打平了做存储导致
定义分组为 Nested 类型
PUT goods_info_nested
{
"mappings": {
"properties": {
"goodsName": {
"type": "text",
"analyzer": "ik_smart"
},
"skuCode": {
"type": "keyword"
},
"brandName": {
"type": "keyword"
},
"shopCode": {
"type": "keyword"
},
"publicPrice": {
"type": "float"
},
"groupPrice": {
"type": "nested",
"properties": {
"boxLevelPrice": {
"type": "keyword"
},
"level": {
"type": "keyword"
}
}
}
}
}
}
#插入同样的测试数据
POST goods_info_nested/_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"}]}
#查询
POST goods_info_nested/_search
{
"query": {
"nested": {
"path": "groupPrice",
"query": {
"bool": {
"must": [
{
"match": {
"groupPrice.level": "A"
}
},
{
"match": {
"groupPrice.boxLevelPrice": "4888.00"
}
}
]
}
}
}
}
}
#返回:
"hits" : [
{
"_index" : "goods_info_nested",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.3862942,
"_source" : {
"goodsName" : "美国苹果",
"skuCode" : "skuCode1",
"brandName" : "美国苹果",
"shopCode" : "sc00001",
"publicPrice" : "8388.88",
"groupPrice" : [
{
"boxLevelPrice" : "4888.00",
"level" : "A"
},
{
"boxLevelPrice" : "6888.00",
"level" : "B"
}
]
}
}
]
返回的是我们期望的,说明 nested 查询生效,解决了嵌套查询的问题