有几种方法可以通过Elasticsearch将自动完成功能添加到您的Spring Boot应用程序中:
我们将专注于使用ngrams的自定义分析器。听起来有点复杂,但实际上并非如此。让我们开始吧!
内容列表:
需求用例
我们想要创建一个简单的REST API,以搜索存储在Elasticsearch中的用户列表。将有一个GET端点,我们可以在其中发送有关正在寻找谁的搜索输入。假设我们有兴趣按国家/地区搜索用户。
我们希望我们的搜索支持以下查询:
基本设置:带有Elasticsearch的SpringBoot
首先,我们需要启动Elasticsearch,其次,我们需要使用Spring Boot应用程序来实现搜索。
检查SpringData Elasticsearch版本支持 当前6.8.4是SpringBoot 2.2.x支持的最新Elasticsearch"
启动Spring Boot应用程序
Clone或下载此 git repo(签出分支master-prefix-phrase-match),然后在您喜欢的IDE中打开项目。首次启动应用程序时, 样本数据中的 用户将被添加到Elasticsearch中。
您可以检查使用此命令添加的用户列表:
curl localhost:8080/users
现在让我们搜索。以下是我们使用 词组前缀查询 进行搜索的逻辑核心。
<b>public</b> List<User> search(String keywords) { MatchPhrasePrefixQueryBuilder searchByCountries = QueryBuilders.matchPhrasePrefixQuery(<font>"country"</font><font>, keywords); <b>return</b> <b>this</b>.userRepository.search(searchByCountries); } </font>
短语前缀工作示例:
关键字:“ puerto r”表示“ puerto”是需要在国家名称中输入的确切单词,而“ r”则是“ puerto”之后的任何单词的前缀。这将匹配“puerto”。
让我们尝试以下搜索:
curl localhost:8080/users/search?keywords=bahamas curl localhost:8080/users/search?keywords=baham
太好了,这将返回来自Bahamas的用户。我们的第一个实现了1.和2.需求,但是由于我们使用Elasticsearch的方式以及前缀短语匹配的工作方式,因此其余所有方法都失败了。
我们可以使用通配符搜索来解决此问题,但这将对性能产生影响,我们避免使用Elasticsearch的核心,即它的反向索引。因此,在下一节中,我们将介绍Elasticsearch如何进行索引和搜索,以及如何在Spring Boot应用程序中使用它来进行更灵活的搜索。
Elasticsearch和自定义分析器
分析器 用于添加到Elasticsearch的数据,也可以用于在Elasticsearch中用于查询数据的搜索输入。
分析器分为三个部分:
对于我们的自动完成功能,我们将创建使用 edge_ngram 令牌过滤器的自定义分析器,以便创建与我们的关键字匹配的其他令牌。将数据添加到Elasticsearch(索引时间)时,将使用此分析器。
<font>"autocomplete_filter"</font><font>: { </font><font>"type"</font><font>: </font><font>"edge_ngram"</font><font>, </font><font>"min_gram"</font><font>: 1, </font><font>"max_gram"</font><font>: 20 } </font>
edge_ngram的工作方式示例:
输入令牌:bahamas 输出令牌:[b,ba,bah,baha,baham,bahama,bahamas] 它创建指定了最小和最大长度的前缀。
将自定义分析器与Ngrams一起使用
使用自定义分析器的代码位于 master分支上 。以下是对先前解决方案的必要更改。
分析器配置:
{ <font>"analysis"</font><font>: { </font><font>"filter"</font><font>: { </font><font>"autocomplete_filter"</font><font>: { </font><font>"type"</font><font>: </font><font>"edge_ngram"</font><font>, </font><font>"min_gram"</font><font>: 1, </font><font>"max_gram"</font><font>: 20 } }, </font><font>"analyzer"</font><font>: { </font><font>"autocomplete_search"</font><font>: { </font><font>"type"</font><font>: </font><font>"custom"</font><font>, </font><font>"tokenizer"</font><font>: </font><font>"standard"</font><font>, </font><font>"filter"</font><font>: [ </font><font>"lowercase"</font><font> ] }, </font><font>"autocomplete_index"</font><font>: { </font><font>"type"</font><font>: </font><font>"custom"</font><font>, </font><font>"tokenizer"</font><font>: </font><font>"standard"</font><font>, </font><font>"filter"</font><font>: [ </font><font>"lowercase"</font><font>, </font><font>"autocomplete_filter"</font><font> ] } } } </font>
用户User类,使用带有@Setting和@Field批注的新配置:
@Document(indexName = <font>"users"</font><font>) @Setting(settingPath = </font><font>"es-config/elastic-analyzer.json"</font><font>) @Getter @Setter <b>public</b> <b>class</b> User { @Id <b>private</b> String id; <b>private</b> String firstName; <b>private</b> String lastName; @Field(type = FieldType.Text, analyzer = </font><font>"autocomplete_index"</font><font>, searchAnalyzer = </font><font>"autocomplete_search"</font><font>) <b>private</b> String country; } </font>
修改搜索使用查询匹配而不是前缀匹配:
<b>public</b> List<User> search(String keywords) { MatchQueryBuilder searchByCountries = QueryBuilders.matchQuery(<font>"country"</font><font>, keywords); <b>return</b> <b>this</b>.userRepository.search(searchByCountries); } </font>
匹配查询工作方式的一个示例:
关键字:“ puerto baham” 它将查找名称中带有“ puerto”或“ baham”的国家,因此它将返回恰好想要的来自Puerto Rico 和 Bahamas的用户。
从Elasticsearch中删除旧索引:
curl -X DELETE localhost:9200/users
现在,我们可以启动Spring Boot应用程序并测试我们的新搜索:
curl localhost:8080/users/search?keywords=trin%20and%20toba
太好了,现在返回了来自Trinidad 和Tobago的用户。
多个国家/地区的另一个示例:
curl localhost:8080/users/search?keywords=bel%20bahamas
它返回 Belize和Bahamas的用户。这样,我们满足了所有用例要求。
结论
仅用几行代码,我们就使用Elasticsearch Spring Data向Spring Boot应用程序添加了一个很酷的自动完成功能。自己尝试一下,因为该项目可以作为您进行测试和添加其他有趣功能的游乐场。