Elasticsearch 警惕使用 wildcard 检索!然后呢?

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
简介: wildcard 检索可以定义为:支持通配符的模糊检索。类似 Mysql 中的 like 模糊匹配,如下所示:

image.png

通配符运算符是匹配一个或多个字符的占位符。


通配符支持两种:


? : 支持模糊匹配单个字符。举例:Ma?s 仅能匹配:Mars, Mass, 和 Maps。


: 支持模糊匹配零个或者多个字符。举例:Ma*s 能匹配:Mars, Matches 和 Massachusetts等。


2、全局视野——wildcard 检索所处位置

全局认知非常重要,检索核心类型大致(非严谨、精确)分为:精准匹配检索(Term-level queries)和基于分词的全文匹配检索(Full text queries)。


全文匹配检索细分如下:

image.png

精准匹配检索细分如下:

image.png

也就是:wildcard 是和Term、Terms检索平级的检索。


3、wildcard 检索适用场景

适用于:召回率要求高的业务场景。


基于分词的全文检索,可能会导致明明存在,但是检索不到。可能的原因如下:


原因1:基础词库不完备;


原因2:分词粒度不精确。


举个例子一看就明白了:


前置说明:


1、纯属举例,不涉及针对具体人。


2、Ik 词典main.dic 非原生,做了互联网词库的扩展,但词库中依然没有“刘强东”三个字。


3、如果你在本地测试结果和文章不一致,极大可能是词典不一样导致的。


PUT test-004

{

 "mappings": {

   "properties": {

     "title": {

       "type": "text",

       "analyzer": "ik_max_word",

       "fields": {

         "keyword": {

           "type": "keyword"

         }

       }

     }

   }

 }

}

POST test-004/_bulk

{"index":{"_id":1}}

{"title":"英文官网承认刘强东一度被捕的原因是涉嫌XX"}

{"index":{"_id":2}}

{"title":"别提了朋友哥哥刘强东窗事发了"}

{"index":{"_id":3}}

{"title":"刘强东施效颦,没想到竟然收获了流量"}

{"index":{"_id":4}}

{"title":"刘强东是谁?我不认识"}

POST test-004/_search

{

 "query": {

   "match_phrase": {

     "title": "刘强东"

   }

 }

}

用的短语检索 match_phrase,搜索结果如下:

image.png

原因说明,analyzer API 能说明一切。

1. POST test-004/_analyze
2. {
3.   "text": [
4.     "京东英文官网承认刘强东一度被捕的原因是涉嫌XX"
5.   ],
6.   "analyzer": "ik_max_word"
7. }

分词结果如下:

image.png

面对如上召回情况,部分不追求精准率只追求召回率的业务场景,可能会需要文档_id = 1、2、3、4 全部都要召回。


这时候,如果不改变分词的情况下,可能的解决方案之一就是:wildcard 检索实现。


POST test-004/_search

{

 "query": {

   "wildcard": {

     "title.keyword": "*刘强东*"

   }

 }

}

如上的方式,文档1、2、3、4全部召回。


相当于在原有DSL的基础上,只改动检索方式和字段名称就搞定了产品经理的提高召回率的需求。


貌似,可以交差大吉了。实则,有非常大的隐患。


4、wildcard 可能的风险

官方文档是这么说的

image.png

中文含义是:避免以*或?开头的模式。这会增加查找匹配项所需的迭代次数并降低搜索性能。

wildcard 到底有多慢?如下示例可见一斑:

image.png

wildcard 检索字段指定的字符数多了以后,会报错如下:

image.png

在 wood 大叔 2017年的文章中,曾经指出如下的核心点:


4.1 出现问题


用户输入的字符串长度没有做限制,导致首尾通配符中间可能是很长的一个字符串。后果就是对应的wildcard Query执行非常慢,非常消耗CPU。


4.2 根本原因


为了加速通配符和正则表达式的匹配速度,Lucene4.0开始会将输入的字符串模式构建成一个DFA (Deterministic Finite Automaton),带有通配符的pattern构造出来的DFA可能会很复杂,开销很大。


源码及细节推荐阅读:


https://elasticsearch.cn/article/171


https://elasticsearch.cn/article/186


5、wildcard 实战中的悲剧

如下,采用原汁原味的技术群交流内容,更具有说服力。


更能警示大家:慎用 Wildcard!


5.1 悲剧1:一味的满足产品经理的需求,wildcard 不考虑性能的乱用。5.4 悲剧4:客户现场演示,集群宕机!

根因:bool 组合了近 100 组+ wildcard 不同关键词的检索。


6、wildcard 可能的替代方案

在寻求解决方案的时候,我们要先问一下:为什么大家喜欢用 wildcard 实现模糊检索?


得到的答复往往是:顺手,类似Mysql like 查询,短、平、快的达到了产品经理的要求,满足了项目需求。


但,这忽略了性能问题以及可能带来的灾难后果。


