曾以为把握了Elasticsearch的match查询就征服了搜索天下——直到产物司理轻叩桌面,抛出一个看似简朴的要求:"我们必要像MySQL的LIKE '%关键词%'那样前后通配的暗昧搜索。" 我嘴角微扬,意识到真正的技能探险才刚刚开始。
引子:一场关于“暗昧”需求的拉锯战
“咱们这个搜索功能,用户反馈说经常只记得内容中心的几个字,盼望支持前后暗昧匹配,就像MySQL里LIKE '%关键词%'那样。”
产物司理眨着等候的大眼睛,而我心田已经开始警铃大作。
“在ES里做前后通配符?这玩意搞欠好会把集群搞崩啊!” 我试图挣扎。
“但是竞品都有这个功能了...” 产物司理使出了杀手锏。
颠末一番“友爱协商”,我们告竣共识:工期可以延伸,但这个功能必须实现!
送走产物司理,我盯着屏幕陷入沉思:在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页,这不是技能限定,而是用户体验的最优解!
技能人的快乐,通常就藏在办理这些“暗昧”需求的过程中。究竟,让暗昧的需求变得清楚,让不大概成为大概——这就是我们的职业兴趣地点!
掘金原文(个人技能文章优先在掘金发布):https://juejin.cn/post/7559981310472470562
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|