转载

使用Elasticsearch实现Spring Boot的自动完成功能 -Milos Biljanovic

有几种方法可以通过Elasticsearch将自动完成功能添加到您的Spring Boot应用程序中:

  1. 使用通配符搜索
  2. 将自定义分析器与ngrams一起使用
  3. Elasticsearch完成建议器

我们将专注于使用ngrams的自定义分析器。听起来有点复杂,但实际上并非如此。让我们开始吧!

内容列表:

  • 需求用例
  • 使用SpringData与Elasticsearch的基本设置SpringBoot
  • Elasticsearch和自定义分析器
  • 将自定义分析器与Ngrams一起使用
  • 结论

需求用例

我们想要创建一个简单的REST API,以搜索存储在Elasticsearch中的用户列表。将有一个GET端点,我们可以在其中发送有关正在寻找谁的搜索输入。假设我们有兴趣按国家/地区搜索用户。

我们希望我们的搜索支持以下查询:

  1. 完整的单词:Bahamas/bahamas寻找来自Bahamas的用户。
  2. 分词:baham,bah从Bahamas寻找用户。
  3. 多个完整的单词:bahamas belize从Bahamas或belize寻找用户。
  4. 多个不完整词:baham beliz从Bahamas或belize寻找用户。
  5. 部分和完整单词的混合单词:trin和toba从Trinidad 和Tobago寻找用户。

基本设置:带有Elasticsearch的SpringBoot

首先,我们需要启动Elasticsearch,其次,我们需要使用Spring Boot应用程序来实现搜索。

检查SpringData Elasticsearch版本支持 当前6.8.4是SpringBoot 2.2.x支持的最新Elasticsearch"

  • 下载Elasticsearch(6.8.4)
  • 运行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中用于查询数据的搜索输入。

分析器分为三个部分:

  1. 字符过滤器:我们可以剥离,删除或更改输入数据。基本示例是使用 html_strip 过滤器,该过滤器将删除html标签。
  2. 分词;我们可以打破输入数据的简单标记。默认情况下,使用 标准标记 器。示例:输入数据:“fox in a forest”令牌:[fox,in,a,forest]
  3. 令牌过滤器:我们可以添加,修改或删除上一步中拥有的令牌。基本示例是 小写 令牌过滤器,它将所有令牌都转换为小写。

对于我们的自动完成功能,我们将创建使用 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应用程序添加了一个很酷的自动完成功能。自己尝试一下,因为该项目可以作为您进行测试和添加其他有趣功能的游乐场。

原文  https://www.jdon.com/53689
正文到此结束
Loading...