00:00
前边我们使用spring boot整合了ES的客户端,并且呢测试了对ES的一些复杂操作,那我们ES在项目中的使用场景有哪些呢?那打开我们之前的项目架构图,在我们的项目里边,首先ES作为一个全文检索引擎,它承担我们项目里边的所有全文检索功能,比如京东商城的我们这一块有一个手机的检索功能,我们可以按照手机的名字在这进行全文检索,也可以按照他手机不同的规格属性来进行检索,那这块的检索呢,我们就要用ES来做第二个。那么一般呢,也会来承担我们的一些日志的分析检索功能。那我们项目里边呢,在运行期间可能有一些日志,我们要进行一些快速定位,我们日志呢也有检索需求,那怎么办?我们就可以将日志呢存输到ES里边,我们有一个技术站叫ELK,那E呢指的就是EL search,我们已经学过了,L呢是logten,它来负责收集日志,把收集来的日志存到ES里边,而看呢,就是K盘呢,我们之前看到的可视化界面,这是我们ES的第二个场景,包括大家如果去网上看一些云服务商,比如我在腾讯云里边截了一个图,腾讯云里边如果我们购买他们的ES服务器,他们呢会搭建好这样的一个环境。首先。
01:25
我们项目的无论我们后台的这些项目运行的一些日志,还是我们移动设备的一些日志,包括我们项目里边可能会用到一些物联网传感器,他们这些的日志我们都可以通过网络传输给我们购买的这个ES集群,而传输给他我们中间呢,需要有一个数据的汇聚节点,也就是说将这些数据呢收集起来,收集呢可以用卡夫卡来做,也可以用elk里边的logtensh,我们将收集来的数据呢,最终存储到ES的集群里边,这样呢我们就可以通过一个可视化界面来监控和快速的定位我们出现的一些问题。当然这块的功能呢,我们也会在运维部分来说整个E开技术站,那么先要做的呢,就是我们的商品检索功能,那首先要检索,我们肯定得给ES里边存有数据,那检索来的数据都是来自于ES的,为什么不用MYS来这做这个检索?首先MYS全文检索功能没有ES强大。
02:25
其次,做这么复杂的检索分析数据,MYSQL的性能呢,是远不及ES的,因为ES是将数据都存在我们内存中的,那有些同学可能又会考虑,那如果都存内存中,那商品这么多全存内存中够不够呢?我们说ES它是一个天然支持分布式的,那一个ES不够,我们可以多装上几台ES,分布在不同服务器里边,然后呢,它就会将数据分片存储,比如有10万个数据,他可以这里边存几千个,这里边存几千个等等,他一分单开,那这样呢,我们最终就会容量不够,我们数量来凑,那就能解决这个问题,所以我们最终还是要做的第一件事,就是先要将我们的商品数据给ES里边存一份,方便我们后来做在这个界面来做检索功能,那我们将商品数据从我们的数据库里边,我们保存到ES的,整个这个过程我们称为商品的上架,但大家打开我们课件里边的这个商城业务,我们这个业务里边呢,我们说了一个叫商品上架功能。
03:32
只有上架了的商品呢,我们才可以在网站这一块展示出来,那没有上架的,那都是在我们后台管理系统里边,而且上架了的商品呢,只要保存在ES中,我们就可以被检索,那么先来写第一个功能上架,那写功能之前呢,我们先把这些服务都提起来,完的整个后台项目鼓立麦,包括我们的前端的这个后台管理系统,因为我们要点击上架按钮,我们使用RA div,我们先把后台管理系统启动起来,包括呢,我们一定要启动我们的nacos注册中心,因为我们整个都是微服务开发,注册中心必不可少。
04:13
好,现在呢,我们这个系统已经启动起来,我们现在来做一个访问测试,那之前登录过呢,那默认就直接登录进来了,那直接进入我们的商品系统,在这商品维护里边有一个P管理。在PU管理里面呢,每一个PU后边那都有一个操作叫上架功能,当我们来点击上架,那就是将我们此商品的首先状态改为我们的上架状态,其次呢,我们商品的数据要给ES中进行保存,那保存到ES里边以后呢,我们所有的前端项目,我们前端的商城项目要来检索,那就要去ES里边来检索我们的商品数据,那要给ES里边保存,我们首先呢得分析一下我们要将哪些数据保存在ES中,我们虽然说呢是在PU上点的是上架,但是我们是要将什么信息保存进来呢?在分析这个之前,我们首先得达成一个共识,因为ES里边所有数据都是存在内存中的,虽然说它原生支持分布式,理论上容量无限,但是毕竟内存产品要比我们的硬盘贵得多,所以我们尽量能节省的就节省,所以第一个共识就是我们只保存我们页面有用的数据,没用的信息我们全部不保。
05:27
存要用的时候,大不了我们检索出来,我们已经查到squ ID了,我们想要看SKU的全部图片,包括整个商品的完整介绍,那我们去数据库再查一遍就行。所以我们必须先达成第一个共识,只来保存我们有用的数据,其次我们来考虑哪些数据要进ES。首先我们在这来搜索名字的时候,我们是来搜索的是SKU的标题,因为我们在录入SKU的时候,每一个SKU有它的标题和副标题,那这就是商品里边详细信息的这些标题。
06:02
所以呢,首先我们squ的信息得进来,除了它的标题信息,我们可能还会按照SQ的价格区间进行检索,包括SQ的销量,这个销量呢,在squ里边也都有,那么这呢有这个销量。那也就是说SQ的一些基本信息,我们都是需要用的。那接下来呢,我们会看到还有我们会按照品牌进行检索,包括如果我们来选中某一个分类,直接从分类里边进来,那相当于是检索当前分类下的这些商品。我们也会按照分类进行检索,所以呢,我们除了保存SKU的一些基本信息,我们还得保存它的这个所属于哪个品牌,所属于哪个分类,包括我们还要保存什么呢?看这一块,那么这一块呢,有一个叫商品的规格检索,我会按照它的不同规格进行逐一检索,比如我选中了之前一个五寸的屏幕,我再来选中一个高通的CPU,那接下来就要检索出所有满足高通CPU的这些商品,而这些规格呢,我们又都知道它是属于我们s puu的,因为所有的s puu都是共享s puu的规格,比如我们华为11号商品,它的SKU虽然有八个,但是他们的规格都是相同的,那么要按照这些规格进行检索,那我们也要给ES中保存我们当前SQ对应的规格信息,所以呢,在ES里边我们保存的文档可能是这样的,来给大家呢,先来分析在这儿首先。
07:33
我们的这个文档,我们在ES中保存的都是一个JS文档,我们先来写一个大对象,那SKU的一些基本信息,SKU的ID,比如一号,SKU的title标题,比如我们的华为什么什么什么。包括我们的价格price,比如998,以及我们的销量等等,JSQ的基本信息我们都要保存,但是呢,还有我们的检索属性,我们叫at t RS,因为每一个SQ都从s po里边继承了一些规格,比如它的尺寸,尺寸呢我们现在是五寸的五寸,还有呢,我们的CPU的品牌CPU,我们的比如是高通的,我们这个骁龙的845。
08:18
再比如我们的分辨率,分辨率我们是全高清分辨率。我们写一个全高清,我们都要按照这些属性进行检索,但是呢,可能这稍微有一个问题,如果我们来这么来给ES里边存储数据,检索起来,无论是按照标题价格还是我们这些属性可能非常比较容易检索,但是呢,可能会产生一个我们叫冗余字段。因为我们都知道,假设是11号的PU的这个华为,我们假设呢,把这个po ID我们也放到这儿po id11号,那11号的华为手机它呢,有八个SKU。那这八个SQ呢?其实这个ATRS都一样的,我们给ES中这么一存,感觉好像很浪费空间,那我们可以来假设计算一下,假设呢,我们有100万的商品,那每一个SQ呢?这100万的SQ每一个平均属性我们算成20个,这20个属性呢,假设合起来。
09:20
有2KB的数据,那现在呢,就是100万乘以我们的2KB,那就是200万的KB,也就是我们2000的MB,那也就是多了两个G的数据,那么整个商城系统呢,只多了两个G的数据,那其实填一根内存条那就完事了。其实哪怕是多20G,我们都是不用怕的,但这种的好处就是我们第一个,我们这个方便检索,接下来有的同学可能会提出第二种设计。比如我们来第二种。首先呢,我们还是给里边要保存squ的信息,我们上架的呢,都是我们sqsqu要用来提供检索的,第二种呢,有些同学我们建议可以这么来保存,比如SKU的ID是什么,是一号的,它所属的Su的ID是什么,是11号的,包括SQ的其他基本信息完了,那这样呢,我们只保存squ的有用信息,所以呢,我们现在呢。
10:23
给SKU,假设我们有一个索引,给SKU索引下只保存我们这个有用信息,但是呢,我们后来说,因为SKU的这些规格属性也是要用来检索的,那规格属性保存在哪呢?那为了不冗余,我们专门建立了一个at tr索引,我们现在没类型了,我们全放在这个索引下,这个索引下保存什么呢?哎,同学们说我们可以这么来保存,我保存成SPU的ID,我们比如是11,然后这个SPU对应哪些的属性,At t RS把这一块呢复制来,那这样做的好处是什么?我们可以看到很明显我们的这个属性的规格我们只存了一次,我们是按照s puu存的,那我们怎么知道当前SKU哪有哪些属性规格,那很方便,每一个SKU有它的s po ID是11。
11:15
我们找到了这个SKU以后,我们再去at tr索引里边找到11号,诶找到它的这些属性,这样既满足了好检索,我们SKU里边按照标题价格等等都好检索,又满足了不冗余,我们的属性呢,只在squ级别保存了一份,但这样会出现一个极大的问题,我们来给大家看一个简单的场景,接下来这个场景大家去来考虑一下,我来看一下,我们在这来检索手机的时候,我每选中一个规格。比如我选中了一个屏幕5.49寸,我再选中一个高清,然后剩下呢,又是一些可选规格,但这些可选规格不断在变,比如我再选一个安卓,但无论它怎么变,它有一个最大特点,什么特点呢?这些所列举的属性查出的这些商品是一定拥有的,不可能我这列出了一个存储,比如这个机身存储,我列了一个256G,我点了一个256G进去没有数据,所以说呢,其实我们上边的这一块的规格是动态计算出来的,怎么计算出来的?我们来检索手机的时候,它会找到所有标题里边包含手机的。
12:30
这些商品,而且呢,他会把这些所有的商品聚合起来,分析一下他们商品,这些所有商品涉及的所有的属性,以及所有的属性值,那么来点进某一个属性值,那就会保证这个属性值一定下边会拥有某某些商品,所以我们这一块是动态计算的,那假设呢,我们要完成这个动态计算,那我们这种设计我们来考虑一下啊,比如我们来搜了一个小米,假设我们来搜索一个小米,那满足小米的呢,商品有很多,有可能还在别的分类,比如我们这个杂粮类里边,我们这个粮食类里边还有小米呢,手机类里边也有小米呢,包括电器里边也有小米呢,有很多的SQ都包含有小米。
13:18
那我要检索出这些SKU所涉及的所有属性怎么办?那假设呢,我们这小米的商品,我们有1万个,我们带了小米两字的商品呢,有1万个,那这1万个我们假设涉及到了4000个PU,那我们要找到这些PU所有的这些属性拿来进行聚合,那我们会做一个分布查询。首先呢,第一步我们查出包含小米的这个手机或者商品,那我们查到了1万个,在这1万个里边呢,我们看一下这些小米呢,涉及了4000个PU,然后呢,第二步查出这4000个SPU对应的所有属性。
14:05
所有可能属性。那我们要分布的话呢,我们相当于会调用第二次查询,第二次呢,我们ES的客户端,它还是给ES发送HTP请求的,这个请求光不说别的,我们来查询SPU的ID,这个ID这个数组,我们就得传4000个数据,4000个pou的ID,那这4000个s puu的ID,因为呢,每一个都是浪型数据,假设呢,每一个我们都占八个字节,那我们4000乘以八,那就是32000个字节。那呢,就是32的KB,也就是一个请求下去得发送32KB的数据,那假设呢,我们现在都在并发检索,我们都不拿百万并发来算,那假设呢,现在就只有1万个人,现在正在我们商城里边检索商品,那现在呢,相当于我们如果这1万个人来检索,那就是会320MB的数据。
15:04
那大家都来做检索,那一次呢,集群中光数据传输320MB,那真来面对百万并发,那么再加个两个零,那就是点个检索,直接32GB的数据就传出去了。这32GB的数据,别的不说,光网络阻塞可能时间就会非常长,所以呢,虽说我们这中也是可以的,但随着我们系统不断的壮大,未来可能就会引申这样的问题,所以总之一句话,我们空间和时间总是呢不能二者兼得,我们浪费空间了,像第一种我们可能呢,就会节省一些时间,但是我们节省空间了,像第二种分到两个锁以下,那一定会造成一些时间的浪费,所以呢,基于种种原因的考虑,最终我们商品的ES中存储的数据模型我们设计成了这样,那给大家呢,在Kan里边我们来看,我们来打开一下这里边的数据,当把这个数据模型呢也给大家复制到下边了,首先我们要给ES里边保存这些信息,第一个是SQ的ID,肯定当前SQID是什么?当我们检索到以后,来点击它要查到它的详情的,接下来第二个SQ的ID保存它呢,那就是当前S。
16:18
都属于哪个s puu,我们就很清楚了,包括我们点击squ的商品详情的时候,那查询它的一些商品规格,规格呢都是按照SPU走的,我们直接可以把s puu的ID带上,按照他们来查询,当然这只是一个简单功能,我们这个s puu呢,在后来我们还会用到一个数据折叠功能,所以呢,我们把它设计成了keyword,那后来用到的时候呢,我们再详细说它po ID,我们还得保存,然后呢,商品的标题我们要保存,副标题呢我们没表保存,因为我们是拿标题来进行检索的,包括商品的价格我们也要来保存,价格的保存呢,我直接使用了keyword,为了防止我们数据精度问题,我是保存了成了keyword,还有我们商品的图片,因为我们每检索到一个商品,这呢都会有一个默认图片。
17:09
所以呢,我们还要保存它的这个默认图片,但是呢,在默认图片里边我们多添了两个属性,一个叫index force,还有一个叫dock values force,这index false呢,大家如果查文档你就会看到解释,如果我们给它标志了一个false字段,说明这个属性不可用来被检索,也就是说我们检索条件不能写这个属性名是什么。但是呢,查询的时候我们却可以带下面,当于它只是一个冗余存储字段,为了我们一次查出来就能看到图片,将来doc values force它的作用呢,大家查看文档,它解释呢,是这样的,说这个属性呢,默认是true的,如果是true的话呢,我们这个属性就可以被用来我们做一些聚合,我们之前说的那个AJGS,包括做一些排序,包括脚本等操作,但如果是false,说明我们这个属性啊,不需要聚合等这些操作,这样的话呢,我们ES就不会维护一些额外的检索,那就更能省我们的空间,所以呢,我们一句话,只要冗余存储的字段,我们只是拿来看一下,我们都标上这两个inex force,不用来检索,也不用来进行聚合分析,来进行空间节省。好我们SQ image呢,是这么来设计,包括呢,我们还有我们商品的销量,因为我们会按照销量进行排序,包括商品是否有库存,我在这要显示库存,仅显示有货的。
18:33
的时候,我们可以用到这个,包括呢,我们这儿还有我们的热度评分,但这块的库存我们存的不是一个精确值,而我只是存的一个true或false,就说有库存的就是true,没库存的就是false,相当于我们无需把库存到底是多少,每天都跟我们数据库里边进行核查,再来进行修改,因为我们数据呢,只要一修改ES就会重新把它索引一次来维护,整片索引也是一个很慢的。
19:01
所以呢,我们只有在我们商品没库存的时候,我们才把它改一下,改为false,当时只要上了库存,我们就给它再改为true,这样要比实时更新库存要好得多。接下来呢,还有我们的这个热度评分,那么后来呢,用它来模拟我们这个访问量最多的这些商品,那后来再说吧,还有我们这个品牌ID以及分类ID,因为我们商品呢,还会按照品牌进行检索,包括按照分类进行检索,所以呢,这两个ID我们也得保存下来,但是呢,我还额外保存了品牌的名字,品牌的图片以及分类的名字,而且呢,他们都只是用来看的,不用来检索,也不用来聚合分析,因为我们最起码要在这儿展示出我们这个品牌的名字,比如我们鼠标划在这儿,这个品牌的名字,包括呢,这儿还有品牌的整个图片,所以呢,我们将这些信息我们也放在我这儿。那剩下的就是这个at t RS,它代表我们当前这个商品,也就是我们当前SK所拥有的所有的属性规格,规格呢,我们只保存了属性的ID,它是一个浪,属性的名字,它是一个keyword,而且也不用来检索,不用来聚合,属性名呢,最终就给这一展示就行了。CPU品牌,但属性的值呢,我们选中某一个值,我们确实要按照这个值进行检索的。
20:21
比如我们寄生存储选了一个128,我们就会看到呢,这一块的检索条件里边就一定会有我们这个128的这个检索这一块,它的这个数据做了一些编码,我们可能直接看不到,所以呢,我们属性的值就是这么设计,它值是一个keyword,也不用来进行全文匹配,所以它是一个keyword。而唯一要进行全文匹配的是我们商品的标题,它是一个test字段,可以进行全文检索,进行分词,而且呢,我们让它默认使用I开smart这个分词器。那这是我们整个商品的映射信息,在这个信息里边呢,有一个特别重要的点,叫这个ne,这是由于我们通过分析,我们发现一个商品呢,所有的属性,它是一个数组,数组里面是对象,而且要按照对象里边某些值进行检索,相当于它是这个内部的属性,那我们就要标志成这个ne的嵌入式的,如果不标它就会有检索出现问题,那我们下一节课呢,模拟一下,如果不用会有什么问题,那么这个ne呢,非常重要,那这就是我们商品的映射信息,那我呢,就直接在这来执行一下put product,把这些映射呢,在这一改,那以后我们填商品就按照这个映射了,行,我们后来真要上架的时候,我们再来执行这个功能。
21:39
这是我们上架需求,以及我们ES里边商品数据模型的分析。
我来说两句