2026/1/24 2:08:48
网站建设
项目流程
2017网站开发主流工具,兰州企业网站建设公司价格,工程咨询公司加盟合作,6617网址导航彩票网站大全引子#xff1a;一场关于“模糊”需求的拉锯战“咱们这个搜索功能#xff0c;用户反馈说经常只记得内容中间的几个字#xff0c;希望支持前后模糊匹配#xff0c;就像MySQL里LIKE %关键词%那样。”产品经理眨着期待的大眼睛#xff0c;而我心里已经开始警铃大作。“在ES里…引子一场关于“模糊”需求的拉锯战“咱们这个搜索功能用户反馈说经常只记得内容中间的几个字希望支持前后模糊匹配就像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时查询会忽略大小写。性能灾难前导通配符*会导致遍历所有termCPU和内存瞬间飙升妥妥的集群杀手新时代的解决方案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页这不是技术限制而是用户体验的最优解