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

2025-12-12 0 356

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

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

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

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

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

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

image.png

送走产品经理,我盯着屏幕陷入沉思:在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*\"
      }
    }
  }
}

性能灾难:前导通配符*会导致遍历所有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左右 很低

结果显而易见!


最终技术选型

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

  1. 采购Elasticsearch 8.x集群
  2. 对需要模糊匹配的字段使用wildcard类型
  3. 传统搜索场景继续使用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字段类型,这条演进之路告诉我们:

  1. 了解业务场景:不同的搜索需求需要不同的技术方案
  2. 理解底层原理:明白分词机制和查询原理才能做出正确选择
  3. 拥抱技术演进:新版本往往用更优雅的方式解决老问题

技术人的快乐,往往就藏在解决这些“模糊”需求的过程中。毕竟,让模糊的需求变得清晰,让不可能成为可能——这就是我们的职业乐趣所在!

最后,不知道jym在使用ES搜索功能中还遇到过哪些有趣的技术挑战?欢迎大家在评论区分享你的“血泪史”,让我们一起在技术的道路上避坑前行!

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 编程相关 与产品经理的“模糊”对决:Elasticsearch实现MySQL LIKE '%xxx%' https://www.zuozi.net/35817.html

常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务