商品上架与ES
# 前言
前面使用Springboot整合了ES,测试了对ES的一些复杂操作。接下来来看看ES在项目中的业务场景。
# 使用场景
ES承担项目的全文检索功能,比如商城中的关键字搜索或者规格检索。
ES检索服务性能远超mysql,而且复杂检索对来ES来说也能轻松做到。
那么这么多数据存到ES中,内存够不够呢?
一个ES不够,可以多装几个ES,分片存储在不同服务器之中。容量不够,数量来凑。
比如日志检索需求,日志存到ES中,比如ELK(Elasticsearch、LogStash、Kibana),把收集来的日志存到ES里面。
像服务器、移动设备、IOT传感器数据汇聚到LogStash或Kafka,最终存储到ES集群里面,最终使用可视化界面来查看,如果有线上问题,可以快速定位
# 存储模型分析
正常来说只有上架的商品才会在前台网站展示,没上架的,只能在后台管理系统查看到。
也就说,每次上架/下架都要更新ES的数据。
因为ES运行在内存中,那么最好只保存有用的数据。
那么需要保存sku基本信息,所属分类,所属品牌,规格参数。
要按照规格进行检索。但是规格参数是属于SPU的。
那么存储模型有2种:
空间占用高,时间占用低
{
skuId:1,
skuTilte:xxx手机,
price:998,
saleCount:99,
attrs:[
{尺寸:5寸},
{CPU:高通875},
{分辨率:全高清}
],
skuId:2,
skuTilte:xxx手机,
price:1998,
saleCount:199,
attrs:[
{尺寸:5寸},
{CPU:高通875},
{分辨率:全高清}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
这种存储模型的问题是,规格参数冗余,因为规格参数是绑定在spu上的,那么每个sku的规格参数都有可能重复,
计算一下占用内存,假设有一百万的商品,每个sku有20个属性,那么一个是sku是2k
100万 * 20 = 1000000*2kb = 2000 MB = 2G
哪怕是20G也不怕,加内存就完事。
空间占用低,时间占用高
sku索引{
skuId:1,
spuId:11,
xxx
}
attr索引{
spuId:11,
attrs:[
{尺寸:5寸},
{CPU:高通875},
{分辨率:全高清}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
这种就不冗余了,每次检索商品需要去找到spuId,然后再去attr索引找到对应的属性。
那么这种方式需要请求两次,
第一次是请求sku信息,然后获取一个spuId数组,
然后第二次,通过spuId数组,去获取attr
看起来没什么问题
会存在极大问题,
在商城页面,在规格选择栏是动态计算出来的,
比如我搜索小米,它有可能在粮食分类,也有可能在手机分类,也有可能在电器分类。
假设现在这些加起来一共有10000个spu,
比如关于小米的手机分类有4000个spu,每个spu有8个属性,
那么我要去动态计算规格时,是不是得传4000个spuId进去
4000*8=32000byte =32kb。
假设有10000个人搜索,32kb*10000=320mb,假设是百万并发,就是32GB,光网络阻塞就等很久了。
小结:
时间和空间不可能兼并,第二种方式虽然占用空间少了,没有冗余,但是每次在时间上就得做牺牲了。第一种方式虽然占用空间比第一种大,但是只需要请求一次,然后再做过滤,不用每次请求发送那么多,能够节省一些时间。
什么?时间和空间你都要?加钱👍。
基于种种原因考虑,采用第一种存储模型:
字段 | 类型 | 说明 |
---|---|---|
skuId | long | 检索到,点击它可以查看详情 |
spuId | keyword | 点击进去通过spuId,可以获取规格参数,供用户选择 |
skuTitle | text,ik_smart | 通过标题也可以检索 |
skuPrce | keyword | keyword防止数据精度问题 |
skuImg | type:keyowrd,index:false,doc_value:false | index,false不可以被检索, doc_value:false,不可以被用来聚合,排序等脚本操作 |
saleCount | long | 销量用来排序 |
hasStock | boolean | 仅显示是否有货 |
hasScore | ||
brandId | ||
catalogId | ||
brandName | ||
brandId |