所以,解决方案应该从根源上入手,以寻求彻底解决。


6.1 替代方案一:写入时分词优化,使用 Ngram 分词。

更细粒度分词,更有利于数据的召回!


PUT test-005

{

 "settings": {

   "index.max_ngram_diff": 10,

   "analysis": {

     "analyzer": {

       "my_analyzer": {

         "tokenizer": "my_tokenizer"

       }

     },

     "tokenizer": {

       "my_tokenizer": {

         "type": "ngram",

         "min_gram": 3,

         "max_gram": 10,

         "token_chars": [

           "letter",

           "digit"

         ]

       }

     }

   }

 },

 "mappings": {

   "properties": {

     "title": {

       "type": "text",

       "analyzer": "my_analyzer",

       "fields": {

         "keyword": {

           "type": "keyword"

         }

       }

     }

   }

 }

}

POST test-005/_bulk

{"index":{"_id":1}}

{"title":"英文官网承认刘强东一度被捕的原因是涉嫌性侵"}

{"index":{"_id":2}}

{"title":"别提了朋友哥哥刘强东窗事发了"}

{"index":{"_id":3}}

{"title":"刘强东施效颦,没想到竟然收获了流量"}

{"index":{"_id":4}}

{"title":"刘强东是谁?我不认识"}

POST test-005/_search

{

 "query": {

   "match_phrase": {

     "title": "刘强东"

   }

 }

}

Ngram 实现推荐:


Elasticsearch能检索出来,但不能正确高亮怎么办?


6.2 替代方案二:7.9 + 以上的版本,使用 wildcard 数据类型。

wildcard 类型出现的目的:一方面避免了某些场景下分词查询不准确的问题,另一方面也解决了通配符和正则检索的效率问题。


注意:新上的数据类型 wildcard,而非 wildcard 检索。


使用方法参见:


https://www.elastic.co/guide/en/elasticsearch/reference/master/keyword.html#wildcard-field-type


6.3 禁用方案:禁止使用wildcard 模糊检索

特殊业务场景需要禁止:wildcard 检索。


实现如下:


PUT _cluster/settings

{

 "transient": {

   "search.allow_expensive_queries": false

 }

}

需要强调的是:


"search.allow_expensive_queries"  是 7.7+ 版本才有的功能,早期版本会报错。


7、小结

由于技术惯性,我们习惯于相同或者相通技术的技术迁移,比如:mysql like 查询迁移到 Elasticsearch 中的 wildcard 模糊检索。但迁移的时候一定要注意:不同技术点的实现差异,同时要多关注技术点不能可能导致的性能问题。


即便 2017年 wood 大叔就发了两篇文章让大家警惕 wildcard 模糊检索可能带来的性能问题。但四年后的今天,仍然很多公司的实战业务中还未考虑性能及后果的前提下,乐此不疲的用着 wildcard 检索!


所以,本文算是 wood 大叔的 wildcard 警示文章接力,希望更多人看到。


参考:


https://t.zsxq.com/Y3zv7Eq


https://t.zsxq.com/bm62zZf


————————————————

版权声明:本文为CSDN博主「铭毅天下」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/laoyang360/article/details/1152223295.4 悲剧4:客户现场演示,集群宕机!

根因:bool 组合了近 100 组+ wildcard 不同关键词的检索。


6、wildcard 可能的替代方案

在寻求解决方案的时候,我们要先问一下:为什么大家喜欢用 wildcard 实现模糊检索?


得到的答复往往是:顺手,类似Mysql like 查询,短、平、快的达到了产品经理的要求,满足了项目需求。


但,这忽略了性能问题以及可能带来的灾难后果。


所以,解决方案应该从根源上入手,以寻求彻底解决。


6.1 替代方案一:写入时分词优化,使用 Ngram 分词。

更细粒度分词,更有利于数据的召回!


PUT test-005

{

 "settings": {

   "index.max_ngram_diff": 10,

   "analysis": {

     "analyzer": {

       "my_analyzer": {

         "tokenizer": "my_tokenizer"

       }

     },

     "tokenizer": {

       "my_tokenizer": {

         "type": "ngram",

         "min_gram": 3,

         "max_gram": 10,

         "token_chars": [

           "letter",

           "digit"

         ]

       }

     }

   }

 },

 "mappings": {

   "properties": {

     "title": {

       "type": "text",

       "analyzer": "my_analyzer",

       "fields": {

         "keyword": {

           "type": "keyword"

         }

       }

     }

   }

 }

}

POST test-005/_bulk

{"index":{"_id":1}}

{"title":"英文官网承认刘强东一度被捕的原因是涉嫌性侵"}

{"index":{"_id":2}}

{"title":"别提了朋友哥哥刘强东窗事发了"}

{"index":{"_id":3}}

{"title":"刘强东施效颦,没想到竟然收获了流量"}

{"index":{"_id":4}}

{"title":"刘强东是谁?我不认识"}

POST test-005/_search

