目标是实现一个公司的申请审批流程,整个业务流程涉及到两种角色,分别为商务角色与管理员角色。整个流程如下图所示:
核心流程总结为一句话:商务角色申请添加公司后由管理员进行审批。
商务在添加公司时,可能为了方便,直接填写公司简称,而公司全称可能之前已经被添加过了,为了防止添加重复的公司,所以管理员在针对公司信息审批之前,需要查看以往添加的公司信息里有无同一个公司。
以上是一个业务场景的大概介绍。从技术层面需要考虑实现的功能点:
- 分词
- 与库里已有数据进行匹配
- 按照匹配度对结果进行排序
分词功能有现成的分词器,所以整个需求的核心重点在于如何与数据库中的数据匹配并按照匹配度排序。
- 方案一:引入ES
- 方案二:利用MySQL实现
本系统规模较小,单纯为了实现这个功能引入ES成本较大,还要涉及到数据同步等问题,系统复杂性会提高,所以尽量使用MySQL已有的功能进行实现。
MySQL提供了以下三种模糊搜索的方式:
like匹配
:要求模式串与整个目标字段完全匹配;RegExp正则匹配
:要求目标字段包含模式串即可;Fulltext全文索引
:在字段类型为CHAR
,VARCHAR
,TEXT
的列上创建全文索引,执行SQL进行查询。
针对于上述业务场景,对相关技术进行优劣分析:
- like匹配,无法满足需求,所以
pass
; - 全文索引:可定制性差,不支持任意匹配查询,
pass
; - 正则匹配:可实现任意模式匹配,缺点在于执行效率不如全文索引。
针对于这个场景,记录数目相对来说没有那么多,所以对于效率稍低的结果可以接受,因此技术选型方面采用RegExp正则匹配
来实现模糊匹配的需求。
整个逻辑基于 提取公司名称关键信息 –>分词 –> 匹配 三个核心步骤。
5.1 提取公司关键信息
对输入的公司名称去除无用信息
,保留关键信息。这里的无用信息指的是地名,圆括号,以及集团,股份,有限等。
- 匹配前处理公司名称
1 | ini复制代码 /** |
- 地名工具类
1 | arduino复制代码public class AddressUtil { |
5.2 分词相关代码
- pom文件:引入IK分词器相关依赖
1 | xml复制代码 <!-- ikAnalyzer 中文分词器 --> |
- IKAnalyzerSupport类:用于配置分词器
1 | java复制代码@Slf4j |
- ServiceImpl类:进行分词处理
1 | typescript复制代码 /** |
5.3 匹配
- ServiceImpl类:匹配核心代码
1 | ini复制代码 public JsonResult matchCompanyName(CompanyDTO companyDTO, String accessToken, String localIp) { |
- Repository类:编写SQL语句
1 | ini复制代码/** |
按照匹配度排序这个功能点,LENGTH(companyName)
返回companyName的长度,LENGTH(REPLACE(companyName, ?2, ''))
计算出companyName中关键词出现的次数。通过这种方式,我们可以根据匹配程度进行排序,匹配次数越多的公司名称排序越靠前。
参考资料
- zhuanlan.zhihu.com/p/343198664 【MySQL模糊搜索】
- blog.csdn.net/Cy_LightBul… 【IK分词器集成Spring Boot】
本文转载自: 掘金