使用到的设计模式

Facade门面模式

为何使用?

在搜索项目中,由于使用Mvc架构且数据库中各种不同类型的数据源并没有放在同一张表,于是我们不可避免的在Controller中需要注入多个service,各种service眼花缭乱,而搜索中台提供的内容又及其单一(只负责返回搜索数据),于是采用Facade来统一接口以及装载service

代码呈现

需要注意的是,我们还需要一个统一的return对象(SearchVo),有两种思路:

  • SearchVo声明成接口,由其他如PostVo来实现
  • 直接聚合:SearchVo聚合各个如PostVo的内容(对于内容我们也可采用抽象类来实现)等
@Component
public class SearchFacade {
@Autowired
private PictureService pictureService;
@Autowired
private PostService postService;
@Autowired
private UserService userService;
@Autowired
private DataSourceRegistry dataSourceRegistry;
public SearchVo getAll(SearchQueryRequest searchQueryRequest, HttpServletRequest request) {
long current = searchQueryRequest.getCurrent();
long size = searchQueryRequest.getPageSize();
String searchText = searchQueryRequest.getSearchText();
String type = searchQueryRequest.getType();
SearchTypeEnum searchTypeEnum = SearchTypeEnum.getEnumByValue(type);
ThrowUtils.throwIf(type != null && StringUtils.isBlank(type), ErrorCode.PARAMS_ERROR);
SearchVo searchVo = new SearchVo();
if (searchTypeEnum == null) {
CompletableFuture<Void> picCF = CompletableFuture.runAsync(() -> {
List<Picture> pictures = pictureService.searchPicture(searchQueryRequest.getSearchText(), searchQueryRequest.getCurrent(), searchQueryRequest.getPageSize());
searchVo.setPicList(pictures);
});
CompletableFuture<Void> userCF = CompletableFuture.runAsync(() -> {
UserQueryRequest userQueryRequest = new UserQueryRequest();
userQueryRequest.setUserName(searchText);
userQueryRequest.setCurrent(current);
userQueryRequest.setPageSize(size);
Page<UserVO> userVOPage = userService.listUserVoByPage(userQueryRequest);
searchVo.setUserList(userVOPage.getRecords());
});
CompletableFuture<Void> postCF = CompletableFuture.runAsync(() -> {
PostQueryRequest postQueryRequest = new PostQueryRequest();
postQueryRequest.setSearchText(searchText);
postQueryRequest.setCurrent(current);
postQueryRequest.setPageSize(size);
Page<PostVO> postPage = postService.listPostVOByPage(postQueryRequest, request); searchVo.setPostList(postPage.getRecords()); });
try {
CompletableFuture.allOf(postCF, userCF, picCF).get();
} catch (Exception e) {
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "查询数据异常");
}
} else { DataSource dataSource = dataSourceRegistry.dataSourceMap.get(type);
List<?> list = dataSource.doSearch(searchText, current, size);
searchVo.setDataList(list);
}
return searchVo;
}
}

tips:

这里的真实有效的仅有dataList(其他三个是第二版的残留物)

/**
* @author:天才玩家M
* @date:2023/10/4 11:32
* @description:TODO
*/
@Data
public class SearchVo {
private List<Picture> picList;
private List<PostVO> postList;
private List<UserVO> userList;
private List<?> dataList;
}

适配器模式

为何使用?:

搜索中台中,我们之后可能会接入各种各样的type的搜索数据源,比如说我自己,有时候,几乎是同样功能的service只是数据源不一样,不复制粘贴就常常弄得各有各的接口,就很乱,所以出现了适配器模式,一方面,如果这个service不是我们写的,我们在其之后写,可以利用适配器尝试将对方改为我们的适配的api,或者我们先定了适配器,让对方按照我们的标准来实现

public interface DataSource<T> {
List<T> doSearch(String searchText,Long current,Long pageSize);
}

其他数据源:

public class PostDataSource implements DataSource<PostVO>{...}

注册器模式

为何使用?

承接上面的门面,以及适配器,在实际场景中我们肯定要根据不同的searchType更换,那么用switch?

太复杂了,那用一个map封装一下,之后get,差不多,这可大大节省了代码量

@Component
public class DataSourceRegistry {
public Map<String,DataSource> dataSourceMap=null;
@PostConstruct
public void initMap(){
dataSourceMap=new HashMap();
dataSourceMap.put(SearchTypeEnum.POST.getValue(),new PostDataSource());
dataSourceMap.put(SearchTypeEnum.PICTURE.getValue(),new PictureDataSource());
dataSourceMap.put(SearchTypeEnum.USER.getValue(),new UserDataSource());
}
}

ES的概念

倒排索引

正向索引:字典or通常书籍的目录

倒排索引:

输入数据时

会根据我们输入es的内容,先分词,然后统计哪个分词在哪个doc出现过,通过内容来检索到哪个doc

查找数据时

同样会通过分词,然后根据总共分词在哪些doc出现过,返回对应的数据

用户搜:“鱼皮rapper”

ES 先切词:鱼皮,rapper

去倒排索引表找对饮的文章:文章A,B

内容 id
你好 文章A,B
我是 文章A,B
rapper 文章A
鱼皮 文章B
coder 文章B

一个待升级点

