聚合搜索平台分享
第一期
核心概念
1.聚合搜索中聚合的概念?
支持多数据源的搜索,可以根据关键词在多数据源中进行搜索,而不是像传统的数据库一样,只支持某以一个数据库源的搜索,而是可以同时支持多个数据源,并把多数据源的搜索结果聚合显示出来
2.聚合搜索平台的作用?
用户角度
用户不用根据搜索内容的类型单独去搜索每种内容,而是直接可以通过一个搜索接口去搜索所有内容比如必应搜索,你随便输入一个关键词,他都是同时显示网页,图片,视频,学术,字典,地图等多个数据源的搜索结果的,你只需要按需选择你要查看的内容即可,不用你单独去搜索网页或者图片等内容类型;提高用户的搜索体验和搜索效率
企业角度
不用为每一种数据源都重复开发一个搜索平台,只需把数据源导入一个公共的搜索中台即可,提高企业的开发效率
系统架构图
聚合搜索平台的架构图
传统搜索平台的设计

现代搜索平台的设计

技术知识收获
1.前端相关知识
前端路由组件对象router和route对象的区别router是路由管理对象,route是具体的路由对象
2.AI的了解和学习
搜索平台的数据可以让鱼聪明生成,辅助我们测试搜索平台的效果AI居然可以直接根据MySQL表结构生成对应的模拟数据insert语句,太厉害了,果然懂提问就行,真的要善于利用AI,关键词给越准确,AI回答的越好
核心收获
1.开发一个系统的关键
最重要就是把系统的架构图想明白,画出来;架构图画出来了,系统怎么实现就一目了然了,具体的实现技术不会可以去网上搜索
2.如何画出系统的架构图?
我们之所以要开发系统,是因为有对应的需求过来,才要开发系统来解决这些需求,所以怎么画系统得架构图就很清晰了,就是根据系统的核心业务来画项目的架构图
第二期
如何爬取数据
核心是模仿正常用户获取数据即可
常用的数据抓取方式
A.直接请求数据接口(最方便),可使用 Hutool (https://hutool.cn/)
B.等客户端发送请求等网页渲染出明文内容后,从前端完整页面中解析出需要的内容(配合爬虫框架jsoup从HTML中解析出想要的内容)
因为这种方式需要先定位出所需的内容在那里,而HTML页面的内容又非常多,可以根据文件后缀来加快文件定位的速度,比如.jpg的图片链接,.png的图片链接,又或者是各种视频和文档格式
有些资源即使是响应回浏览器,资源也是经过加密,爬取的难度要大一点,当然理论上所有用户可以看到的数据,爬虫都可以爬取,他既然有加密,在客户端就一定有解密,找到其是如何解密的,然后模仿其解密即可
C.有一些网站可能是动态请求的,他不会一次性加载所有的数据,而是要你点某个按钮、输入某个验证码才会显示出数据。可使用无头浏览器:selenium、node.js puppeteer
搜索的业务场景
A.根据tab栏进行搜索,点击那个tab栏就搜索那个tab栏目的内容;此方式可以用聚合的方式实现,也可以用非聚合的方式实现,看具体的业务场景选择即可
非聚合方式实现:统一前后端的搜索接口,不要一个内容类型对应一个搜索请求
统一接口的作用:降低前端的开发成本,并且可以降低前后端的沟通成本
如果一个搜索内容对应一个搜索请求,前后端都需要重复编写很多搜索接口,并且会提高前后端的沟通成本;如果统一接口,然后让后端来实现根据不同的内容类型执行不同的搜索业务,可以降低前端的开发成本,并且可以降低前后端的沟通成本。
非聚合方式实现的弊端:后端需要根据内容类型不断的去重复编写搜索接口的业务,只是不用前端重复编写接口请求罢了,后端仍然是需要做这些事情的
聚合方式实现:统一前后端搜索接口,并且后端的搜索接口业务是适用于所有内容类型的
统一接口的作用:降低前后端的开发和沟通成本 前后端都是只需要开发一个接口即可,相较于传统非聚合的方式,前后端开发都无需重复编写搜索接口,降低前后端的开发成本和沟通成本
聚合方式实现的弊端: 如果聚合回显的内容太多,也会提高服务器资源耗费的成本,所以要根据实际的业务场景选择要聚合的内容体量,不要盲目的全部将所有内容都回显,所以才需要tab栏切换时再进行相应内容的搜索,当然也有一次性全部回显的内容的业务场景,下面罗列的就是
以优雅的方式接入数据源
目前这种方式是写死的,代码的可拓展性和可维护性交叉,至于优化的方式,很明显是用设计模式来优化了,因为要有更好的可拓展性和可维护性,那用什么设计模式优化呢?怎么优化呢?
接入数据源明显是用可以自动注册数据源的注册器设计模式,来一个数据源就将其注册进去,然后统一调用的搜索接口,根据搜索内容的类型动态执行搜索的业务
23种标准的设计模式中为什么没有注册器模式?
因为注册器模式是设计模式的拓展,所以并不属于23种标准的设计模式,注册器模式本质上属于创建型设计模式,是为了解耦对象的创建和使用
注册器模式和单例模式的对比
注册器和单例模式非常像,单例模式只是专注一个对象的解耦,而注册器模式是用一个容器来管理注册的对象实例,是可以解耦一群对象的,这是二者最大的不同点,并且注册器模式注册的对象并不一定是单例的,当然大部分都是单例的,毕竟单例是可以复用对象资源的
注册器模式+策略模式优化聚合搜索接口
1.注册现有的所有数据源,key是数据源的标识,值是数据源的对象
2.搜索接口遍历数据源,并调用数据源相应的搜索业务;如果数据源的搜索业务不统一,可以将其向上统一抽象,然后根据不同的数据源执行不同的搜索业务。抽象主要是向上抽象搜索请求,抽象搜索请求对应的服务处理,因为不同的搜索请求对象的参数不相同,所以需要在对应的搜索处理方法中对其向下转型
转型踩坑
客户端传输过来的请求对象只是序列化和反序列化的结果,并没有发生类型强转,所以请求对象的向上转型得发生在服务端中我们才有类型转型的记录,才能够在请求处理的服务中对其进行向下转型
第三期
门面设计模式优化
门面设计模式,客户端不用关心内部的实现细节即可实现调用聚合就是门面模式的典型应用,用户或者说前端开发者根本不需要知道你是怎么实现多数据源的聚合的,他只需要发起获取数据的请求即可,降低用户的使用成本
统一规范 && 适配器模式
统一规范的应用
统一规定数据源接入的规范,让其他开发团队按照我们的规范进行接入,防止其影响我们的系统稳定性,我不可能根据不同人的接入写不同的对接吧,那我岂不是很多事情要做,而且也不符合设计模式的开闭原则,所以必须要规定数据源接入的规范,符合我们的规范就允许接入,否则拒绝接入
适配器模式的应用
适配器就是让原本不兼容的类型通过一个中间转化让二者可以兼容,在规范适配上就有非常好的应用了,有两个角度假如你是规范的制定者,你无需适配别人,让是让别人去适配你制定的规范假如你是规范的遵守着,而你本身的接口又不符合规范,那么你就需要修改你自己的接口到符合规范为止,因为只有符合规范我才允许你接入
疑问
1.我发现我自己去优化接入数据源,使用的是策略设计模式,而非适配器设计模式?
是的,你用的是策略设计模式,而鱼总用的适配器设计模式,在当下适配数据源规范的业务场景,更适合用适配器模式而非策略设计模式,你对设计模式理解太浅了,导致很容易误用甚至用错设计模式
2.为什么不能将数据源的接入规范接口合并在Service中呢?
因为将制定的接口规范合并到Service接口中会增加业务耦合度,会降低系统的可拓展性和可维护性
3.为什么我觉得这个设计模式是策略设计模式,他觉得是适配器设计模式呢?策略模式和适配器模式有什么区别呢?
一图胜前言
策略模式

适配器模式

4.鱼皮哥的适配器设计模式比我的策略模式实现要简单多了,少了很多对象的向下类型的强转,为什么是这样的呢?
因为业务场景是接入的数据源不符合制定的数据源规范,需要将不规范的数据源转换为规范的数据源
这个业务场景显然是更适合适配器设计模式,而你却用了策略设计模式,自然就没有解决数据源不符合规范的问题,所以你需要做大量的类型强转,因为你没有解决真正的类型适配问题
因为接入的数据源不符合制定的数据源规范,所以需要将不规范的数据源转换为规范的数据源,鱼皮哥使用的方案是适配器设计模式,而我使用的方案是统一抽象一个父类型请求Request,然后用父类型去兼容数据源的规范
因为统一抽象一个父类型Request这种方向仅仅只是实现类型的兼容,并没有真正实现的类型适配和转换,导致我在执行搜索业务逻辑时出现了类型不匹配异常,所以需要大量的类型转型,将父类型转换为对应的子类型,所以我这种类型适配的方案是不好的,因为其并没有实现真正的类型适配
5.鱼皮的注册器模式的map管理是用对象来实现的,我是用static来实现,为什么呢?二者有什么区别呢?
注册器模式本质是创建型模式,可以用statis来实现也可以用非static来实现;static实现的方式是符合单例模式,非static实现不一定是单例(由自己来控制)
6.Mysql的like查询有什么缺陷?
like查询是包含查询而非分词查询,查询的灵活性较差,比如我想查询包含java,介绍,并发三个词语的内容
SQL语句SELECT * FROM post WHERE title like '%java%介绍%并发%'
根本就实现不了我要查询的内容,因为like表明要同时包含java,介绍,并发三个词语,并不能作为单独的词语关键词来进行检索
如果要SQL实现关键词检索,可以手动将句子拆分成多个关键词
SELECT * FROM post WHERE title like 'java%'
SELECT * FROM post WHERE title like '%介绍'
SELECT * FROM post WHERE title like '%并发'
聪明的你很快就发现,如果这样实现,是不是非常的复杂和麻烦,因为搜索是非常灵活的,你需要手动将句子拆分成多个词语,还不知道怎么拆分才合适;而且不同的关键词对应不同的SQL语句,要写的SQL非常非常多,而且关键词检索是非常灵活的;而且你还要聚合搜索结果,去重啥的....
7.为什么要引入ES
因为搜索存在问题,我们才需要去解决,才需要去引入ES搜索框架,这个根据业务去找技术实现的意识非常重要,进一步明确了技术是用来为业务服务的,没有业务就没有技术
8.阅读es的官方文档并根据文档学习es的使用,学会阅读官方文档
实质上阅读官方文档最关键是利用好文档的目录准确定位到自己所需的地方,然后根据文档实践即可
核心收获
1.门面模式,注册器模式,适配器模式,策略模式等设计模式
2.学会阅读技术的官方文档
3.ES的概念
第四期
官方文档的翻译
1.使用谷歌翻译+沙拉查词划线翻译,二者结合使用,谷歌用作全文翻译,沙拉查词用作指定划线部分翻译。
之所以需要使用沙拉词典翻译是因为有时候我们只需要翻译文档的部分英文
ES的概念
1.索引(文档)->MySQL的表
2.映射->MySQL的表结构
3.正向索引和倒排索引。正向索引是根据文章目录找文章内容,倒排索引是根据文章内容找文章目录
4.DSL,EQL,SQL;重点掌握DSL语法即可
说明:因为ES的搜索非常灵活,所以对应的DSL语法也较为复杂,相对于SQL的语法来说,DSL的学习成本要高一点,但学习方法和SQL一样,孰能生巧就行,不记得就去官方文档查即可
5.分词器
中文较为友好的分词器是ik分词器,ik_smart,ik_max_word,后者是更细粒度的分词器,适合存储数据时使用,前者分词的粒度相对低一点,更适合客户端搜索时使用,更符合语义
6.打分机制
命中的词语越多,得分越高,然后根据得分排序显示结果
操作ES的客户端
1.kinbata的dev tools工具;推荐测试使用,因为安全性的问题,不推荐生产使用
2.spring-data-elasticsearch;推荐开发使用
数据同步
1.定时任务。优点是简单易懂,好上手;缺点是有时间差,会丢失数据,但可以采取补偿机制弥补这个缺陷
2.双写,需要用事务来实现。优点是数据拥有强一致性,缺点是强一致性会带来一定的性能损耗
3.Logstash是一个数据传输和处理的管道组件。组件已经实现数据传输,你只需要配置输入和输出的数据源以及要同步的数据即可;优点是好上手,缺点是需要额外配置和维护一个组件,并需要维护输出和输出等插件,带来额外的成本
4.canal订阅binlog日志组件实现MySQL数据变化的监听,从而实现MySQL和其他数据库的同步(MySQL为主)
鱼皮小贴士
1.开发一定要循序渐进,一个一个小目标去攻克
鱼皮通过阅读官方文档直播踩坑,再一次说明了开发一定要循序渐进,如果上来就把所有东西都做好再测试,会大大增加排错的范围,降低排错的效率,进而降低开发的效率;
而且开发循序渐进,一个小目标一个小目标的攻克,会让人更有动力,也会觉得开发项目没这么难了,毕竟每一个拆分下来的小目标都是较为简单的,可以攻克的
