场景
假设有一张表 t_course
,数据量在三到四位数,字段 name
需要支持模糊搜索。用普通的 like
语句,比如:
select id, name from t_course where name like '%2025数学高一下%';
结果却查不到 2025年高一数学下学期
。这就很尴尬了,用户体验直接拉胯。
方案探索
1. mysql 全文索引
首先想到 mysql 的全文索引,但要支持中文分词得改 ngram_token_size
配置,还得重启数据库。为了不动生产环境配置,果断放弃。
2. elasticsearch
接着想到 elasticsearch,但对这么简单的场景来说,未免有点“杀鸡用牛刀”。于是继续寻找更轻量的方案。
3. 自定义分词 + mysql instr
最后想到一个“土办法”:先对用户输入进行分词,再用 mysql 的 instr
函数匹配。简单粗暴,但很实用。
实现
分词工具
一开始用了 jcseg
分词库,写了个工具类:
public class jcsegutils { private static final segmenterconfig config = new segmenterconfig(true); private static final adictionary dic = dictionaryfactory.createsingletondictionary(config); public static list<string> segment(string text) throws ioexception { isegment seg = isegment.nlp.factory.create(config, dic); seg.reset(new stringreader(text)); iword word; list<string> result = new arraylist<>(); while ((word = seg.next()) != null) { string wordtext = word.getvalue(); if (stringutils.isnotblank(wordtext)) { result.add(wordtext); } } return result; } }
本地测试一切正常,但部署到测试环境后,分词结果却变了!比如:
- 本地:
[2025, 数学, 高一, 下]
- 测试环境:
[2025, 数, 学, 高, 1, 下]
原因是 jcseg
在 jar 包中加载默认配置和词库时出问题了。网上的解决方案大多是外置词库,但我懒得折腾,决定自己撸个简易分词工具。
简易分词工具
最终实现如下:
public class wordsegmentationutils { private static final list<string> dict; private static final string course_search_keyword_list = "数学,物理,化学,生物,地理,历史,政治,英语,语文,高中,高一,高二,高三"; static { dict = new arraylist<>(); for (int i = 2018; i <= 2099; i++) { dict.add(string.valueof(i)); } dict.addall(arrays.aslist(course_search_keyword_list.split(","))); } public static list<string> segment(string text) { if (stringutils.isblank(text)) { return new arraylist<>(); } list<string> segments = new arraylist<>(); segments.add(text); for (string word : dict) { segments = segment(segments, word); } return segments; } private static list<string> segment(list<string> segments, string word) { list<string> newsegments = new arraylist<>(); for (string segment : segments) { if (segment.contains(word)) { newsegments.add(word); string[] split = segment.split(word); for (string s : split) { if (stringutils.isnotblank(s)) { newsegments.add(s.trim()); } } } else { newsegments.add(segment); } } return newsegments; } }
这个工具基于一个简单的词典 dict
,按词典中的词对输入文本进行分割。比如:
- 输入:
2025数学高一下
- 输出:
[2025, 数学, 高一, 下]
效果验证
现在,无论用户输入以下哪种形式,都能成功匹配到 2025年高一数学下学期
:
2025高一数学下
2025 高一 数学
数学高一2025
小结
这个方案虽然简单,但在小数据量场景下,性能和体验都能满足需求,且实现成本低。如果遇到特殊情况,可以通过动态更新词典来解决。
当然,这种“土办法”并不适合复杂场景。如果需求升级,可以再考虑 mysql 全文索引或 elasticsearch。
到此这篇关于java优化模糊搜索体验的方法详解的文章就介绍到这了,更多相关java优化模糊搜索内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论