在与产品经理讨论如何使用Elasticsearch实现类似MySQL中的LIKE查询时,以下是一些可能的技术方案和讨论点:### 方案一:使用Elasticsearch的模糊查询(Fuzzy Query)Elasticsearch本身并不直接支持LIKE查
摘要:曾以为掌握了Elasticsearch的match查询就征服了搜索世界——直到产品经理轻叩桌面,抛出一个看似简单的要求:'我们需要像MySQL的LIKE '%关键词%'那样前后通配的模糊
曾以为掌握了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实现。
