Java優(yōu)化模糊搜索體驗的方法詳解
場景
假設有一張表 t_course
,數(shù)據(jù)量在三到四位數(shù),字段 name
需要支持模糊搜索。用普通的 LIKE
語句,比如:
SELECT id, name FROM t_course WHERE name LIKE '%2025數(shù)學高一下%';
結果卻查不到 2025年高一數(shù)學下學期
。這就很尷尬了,用戶體驗直接拉胯。
方案探索
1. MySQL 全文索引
首先想到 MySQL 的全文索引,但要支持中文分詞得改 ngram_token_size
配置,還得重啟數(shù)據(jù)庫。為了不動生產(chǎn)環(huán)境配置,果斷放棄。
2. Elasticsearch
接著想到 Elasticsearch,但對這么簡單的場景來說,未免有點“殺雞用牛刀”。于是繼續(xù)尋找更輕量的方案。
3. 自定義分詞 + MySQL INSTR
最后想到一個“土辦法”:先對用戶輸入進行分詞,再用 MySQL 的 INSTR
函數(shù)匹配。簡單粗暴,但很實用。
實現(xiàn)
分詞工具
一開始用了 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; } }
本地測試一切正常,但部署到測試環(huán)境后,分詞結果卻變了!比如:
- 本地:
[2025, 數(shù)學, 高一, 下]
- 測試環(huán)境:
[2025, 數(shù), 學, 高, 1, 下]
原因是 jcseg
在 jar 包中加載默認配置和詞庫時出問題了。網(wǎng)上的解決方案大多是外置詞庫,但我懶得折騰,決定自己擼個簡易分詞工具。
簡易分詞工具
最終實現(xiàn)如下:
public class WordSegmentationUtils { private static final List<String> DICT; private static final String COURSE_SEARCH_KEYWORD_LIST = "數(shù)學,物理,化學,生物,地理,歷史,政治,英語,語文,高中,高一,高二,高三"; 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數(shù)學高一下
- 輸出:
[2025, 數(shù)學, 高一, 下]
效果驗證
現(xiàn)在,無論用戶輸入以下哪種形式,都能成功匹配到 2025年高一數(shù)學下學期
:
2025高一數(shù)學下
2025 高一 數(shù)學
數(shù)學高一2025
小結
這個方案雖然簡單,但在小數(shù)據(jù)量場景下,性能和體驗都能滿足需求,且實現(xiàn)成本低。如果遇到特殊情況,可以通過動態(tài)更新詞典來解決。
當然,這種“土辦法”并不適合復雜場景。如果需求升級,可以再考慮 MySQL 全文索引或 Elasticsearch。
到此這篇關于Java優(yōu)化模糊搜索體驗的方法詳解的文章就介紹到這了,更多相關Java優(yōu)化模糊搜索內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
關于ApplicationContext的三個常用實現(xiàn)類
這篇文章主要介紹了關于ApplicationContext的三個常用實現(xiàn)類,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06基于SpringMVC實現(xiàn)網(wǎng)頁登錄攔截
SpringMVC的處理器攔截器類似于Servlet開發(fā)中的過濾器Filter,用于對處理器進行預處理和后處理。因此,本文將為大家介紹如何通過SpringMVC實現(xiàn)網(wǎng)頁登錄攔截功能,需要的小伙伴可以了解一下2021-12-12SpringBoot?Validation快速實現(xiàn)數(shù)據(jù)校驗的示例代碼
在實際開發(fā)中,肯定會經(jīng)常遇到對參數(shù)字段進行校驗的場景,通常我們只能寫大量的if else來完成校驗工作,而如果使用SpringBoot Validation則可以輕松的通過注解來完成,接下來小編給大家介紹下利用SpringBoot?Validation快速實現(xiàn)數(shù)據(jù)校驗的示例代碼,需要的朋友參考下吧2022-06-06