news 2026/1/2 9:53:15

与产品经理的“模糊”对决:Elasticsearch实现MySQL LIKE ‘%xxx%‘

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
与产品经理的“模糊”对决:Elasticsearch实现MySQL LIKE ‘%xxx%‘

引子:一场关于“模糊”需求的拉锯战

“咱们这个搜索功能,用户反馈说经常只记得内容中间的几个字,希望支持前后模糊匹配,就像MySQL里LIKE '%关键词%'那样。”

产品经理眨着期待的大眼睛,而我心里已经开始警铃大作。

“在ES里做前后通配符?这玩意搞不好会把集群搞崩啊!” 我试图挣扎。

“但是竞品都有这个功能了...” 产品经理使出了杀手锏。

经过一番“友好协商”,我们达成共识:工期可以延长,但这个功能必须实现!

image

送走产品经理,我盯着屏幕陷入沉思:在Elasticsearch里做前后模糊匹配,这确实是个技术挑战。不过话说回来,我们正准备新采购ES集群,和主管评估后决定直接上8.x版本——等等,ES 7.9不是引入了专门的wildcard字段类型吗?

最终方案:基于ES 8.x的wildcard类型字段 + wildcard查询,完美实现前后模糊匹配!

从“分词”这个基础概念说起

要理解ES的模糊搜索,得先搞明白它最核心的概念——分词。

分词的奇妙世界

当你往ES里存入“苹果手机真香”时,背后发生了这样的变化(使用不同分词器,分出来的词可能不一样):

原始文本:"苹果手机真香"

↓ 分词处理

["苹果", "手机", "真", "香"]

这就是为什么最简单的match查询能够工作:

GET /products/_search

{

"query": {

"match": {

"name": "苹果手机"

}

}

}

但是,这里藏着第一个坑!

默认情况下,match查询使用or操作符,意味着:

// 搜索"苹果手机"可能返回:

// - "苹果电脑"(只匹配"苹果")

// - "华为手机"(只匹配"手机")

// - "苹果手机"(完全匹配)

// - "好吃苹果"(只匹配"苹果")

用户想要的是“苹果手机”,结果搜出来一堆不相干的东西,这体验能好吗?

更精确的匹配方式

match + operator "and" - 必须全部包含

GET /products/_search

{

"query": {

"match": {

"name": {

"query": "苹果手机",

"operator": "and"

}

}

}

}

效果:必须同时包含"苹果"和"手机"两个词。

进步: 排除了只包含一个词的无关结果。

新问题:顺序不固定!“手机苹果”也会被匹配,这显然不符合正常语言习惯。

match_phrase - 真正的词组匹配

GET /products/_search

{

"query": {

"match_phrase": {

"name": "苹果手机"

}

}

}

完美!必须完整包含"苹果手机"这个词组,且顺序一致。

但是... 当测试用例显示:“用户只记得'果手'两个字,怎么搜不到'苹果手机'?”

我意识到,传统的分词搜索有其局限性。

ES 7.9之前的解决方案:n-gram分词器

面对前后模糊匹配的需求,在ES 7.9之前,最成熟的方案就是n-gram分词器 + match_phrase实现。

什么是n-gram?

简单说,就是把文本切成固定长度的片段:

原始文本:"苹果手机"

2-gram分词:["苹果", "果手", "手机"]

3-gram分词:["苹果手", "果手机"]

配置n-gram分析器

PUT /products

{

"settings": {

"analysis": {

"analyzer": {

"ngram_analyzer": {

"tokenizer": "ngram_tokenizer"

}

},

"tokenizer": {

"ngram_tokenizer": {

"type": "ngram",

"min_gram": 2, // 最小2个字符

"max_gram": 3 // 最大3个字符

}

}

}

},

"mappings": {

"properties": {

"name": {

"type": "text",

"analyzer": "ngram_analyzer",

"search_analyzer": "standard"

}

}

}

}

实现前后模糊匹配

GET /products/_search

{

"query": {

"match_phrase": {

"name": "果手"

}

}

}

效果:成功匹配到"苹果手机"!

付出的代价:

✅ 支持任意位置的子串匹配

❌ 索引体积膨胀3倍以上

❌ 查询性能受影响

❌ 需要精细调整n-gram参数

危险的诱惑:7.9之前的wildcard查询

在调研过程中,我发现ES其实一直都有wildcard查询,但文档里满是红色警告。

揭开wildcard查询的真相

常见误解1: "7.9版本以下只能查keyword字段"

事实: wildcard可以作用于text字段,但匹配的是分词后的term,结果往往出乎意料,不尽人意。

常见误解2: "会进行全索引扫描"

事实: 扫描的是字段倒排索引中的所有term,对每个term进行正则匹配。

wildcard查询实战

// 对keyword字段查询(相对可用)

GET /products/_search

{

"query": {

"wildcard": {

"name": {

"value": "*iPhone*",

"case_insensitive": true

}

}

}

}

// 对text字段查询(强烈不推荐)

GET /products/_search

{

"query": {

"wildcard": {

"name": {

"value": "*iphone*"

}

}

}

}

说明:当设置case_insensitive为true时,查询会忽略大小写。

性能灾难:前导通配符*会导致遍历所有term,CPU和内存瞬间飙升,妥妥的集群杀手!

新时代的解决方案:ES 7.9+的wildcard字段类型

就在我纠结要不要接受n-gram的索引膨胀时,突然想起:我们不是准备采购ES 8.x吗?

