读书笔记《elasticsearch-blueprints》改善搜索体验
完成搜索后,我们需要改进整个搜索体验。改善搜索体验意味着提供无忧无虑的无缝搜索,并能够在第一次尝试时为用户获得结果。在不同的情况下,这可能意味着不同。在某些情况下,考虑搜索词的同义词可能会更好地帮助用户。在其他情况下,提供在非结构化文本中搜索电子邮件或链接的规定可能对用户有更多帮助。简而言之,即使用户没有提供正确的搜索词,搜索引擎也应该能够猜测用户正在搜索的内容。
在本章中,我们将从用户的角度探讨各种搜索模式,然后进一步了解这些模式是如何产生的。稍后,我们将重点介绍如何借助为 Elasticsearch 开发的内部和外部分析器和插件来解决这些问题。
让我们 在文档的内容字段中搜索邮件地址<[email protected]>
:
顺便说一句,文档 1 和文档 2 与我们的查询匹配,而不仅仅是文档 1。
让我们看看为什么会发生这种情况以及如何发生:
默认情况下,将标准分析器作为默认分析器
标准分析器将
<[email protected]>
分解为 malhotra和 gmail.com标准分析器还会破坏电子邮件 ID
<[email protected]>
进入 buygroceries 和 gmail.com这意味着当我们搜索电子邮件 ID
<[email protected] >
,malhotra 或 gmail.com 都需要匹配才能使文档成为合格的结果
因此,文档 1 和文档 2 都匹配我们的查询,而不仅仅是文档 1。
对于这个问题的 解决方案是使用UAX Email URL tokenizer< id="id264" class="indexterm"> 而不是默认的分词器。此标记器保留电子邮件 ID 和 URL 链接,不会破坏它们。因此我们的搜索工作。
最后,我们需要将它应用到我们的领域:
现在,当标记化发生时,它不会破坏基于 @
的标记。因此,我们以前的条件不会占上风。
让我们考虑 Author
字段中的聚合,以获取每个作者姓名的统计信息:
通过提供 search_type=count
,我们确保我们只收到聚合结果而不是命中,或者更确切地说,是前 10 个结果。
我们得到的响应如下:
在这里,我们看到了意想不到的结果。要了解这里发生了什么,我们需要深入了解 Elasticsearch 的工作原理。 Elasticsearch 建立在名为 Lucene 的强大文本搜索和分析库之上。 Lucene 创建一个反向索引,其中单词/标记 被反向映射到它们出现的文档。
现在,让我们根据这两个文档创建一个反向索引:
聚合发生在这个破碎的标记集中而不是纯文本中,因此,我们的结果被分解成单词而不是确切的文本。
部分示例如下所示:
有了这个,我们的搜索就会好很多。当有人搜索 run
时,所有的文档,无论是包含 running 还是 ran,都将显示为匹配项。
为了实现这一点,我们有两种方法:
让我们看看如何实现算法方法以及它的优缺点。
我们的首选是 snowball 算法。这是一种强大的算法,可以使用算法找到给定单词的词干。这意味着它可以智能地删除尾随字符,例如 ing、ed 等。
让我们看看如何实现这个算法并检查它的一些输出:
现在,让我们看看这个分析器是如何将文本分解为标记的。为此,我们可以使用分析器 API。分析器 API 用于调试目的,可以将索引分析器作为参数。此分析器应用于有效负载文本,并返回分析的令牌,如以下代码所示:
在这里,我们可以看到“running”和“run”这两个词映射到它们的基本形式,即run。现在,让我们看一些复杂的例子。让我们看看 snowball 如何处理 insider
和 inside
文本:
现在,“running”这个词的词干很好,但是insider
的词干看起来很有趣。只要我们在搜索查询中也使用相同的词,这很好。但是,insider
和 inside
映射到同一个词干。虽然 insider
看起来与 inside
相似,但它是一个完全不同的术语,具有不同的含义。因此,算法方法在某些情况下可能会失败。
一个神圣的搜索框 是一个文本输入框,您可以在其中输入您想要搜索的所有约束条件。
例如,如果我想在新闻数据库中搜索标题中包含“印度”一词、内容中包含“职业”一词的新闻,日期为 1990 年至 1992 年,作者是 Shiv Shankar,我应该可以通过以下方式快速搜索:
对于这种搜索,查询字符串查询是我们选择的武器。
它为我们提供了多种搜索选项,可以写成纯文本。这些特性将在下一节中讨论。
您可以通过 field:value
表示法指定特定字段。如果您未指定任何字段,则搜索将在 _all
上进行,并且如果您将该字段称为 default_field
将采用 query_string_query
下的选项。
10岁以上:
"age:[10 TO *]
10 到 15 岁之间的年龄:
" age:[10 TO 15]
年龄不包括 10 岁及以上 10 岁及以下 20 岁:
"age:[10 TO 20]
1990 年到 1992 年之间的日期:
"date:[1990 TO 1992]
如果我们可以映射具有相似发音的单词,例如 forgot 或 forghot,将会提升用户体验。为此,我们可以使用 phonetic 分析器。
语音分析器是一个社区驱动的项目,能够理解具有相似发音的单词。
首先,我们需要 安装语音分析器。您可以在 https://github.com/elastic/elasticsearch 找到代码库-分析-语音。
然后,我们需要从中创建一个分析器:
在这里,我们正在创建一个名为 my_metaphone
的过滤器,并使用它来创建 metaphone 分析器。 有许多可用于语音过滤的编码器,但在这里,我们选择了变音位。
现在,让我们看看变音位分析器是如何工作的。为此,我们使用 _analyze
API 来查看具有相同发音的各种单词的 输出。出于同样的目的,我们选择 aamerika、amerika 和 America 三个词,因为这三个词的发音相同:
我们试试amerika
,如下代码所示:
在这里,我们可以看到这三个词在发音相似的基础上都映射到了同一个标记AMRK
。