基于SpringBoot整合Elasticsearch实现搜索补全功能

一、概述

想必大家在生活中用过或者体验过这样一种功能,就是搜索智能提示,像百度、淘宝、京东等在搜索内容时,都是有这一功能。今天就是来给大家讲述一下如何简单快速的基于SpringBoot整合ES搜索补全功能~

二、前提

由于SpringBoot和Elasticsearch的版本对应有着严格的要求,故将两者的版本贴一下:

  1. SpringBoot:2.3.1
  2. Elasticsearch: 7.6.2

三、实现过程

如果事先有了解过的同学肯定知道,在SpringBoot容器启动时,会默认初始化标有 @Document 注解的类,若ES中未创建索引,则会以 @Document 中的 indexName 为索引名创建索引,若ES中已存在该索引,则会忽略。在这里先贴一下ES实体类

@Data
@Document(indexName = "es_test", type = "_doc", shards = 1, replicas = 0)
@NoArgsConstructor
@AllArgsConstructor
public class EsTest{
    
    @Id
    @Field(type = FieldType.Keyword)
    private String id;
    
    @Field(analyzer = "standard", type = FieldType.Text)
    private String name;

    @Field(type = FieldType.Integer)
    private Integer age;

    @CompletionField(analyzer="ik_smart",searchAnalyzer="ik_smart", maxInputLength = 100)
    private Completion suggest;

    public EsTest(String id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    
}

接着就是进行测试咯,这里我是使用的SpringBoot测试类进行测试
首先就是得先将数据插入ES中,这里我写了个EsTestRepository继承了ElasticsearchRepository,可以很方便的调用一些API(具体有哪些API就不在这赘述咯~)

/**
 * @author Brave
 * @version V1.0
 * @date 2020/11/16
 */
public interface EsTestRepository extends ElasticsearchRepository<Student, String> {
}

接着就是编写测试类,其中test01方法呢,就是将数据插入至ES中,来方便后面实现搜索补全功能

/**
 * @author Brave
 * @version V1.0
 * @date 2021/3/12
 */
@RunWith(SpringRunner.class)
@SpringBootTest
class SearchTestApplication {

    @Autowired
    private EsTestRepository esTestRepository;
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;
    @Autowired
    private ElasticsearchOperations elasticsearchOperations;

     @Test
    void test01(){
        List<EsTest> esTests = Lists.newArrayList();

        EsTest esTest01 = new EsTest("1","中华人民共和国",18);
        List<String> suggestList =  new ArrayList<>();
        suggestList.add("中华人民共和国");
        esTest01.setSuggest(new Completion(suggestList.toArray(new String[suggestList.size()])));
        esTests.add(esTest01);

        EsTest esTest02 = new EsTest("2","中国人民大会堂",19);
        List<String> suggestList01 =  new ArrayList<>();
        suggestList01.add("中国人民大会堂");
        esTest02.setSuggest(new Completion(suggestList01.toArray(new String[suggestList01.size()])));
        esTests.add(esTest02);

        EsTest esTest03 = new EsTest("3","中国人民一家亲",20);
        List<String> suggestList02 =  new ArrayList<>();
        suggestList02.add("中国人民一家亲");
        esTest03.setSuggest(new Completion(suggestList02.toArray(new String[suggestList02.size()])));
        esTests.add(esTest03);

        EsTest esTest04 = new EsTest("4","中国南波万",21);
        List<String> suggestList03 =  new ArrayList<>();
        suggestList03.add("中国南波万");
        esTest04.setSuggest(new Completion(suggestList03.toArray(new String[suggestList03.size()])));
        esTests.add(esTest04);

        esTestRepository.saveAll(esTests);
    }
}

重头戏来咯!!

    @Test
    void test02(){
        // 使用suggest进行标题联想
        CompletionSuggestionBuilder suggest = SuggestBuilders.completionSuggestion("suggest")
                // 关键字(参数传此)
                .prefix(keyword)
                // 重复过滤
                .skipDuplicates(true)
                // 匹配数量
                .size(10);
        SuggestBuilder suggestBuilder = new SuggestBuilder();
        suggestBuilder.addSuggestion("my-suggest",suggest);

        IndexCoordinates indexCoordinates = elasticsearchOperations.getIndexCoordinatesFor(EsTest.class);

        // 查询
        SearchResponse goodsNameSuggestResp = elasticsearchRestTemplate.suggest(suggestBuilder, indexCoordinates);
        Suggest.Suggestion<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>> goodsNameSuggest = goodsNameSuggestResp
                .getSuggest().getSuggestion("my-suggest");

        // 处理返回
        List<String> suggests = goodsNameSuggest.getEntries().stream().map(x -> x.getOptions().stream().map(y->y.getText().toString()).collect(Collectors.toList())).findFirst().get();
        // 输出内容
        for (String suggest : suggests) {
            System.out.println("suggest = " + suggest);
        }

上面test02()这个方法就是实现搜索补全的代码啦!

四、结尾

如此高大上的功能就这样实现咯,当然其中也有许多可以优化的地方,例如为ES上安装ik分词器以及拼音分词器,这样子补全功能又会更加人性化!有兴趣的小伙伴们快去试试吧!若有啥不足的地方也欢迎大家点评我将热情回复😉

posted @ 2021-03-12 17:25  天青色等烟雨~  阅读(1841)  评论(0)    收藏  举报