{

 "query": {

   "match_phrase": {

     "title": "刘强东"

   }

 }

}

Ngram 实现推荐:


Elasticsearch能检索出来,但不能正确高亮怎么办?


6.2 替代方案二:7.9 + 以上的版本,使用 wildcard 数据类型。

wildcard 类型出现的目的:一方面避免了某些场景下分词查询不准确的问题,另一方面也解决了通配符和正则检索的效率问题。


注意:新上的数据类型 wildcard,而非 wildcard 检索。


使用方法参见:


https://www.elastic.co/guide/en/elasticsearch/reference/master/keyword.html#wildcard-field-type


6.3 禁用方案:禁止使用wildcard 模糊检索

特殊业务场景需要禁止:wildcard 检索。


实现如下:


PUT _cluster/settings

{

 "transient": {

   "search.allow_expensive_queries": false

 }

}

需要强调的是:


"search.allow_expensive_queries"  是 7.7+ 版本才有的功能,早期版本会报错。


7、小结

由于技术惯性,我们习惯于相同或者相通技术的技术迁移,比如:mysql like 查询迁移到 Elasticsearch 中的 wildcard 模糊检索。但迁移的时候一定要注意:不同技术点的实现差异,同时要多关注技术点不能可能导致的性能问题。


即便 2017年 wood 大叔就发了两篇文章让大家警惕 wildcard 模糊检索可能带来的性能问题。但四年后的今天,仍然很多公司的实战业务中还未考虑性能及后果的前提下,乐此不疲的用着 wildcard 检索!


所以,本文算是 wood 大叔的 wildcard 警示文章接力,希望更多人看到。


参考:


https://t.zsxq.com/Y3zv7Eq


https://t.zsxq.com/bm62zZf

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
4月前
|
SQL JSON 大数据
ElasticSearch的简单介绍与使用【进阶检索】 实时搜索 | 分布式搜索 | 全文搜索 | 大数据处理 | 搜索过滤 | 搜索排序
这篇文章是Elasticsearch的进阶使用指南,涵盖了Search API的两种检索方式、Query DSL的基本语法和多种查询示例,包括全文检索、短语匹配、多字段匹配、复合查询、结果过滤、聚合操作以及Mapping的概念和操作,还讨论了Elasticsearch 7.x和8.x版本中type概念的变更和数据迁移的方法。
ElasticSearch的简单介绍与使用【进阶检索】 实时搜索 | 分布式搜索 | 全文搜索 | 大数据处理 | 搜索过滤 | 搜索排序
|
4月前
|
存储 API 数据库
检索服务elasticsearch索引(Index)
【8月更文挑战第23天】
70 6
|
4月前
|
存储 负载均衡 监控
检索服务elasticsearch节点(Node)
【8月更文挑战第23天】
62 5
|
4月前
|
存储 监控 负载均衡
检索服务elasticsearch集群(Cluster)
【8月更文挑战第23天】
66 3
|
4月前
|
网络协议 Java API
SpringBoot整合Elasticsearch-Rest-Client、测试保存、复杂检索
这篇文章介绍了如何在SpringBoot中整合Elasticsearch-Rest-Client,并提供了保存数据和进行复杂检索的测试示例。
SpringBoot整合Elasticsearch-Rest-Client、测试保存、复杂检索
|
3月前
|
存储 自然语言处理 关系型数据库
ElasticSearch基础3——聚合、补全、集群。黑马旅游检索高亮+自定义分词器+自动补全+前后端消息同步
聚合、补全、RabbitMQ消息同步、集群、脑裂问题、集群分布式存储、黑马旅游实现过滤和搜索补全功能
ElasticSearch基础3——聚合、补全、集群。黑马旅游检索高亮+自定义分词器+自动补全+前后端消息同步
|
4月前
|
SQL 存储 自然语言处理
检索服务elasticsearch全文搜索
【8月更文挑战第22天】
61 3
|
4月前
|
SQL 存储 监控
检索服务elasticsearch
【8月更文挑战第21天】
41 0
|
4月前
|
存储 缓存 监控
Elasticsearch Filter 缓存加速检索的细节,你知道吗?
【8月更文挑战第15天】在大数据与搜索引擎的广阔天地里,Elasticsearch 凭借其强大的全文搜索能力和可扩展性,成为了众多企业和开发者的首选。而在Elasticsearch的性能优化中,Filter缓存(也称为Filter Cache,自Elasticsearch 7.x版本后更名为Query Cache的一部分)扮演着至关重要的角色。今天,我们就来深入探讨一下Elasticsearch Filter缓存如何加速检索过程,以及在日常工作学习中如何有效利用这一特性。
90 0
|
4月前
|
自然语言处理 Java 关系型数据库
ElasticSearch 实现分词全文检索 - id、ids、prefix、fuzzy、wildcard、range、regexp 查询
ElasticSearch 实现分词全文检索 - id、ids、prefix、fuzzy、wildcard、range、regexp 查询
115 0