ES 7.9引入的wildcard字段类型简直就是为此场景量身定制!

技术原理揭秘

智能n-gram索引:底层使用优化的3字符n-gram

二进制doc value:完整保存原始文档,保证匹配精度

专用查询引擎:针对通配符场景深度优化

实际配置和使用

PUT /products

{

"mappings": {

"properties": {

"name": {

"type": "wildcard" // 专门为通配符优化的字段类型

}

}

}

}

GET /products/_search

{

"query": {

"wildcard": {

"name": {

"value": "*果手*" // 前后模糊匹配

}

}

}

}

性能对比:数字说话

在我们的测试环境中:

方案 索引大小 平均查询延迟 集群影响 功能完整性

n-gram + match_phrase 原始大小 × 约3倍 50ms左右 中等 ✅

旧版wildcard查询 原始大小 1000ms+ 极高风险 ✅

wildcard字段类型 原始大小 × 约1.4倍 25ms左右 很低 ✅

结果显而易见!

最终技术选型

经过充分的测试和对比,我们最终拍板:

采购Elasticsearch 8.x集群

对需要模糊匹配的字段使用wildcard类型

传统搜索场景继续使用match_phrase等成熟方案

// 最终的映射设计

PUT /products

{

"mappings": {

"properties": {

"name": {

"type": "wildcard" // 用于前后模糊匹配

},

"description": {

"type": "text" // 用于常规全文搜索

},

"category": {

"type": "keyword" // 用于精确分类匹配

}

}

}

}

当演示结果出来时,产品和用户都很满意:“所以现在输入'果手'真的能找到'苹果手机'了?而且性能还不错?”

“没错,这就是技术演进的力量!”我微笑着回答。

(其实是工期足的力量☺️,工期足够长,资金足够多,什么都能做😊)

总结:Elasticsearch模糊搜索方案对比

搜索方式 适用场景 优点 缺点 推荐指数

match 常规全文搜索 简单易用 精度较低 ⭐⭐⭐⭐

match + operator: "and" 多词必须匹配 提高相关性 顺序不固定 ⭐⭐⭐

match_phrase 精确词组匹配 顺序一致 不支持模糊 ⭐⭐⭐⭐

n-gram + match_phrase 前后模糊匹配 功能完整 索引膨胀严重 ⭐⭐⭐

旧版wildcard查询 通配符匹配 使用简单 性能极差 ⭐

wildcard字段类型 前后模糊匹配 性能优秀 需要ES 7.9+ ⭐⭐⭐⭐⭐

技术心得:

从最初的match查询到最终的wildcard字段类型,这条演进之路告诉我们:

了解业务场景:不同的搜索需求需要不同的技术方案

理解底层原理:明白分词机制和查询原理才能做出正确选择

拥抱技术演进:新版本往往用更优雅的方式解决老问题

友情提示: 如果你的产品经理接下来要求实现“深度分页”,请温柔地提醒TA——就连淘宝搜索也只支持100页,这不是技术限制,而是用户体验的最优解!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/17 19:21:24

(N_115)基于springboot,vue教务管理系统

开发工具:IDEA 服务器:Tomcat9.0, jdk1.8 项目构建:maven 数据库:mysql5.7 前端技术:vue elementUI 服务端技术:springbootmybatis 本系统拥有三种角色:管理员、教师和学生&am…

作者头像 李华
网站建设 2025/12/17 19:20:17

Photoshop图层批量处理工作流优化指南

Photoshop图层批量处理工作流优化指南 【免费下载链接】Photoshop-Export-Layers-to-Files-Fast This script allows you to export your layers as individual files at a speed much faster than the built-in script from Adobe. 项目地址: https://gitcode.com/gh_mirror…

作者头像 李华
网站建设 2025/12/27 22:23:03

linpack测试中的报错分析及解决办法

mpirun -np 256 xhpl -input ./HPL.dat 出现报错 [proxy:0localhost] HYDU_create_process (lib/utils/launch.c:24): pipe error (Too many open files) [proxy:0localhost] launch_procs (proxy/pmip_cb.c:1008): create process returned error [proxy:0localhost] handle_…

作者头像 李华
网站建设 2025/12/24 14:15:31

Element Plus自动化部署突破:5分钟快速搭建高效CI/CD流水线

Element Plus自动化部署突破:5分钟快速搭建高效CI/CD流水线 【免费下载链接】element-plus element-plus/element-plus: Element Plus 是一个基于 Vue 3 的组件库,提供了丰富且易于使用的 UI 组件,用于快速搭建企业级桌面和移动端的前端应用。…

作者头像 李华
网站建设 2025/12/30 11:53:19

LightGlue实战指南:突破传统图像匹配的性能瓶颈

LightGlue实战指南:突破传统图像匹配的性能瓶颈 【免费下载链接】LightGlue LightGlue: Local Feature Matching at Light Speed (ICCV 2023) 项目地址: https://gitcode.com/gh_mirrors/li/LightGlue 在计算机视觉领域,图像特征匹配技术正面临前…

作者头像 李华
网站建设 2025/12/19 13:05:46

思特奇实力入选“2025中国信创服务商TOP50”,以创新驱动信创生态建设

近日,在亿欧主办的“WIM2025创新者年会”颁奖盛典期间,2025中国信创服务商TOP50榜单正式发布。思特奇凭借在信创领域的持续深耕与卓越创新,成功入选该榜单。这一荣誉不仅是对思特奇技术实力与行业贡献的高度认可,更体现了其在推动…

作者头像 李华