弹性搜索的模糊查询是许多情况下的强大工具。用户名搜索,拼写错误和其他时髦问题通常可以通过这种非常规查询来解决。在本文中,我们澄清了模糊搜索有时令人困惑的选项,以及潜入Lucene的FuzzyQuery的内部构件。
介绍
搜索自然语言本质上是不精确的。由于电脑不能理解自然语言,所以搜索方法有很多,每一种都有自己的优点和缺点。Lucene是Elasticsearch的技术,是由许多文本处理工具组成的瑞士军刀。其中的每个工具都是启发式的,代替真实语言理解的算法快捷方式。其中一些工具,如Snowball干扰器和Metaphone语音分析仪,都非常复杂。这些工具分别模仿语言理解的语法和语音方面。其他工具是非常基本的,像前缀查询类型,它只是匹配单词的起始字母。模糊查询位于这个工具箱的中间位置,在复杂性方面; 他们找到最多需要一定数量的字符修改的字词,称为“编辑”,以匹配查询。例如,对于'ax'的模糊搜索将匹配单词'ax',因为只需要删除一个删除'e'即可匹配这两个单词。
一个简单的模糊匹配
模糊查询最容易通过match
查询类型的其他参数来执行,如本段下面的示例所示。在这个例子中,最后一个请求,搜索“vaacuum”,其中有一个额外的A,应该还是提起“真空”产品。该fuzziness
参数指定结果与最大编辑距离为2匹配。应该注意的是,fuzziness
只能使用值1和2,这意味着查询和文档中的术语之间最多可以进行2次编辑。更大的差异要高效计算,而不是由Lucene处理。官方文件仍然指的是将模糊性设置为浮动值,如0.5,但这些值实际上已被弃用,更难理解。
# Create the index PUT /fuzzy_products # Create the product mapping PUT /fuzzy_products/product/_mapping { "product": { "properties": { "name": { "type": "string", "analyzer": "simple" } } } } # Upload some documents PUT /fuzzy_products/product/1 {"name": "Vacuum Cleaner"} PUT /fuzzy_products/product/2 {"name": "Turkey Baster"} # Perform a fuzzy search! POST /fuzzy_products/product/_search { "query": { "match": { "name": { "query": "Vacuummm", "fuzziness": 2, "prefix_length": 1 } } } }
确定编辑距离
模糊查询用于确定匹配的度量是Damerau-Levenshtein距离公式。简单来说,两个文本之间的Damerau-Levenshtein距离是使一个字符串与另一个字符串匹配所需的插入,删除,替换和转换的数量。例如,由于需要单次删除,“ax”和“ax”之间的列文斯特距离为1。
Damerau-Levenshtein距离公式是经典Levenshtein距离公式的修改,通过添加换位作为有效操作进行更改。两个公式都是支持的,Damerau-Levenshtein是默认的,经典的Levenshtein可以通过设置来选择transpositions
在查询中为false。在比较字符串“aex”和“ax”的情况下,可以看到转置的效用。当使用经典Levenshtein距离公式时,“aex”不是一个,而是两次编辑; 必须删除'e',之后将新的'e'插入适当的位置,而在Damerau-Levenshtein,一个单一的操作即可交换'e'和'x'就足够了。使用经典Levenshtein来推断这一点,这意味着“aex”与“传真”一样远离“斧头”; 一个例子表明,为什么Damerau-Levenshtein在大多数情况下使得更直观的意义。
特别是在处理模糊搜索时,至关重要的是要理解,在弹性搜索文本中,首先通过分析器进行搜索。当数据索引时,它被处理成所谓的“术语”,即数据库中的实际可搜索单元。分析的术语(从底部向上弹性搜索中涵盖的术语是什么),而不是搜索的实际存储的文档。这意味着当执行模糊查询时,作为分析的结果,可以将查询文本与未预料的术语值进行比较,导致有时混乱的结果。这也意味着如果同义词在同义词可能匹配的字段上启用,即使该文字在源文本中根本不显示。例如,如果一个人在一个ngram分析字段上使用模糊查询,结果可能会是奇怪的,因为ngram将单词分解成许多小写字母组合,其中许多只是一个编辑或两个,尽管实际的单词涉及的是相当不同的。这也意味着,如果使用一个雪球分析仪,一个模糊的搜索“跑步”将被阻止“跑”,但是不会匹配拼写错误的词“跑步”,这就是“跑步”,因为“跑”距离'runa'超过2个编辑。这可能会引起相当多的混乱,因此,通常只有使用它才有意义simple
分析器用于与模糊查询一起使用的文本,也可能会禁用同义词。为了弄清楚这一点,下面可以看到示出针对雪球分析文档运行的模糊查询的图。
使用雪球分析仪进行模糊查询
不同类型的模糊搜索
弹性搜索支持多种类型的模糊搜索,差异可能令人困惑。以下列表试图消除这些不同类型的歧义。
match
query +fuzziness
选项:将fuzziness
参数添加到match
查询会将纯匹配查询转换为模糊的查询。在执行搜索之前分析查询文本。fuzzy
query:弹性fuzzy
搜索查询类型通常应该避免。行为很像term
查询。难道不是先分析查询文本。fuzzy_like_this
/fuzzy_like_this_field
:一个more_like_this
查询,但支持模糊性,并且具有更好地处理模糊匹配结果的特征的调优评分算法。suggesters
: Suggesters不是一个实际的查询类型,而是一种独立的操作类型(内部构建在模糊查询之上),可以与查询一起运行,也可以独立运行。Suggesters是伟大的'你的意思'风格的功能。
一个match
与查询fuzziness
参数集也许是最通用的模糊查询。该fuzzy
查询类型支持完全相同的行为,但它不允许任何分析查询文本。另外,fuzzy
查询类型是查询功能的一个子集,match
使得它比有用的更混乱。
的fuzzy_like_this
,或FLT,查询是用于基于一大块源文本可能包含错误拼写或通过编辑距离隔开其它不准确的建议是有用的。有此类别中的两个不同的查询fuzzy_like_this
和fuzzy_like_this_field
,这既提供相同的功能,后者查询简化其中仅使用单个场的情况下的语法。这些查询采用一个参数,like_text
由一大块文本组成,说出一篇文章的正文,并尝试查找文档“像”一个。检查文章中的文本,并根据查询条件的频率对查询项进行加权like_text
具有特殊的调整(禁用协调因素,基于源文本的IDF),用于组合源文本中的各种术语。FLT查询对于语料库包含大量拼写错误的情况最有效,否则标准more_like_this
查询将具有更好的性能。更多详细信息,请参见Fuzzy更多相关的官方文档。
在用户输入“New Yrok”进行搜索,打算输入“New York”的情况下,Sugges是非常棒的。应用程序可以在UI中提出一个“你的意思”框,建议可能的更正。请注意,针对预先提前搜索的具体情况,完成API会提供更好的性能,因为提前搜索的延迟敏感性。有关suggesters的更多信息,请参见search suggesters
页面。
绩效注意事项
即使Lucene的Levenshtein距离实现是最先进的,而且速度相当快,仍然比一个简单的match
查询慢得多。查询的运行时随索引中唯一项的数量而增长。也就是说,当执行模糊搜索时,主要标准不是将返回多少个文档,而是在整个集群中搜索的字段有多少个独特的术语。如果有100个文档,每个单独的10,000个单词,搜索该索引将比搜索10,000个文档的搜索速度慢,搜索的字段只有100个唯一的单词。
这种缓慢的主要原因是,标准匹配查询可以快速检查术语索引,Lucene使用的内部数据结构进行匹配,并使用二进制搜索快速查找文档。即使对于大型字典,这个过程也是快速的,因为二进制搜索量表很好。另一方面,模糊查询使用涉及必须处理大量术语的DFA的更先进的算法。处理模糊搜索所需的大量术语总是比简单的二进制搜索慢。例如,在英语维基百科数据集上运行模糊搜索对于给定一个min_similarity
2 的术语“历史”需要大约320ms ,而match
对同一术语的简单搜索仅在35ms内运行,具有一个数量级的差异。给了一个min_similarity
的1,搜索时间只有150ms。应该注意的是,这些测试没有以统计学的方式进行,这些时间可能会受到个别应用特定因素的显着影响。维基百科的数据集具有比许多常见用例更多的术语。
通过要求匹配与查询具有完全匹配的前缀匹配,可以显着提高性能。这大大缩短了搜索空间,牺牲了找不到拼写错误的单词。前缀长度越长,加速速度越快。指定一个prefix_length
将上述320ms查询切换到仅104ms。增加这个数字进一步增加速度。一般来说,建议对于具有大量术语或性能的数据集需要一个前缀,通常在100s的毫秒内是差的。
max_expansions
定义模糊查询在停止搜索之前将匹配的最大项数量的设置也可以对模糊查询的性能产生显着影响。减少查询条款会产生负面影响,但是由于查询的提前终止,可能无法找到一些有效的结果。重要的是要了解max_expansions
查询限制在分片级别上工作,这意味着即使设置为1,多个术语可能匹配,所有这些都来自不同的分片。这种行为可能会使它看起来好像max_expansions
没有效果,所以要注意返回的唯一术语的计数不是确定是否max_expansions
正常工作的有效方式。
模糊匹配的替代方法
模糊匹配并不总是工作的正确工具,通常可以通过其他技术找到不精确的匹配。该语音分析插件包含近似匹配,比如一些有趣的工具音位分析仪,它发现,声音相似的其他单词。举例来说,如果所需要的是让喜欢肯定的话run
,并ran
都被视为等同,智能分析仪就像一个雪球仪是优选的。或者,用于检查拼写错误,N-gram分析,如本简短教程中所述在查询时可以运行得相当快一些,具体取决于数据集。然而,N-gram的成本来自于额外的存储/内存使用,稍微更多的索引时间处理以及良好的匹配后的长尾误差。
更多阅读
- 为了更深入地了解“弹性搜索”中模糊查询的性能,Lucene核心贡献者麦克·麦坎德(Mike McCandless)撰写了一篇关于该主题的迷人博客文章。还有一个视频,Lucene和Solr的有限状态自动机,由Dawid Weiss发表的一篇演示文稿,涵盖了莱文斯(Lucene)的Levenshtein和其他自动机。
- 如果你想了解更多关于Levenshtein自动机,尼克·约翰逊有一个伟大的职位Damn酷算法:Levenshtein自动机。