es会通过我们输入的searchText来分词然后返回docs,这些doc同时带有一定的评分,我们可以通过这些评分来倒序返回给用户,实现对应的功能

(类似:百度:查找的时候第一页的内容和我们搜索的相关性较高(抛开广告不谈的话),之后相关性逐渐降低)

待解决点:

page改成cur_point

能够优化ES性能

尤其是像我们手机电商这种页码不明显的情况下,当然明显也能替换

Sea-Search03总结&&un finish的更多相关文章

  1. sea.js模块化编程

    * 为什么要模块化? 解决文件依赖 解决命名冲突 ; var var2 = 2; function fn1(){ } function fn2(){ } return { fn1: fn1, fn2: ...

  2. 【Codeforces 738D】Sea Battle(贪心)

    http://codeforces.com/contest/738/problem/D Galya is playing one-dimensional Sea Battle on a 1 × n g ...

  3. 在eclipse创建android project,最后一步点击finish没反应

    在创建android project的时候,到最后一步点击finish没有反应. 本来以为可能是SDK中的Extra下Android Support Library没有安装,后来检查发现Minimum ...

  4. 解决sea.js引用jQuery提示$ is not a function的问题

    在使用sea.js的如下写法引用jQuery文件时, //main.jsdefine(function(require,exports,module){ var $ = require('jquery ...

  5. Android中finish掉其它的Activity

    在Android开发时,一般情况下我们如果需要关掉当前Activity非常容易,只需要一行代码 this.finish;即可.那么,如果是想要在当前Activity中关掉其它的Activity应该怎么 ...

  6. finish()在dialog中的作用

    finish()在dialog中销毁的是dialog所在的活动:

  7. 模块化开发--sea.js

    当你的网站开发越来越复杂的时候,会经常遇到一下问题吗?1.冲突2.性能3.依赖如果在多人开发或者是复杂的开发过程中会经常遇到这些问 题,就可以用模块化开发来解决.以上问题是如何产生的?1.冲突:如果你 ...

  8. sea.js 入门

    上个月学了 require.js 现在顺便来学学 sea.js. 对比下这两种的区别,看自己喜欢哪个,就在接下来的项目中去使用它吧. seajs中的所有 JavaScript 模块都遵循 CMD 模块 ...

  9. 第三课:sea.js模块加载原理

    模块加载,其实就是把js分成很多个模块,便于开发和维护.因此加载很多js模块的时候,需要动态的加载,以便提高用户体验. 在介绍模块加载库之前,先介绍一个方法. 动态加载js方法: function l ...

  10. Codeforces 738D. Sea Battle 模拟

    D. Sea Battle time limit per test: 1 second memory limit per test :256 megabytes input: standard inp ...

随机推荐

  1. 【驱动】以太网扫盲(四)phy驱动link up流程分析

    1. 简介 在调试网口驱动的过程中发现phy芯片的驱动框架结构还有点复杂,不仔细研究的话还不好搞懂,另外百度到的资料也不够全面,这篇就总结梳理一下这方面的知识. 我们知道一个 phy 驱动的原理是非常 ...

  2. h5响应式方案设计

  3. 用C#实现最小二乘法(用OxyPlot绘图)✨

    最小二乘法介绍 最小二乘法(Least Squares Method)是一种常见的数学优化技术,广泛应用于数据拟合.回归分析和参数估计等领域.其目标是通过最小化残差平方和来找到一组参数,使得模型预测值 ...

  4. 每天学五分钟 Liunx 010 | ssh

    Liunx ssh known_hosts   known_hosts是做服务器认证的.当用 ssh 连接到一个新的服务器的时候,ssh 会让你确认服务器的信息(域名.IP.公钥),如果你确认了,就会 ...

  5. spring boot 集成配置阿里 Druid监控配置

    本文为博主原创,转载请注明出处: github 地址如下:https://github.com/alibaba/druid/wiki 其相关问题也可参考:https://github.com/alib ...

  6. AHB 局限性

    AHB's problem SoC bus 架构 AXI is used more and more 频率200M使用AHB,频率再升高就使用AXI AHB的问题 AHB协议本身限制要求较高,比如co ...

  7. DC逻辑综合工具简介-Design Compiler

    逻辑综合简介 逻辑综合:代码转变为网表 FPGA:代码转变为FPGA内部的数字单元 在进行综合的时候往往会使用一些脚本工具 需要学会看综合之后的报告 1.目标 进行综合需要读入RTL设计,还需要用到f ...

  8. 【TouchGFX】屏幕概念

    Screen构成 界面布局 View, 逻辑处理 Presenter Currently Active Screen 因TouchGFX分配内存的的方式是,按照最大的Screen分配,即最大View+ ...

  9. Springboot开发的应用为什么这么占用内存

    Springboot开发的应用为什么这么占用内存 Java的原罪 Java 程序员比 c或者是c++程序员相比轻松了很多. 不要管理繁杂的内存申请与释放,也不用担心因为忘记释放内存导致很严重的内存泄漏 ...

  10. [转帖]redis缓存命中率介绍

    缓存命中率的介绍 命中:可以直接通过缓存获取到需要的数据. 不命中:无法直接通过缓存获取到想要的数据,需要再次查询数据库或者执行其它的操作.原因可能是由于缓存中根本不存在,或者缓存已经过期. 通常来讲 ...