✅P128-129_商城业务-商品上架-sku在es中存储模型分析
大约 3 分钟
商品部分信息存储在es中
保存 sku 信息
当搜索商品名时,查询的是 sku 的标题 sku_title;
可能通过 sku 的标题、销量、价格区间检索。
保存品牌、分类信息
点击分类,检索分类下的所有信息。
点击品牌,检索品牌下的商品信息。
保存 spu 信息
选择规格,检索共有这些规格的商品。
商品 Mapping
存储结构方案
空间换时间
缺点:会产生冗余字段,对于相同类型的商品,attrs 属性字段会重复,空间占用大好处:方便检索
{
skuId:1
spuId:11
skuTitile:华为xx
price:999
saleCount:99
attrs:[
{尺寸:5存},
{CPU:高通945},
{分辨率:全高清}
]
}
时间换空间
缺点:选择公共属性attr时,会检索当前属性的所有商品分类,然后再查询当前商品分类的所有可能属性;导致耗时长。
好处:空间利用率高
sku索引
{
skuId:1
spuId:11
}
attr索引
{
spuId:11
attrs:[
{尺寸:5寸},
{CPU:高通945},
{分辨率:全高清}
]
}
因此,选择第一种存储模型.
最终商品Mapping设计
分析:keyword不全文检索,text全文检索,价格使用keyword为了保存精度,hasStock表示库存,hotScore表示热度,只用于显示的数据将index和doc_values设置为false表示不参与检索和聚合
PUT product
{
"mappings": {
"properties": {
"skuId": {
"type": "long"
},
"spuId": {
"type": "keyword"
},
"skuTitle": {
"type": "text",
"analyzer": "ik_smart"
},
"skuPrice": {
"type": "keyword"
},
"skuImg": {
"type": "keyword",
"index": false,
"doc_values": false
},
"saleCount": {
"type": "long"
},
"hasStock": {
"type": "boolean"
},
"hotScore": {
"type": "long"
},
"brandId": {
"type": "long"
},
"catalogId": {
"type": "long"
},
"brandName": {
"type": "keyword",
"index": false,
"doc_values": false
},
"brandImg": {
"type": "keyword",
"index": false,
"doc_values": false
},
"catalogName": {
"type": "keyword",
"index": false,
"doc_values": false
},
"attrs": {
"type": "nested",
"properties": {
"attrId": {
"type": "long"
},
"attrName": {
"type": "keyword",
"index": false,
"doc_values": false
},
"attrValue": {
"type": "keyword"
}
}
}
}
}
}
mapping结构字段说明
index
默认 true, 如果为 false, 表示该字段不会被索引, 但是检索结果里面有, 但字段本身不能当做检索条件。
doc_values
默认 true, 设置为 false, 表示不可以做排序、 聚合以及脚本操作, 这样更节省磁盘空间。还可以通过设定 doc_values 为 true, index 为 false 来让字段不能被搜索但可以用于排序、 聚合以及脚本操作。
"mappings": {
"properties": {
"skuId": { "type": "long" },
"spuId": { "type": "keyword" }, # 精确检索,不分词
"skuTitle": {
"type": "text", # 全文检索
"analyzer": "ik_smart" # 分词器
},
"skuPrice": { "type": "keyword" },
"skuImg": {
"type": "keyword",
"index": false, # false 不可被检索
"doc_values": false # false 不可被聚合
},
"saleCount":{ "type":"long" }, # 商品销量
"hasStock": { "type": "boolean" }, # 商品是否有库存
"hotScore": { "type": "long" }, # 商品热度评分
"brandId": { "type": "long" }, # 品牌id
"catalogId": { "type": "long" }, # 分类id
"brandName": { # 品牌名,只用来查看,不用来检索和聚合
"type": "keyword",
"index": false,
"doc_values": false
},
"brandImg":{ # 品牌图片,只用来查看,不用来检索和聚合
"type": "keyword",
"index": false,
"doc_values": false
},
"catalogName": { # 分类名,只用来查看,不用来检索和聚合
"type": "keyword",
"index": false,
"doc_values": false
},
"attrs": { # 属性对象
"type": "nested", # 嵌入式,内部属性
"properties": {
"attrId": {"type": "long" },
"attrName": { # 属性名
"type": "keyword",
"index": false,
"doc_values": false
},
"attrValue": { "type": "keyword" } # 属性值
}
}
}
}
Es-数组的扁平化处理
Object 数据类型的数组会被扁平化处理为一个简单的键与值的列表,即对象的相同属性会放到同一个数组中,在检索时会出现不存在的数据被检索到。参考官网:How arrays of objects are flattened
nested 类型
对于 Object 类型的数组,要使用 nested 字段类型。参考官网:Using nested fields for arrays of objects
举例:
"attrs": { # 属性对象
"type": "nested", # 嵌入式,内部属性
"properties": {
"attrId": {"type": "long" },
"attrName": { # 属性名
"type": "keyword",
"index": false,
"doc_values": false
},
"attrValue": { "type": "keyword" } # 属性值
}
}