spring boot 3使用 elasticsearch 提供搜索建议

业务场景

用户输入内容,快速返回建议,示例效果如下

技术选型

  • spring boot 3
  • elasticsearch server 7.17.4
  • spring data elasticsearch 5.0.1
  • elasticsearch-java-api 8.5.3

pom.xml

xml 复制代码
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
  </dependency>
  <dependency>
     <groupId>org.elasticsearch</groupId>
     <artifactId>elasticsearch</artifactId>
     <version>8.5.3</version>
 </dependency>
        

yml

yaml 复制代码
spring:
  elasticsearch:
    uris: http://127.0.0.1:9200
  data:
    elasticsearch:
      repositories:
        enabled: true

实体类

为了启动时候自己创建相关的index,以及存储搜索内容

java 复制代码
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.CompletionField;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.core.suggest.Completion;

/**
 * 业务搜索建议
 * @author chunyang.leng
 * @date 2023-08-21 14:24
 */
@Document(indexName = "biz_suggest")
public class BizSuggestDocument {

    @Id
    private Long id;

    /**
     * 标题,可以用于纠错,不参与搜索建议
     */
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String name;

    /**
     * 自动补全标题,搜索建议使用的对象
     */
    @CompletionField(analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
    private Completion completionName;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Completion getCompletionName() {
        return completionName;
    }

    public void setCompletionName(Completion completionName) {
        this.completionName = completionName;
    }
}

搜索结果对象

java 复制代码
/**
 * 搜索建议返回对象
 * @author chunyang.leng
 * @date 2023-08-21 19:02
 */
public class SuggestVO {
    /**
     * 数据id
     */
    private Long id;

    /**
     * 内容
     */
    private String text;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

搜索业务层

  • 数据导入时候,因为有数据格式要求,必须使用实体类进行写入
java 复制代码
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.CompletionSuggester;
import co.elastic.clients.elasticsearch.core.search.Suggester;
import co.elastic.clients.elasticsearch.core.search.Suggestion;
import co.elastic.clients.elasticsearch.core.search.TermSuggester;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author chunyang.leng
 * @date 2023-08-18 18:29
 */
@Component
public class SuggestionServiceImpl implements SuggestionService {
    /**
     * 搜索建议 key
     */
    private static final String SUGGEST_TAG = "suggest_query";

    /**
     * 纠错key
     */
    private static final String TERM_TAG = "suggest_team";
    @Autowired
    private ElasticsearchClient elasticsearchClient;

    /**
     * 根据 关键词,返回搜索建议
     *
     * @param match 搜索关键词
     * @return 搜索建议,10条
     */
    @Override
    public List<SuggestVO> suggest(String match) throws IOException {
        SearchRequest completionSuggestSearchRequest = new SearchRequest
            .Builder()
            .suggest(
                new Suggester
                    .Builder()
                    .suggesters(SUGGEST_TAG, builder -> builder.prefix(match)
                        .completion(new CompletionSuggester
                            .Builder()
                            .field("completionName")
                            .size(10)
                            .build()
                        )
                    )
                    .build())
            .build();

        SearchResponse<BizSuggestDocument> completionSuggestSearch = elasticsearchClient.search(completionSuggestSearchRequest, BizSuggestDocument.class);

        Map<String, List<Suggestion<BizSuggestDocument>>> suggest = completionSuggestSearch.suggest();

        List<Suggestion<BizSuggestDocument>> suggestions = suggest.get(SUGGEST_TAG);

        return suggestions
            .parallelStream()
            .flatMap(x -> x.completion()
                .options()
                .stream()
                .map(o -> {
                      // 原始数据对象,如果有需要,可以对其进行操作
                    BizSuggestDocument source = o.source();
                    
                   
                    String text = o.text();
                    String idValue = o.id();
                    Long id = Long.valueOf(idValue);
                    SuggestVO vo = new SuggestVO();
                    vo.setId(id);
                    vo.setText(text);
                    return vo;
                }))
            .collect(Collectors.toList());
    }
}

导入数据

java 复制代码
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.suggest.Completion;

/**
 * @author chunyang.leng
 * @date 2023-08-21 18:09
 */
@SpringBootTest
public class EsTest {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Test
    public void test() {
        BizSuggestDocument document = new BizSuggestDocument();
        document.setId(1L);
        document.setName("飞翔的世界");

        String[] s = "你的世界1.0,我的世界2.0".split(",");
        Completion completion = new Completion(s);
        completion.setWeight(10);
        document.setCompletionName(completion);
        elasticsearchTemplate.save(document);


        BizSuggestDocument document2 = new BizSuggestDocument();
        document2.setId(2L);
        document2.setName("路人甲乙丙");

        String[] s2 = "你的滑板鞋1.0,我的滑板鞋2.0".split(",");
        Completion completion1 = new Completion(s2);
        completion1.setWeight(5);
        document2.setCompletionName(completion1);
        elasticsearchTemplate.save(document2);
    }
}

POSTMAN 测试结果如下


相关推荐
VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue图书管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
利刃大大3 小时前
【SpringBoot】搭建Java部署环境 && 部署项目到Linux服务器
java·服务器·spring boot
椰果子3 小时前
Nacos 2.x.x版本不适用JDK17的处理方式
java·spring boot·后端
骇客野人6 小时前
基于springboot的Java快速定时任务
java·windows·spring boot
05大叔6 小时前
Springboot
java·spring boot·spring
lpfasd1236 小时前
Spring Boot 4.0.1 集成 Spring Boot AI 全攻略
人工智能·spring boot·后端
+VX:Fegn08957 小时前
计算机毕业设计|基于springboot + vue在线教育学习系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·学习·课程设计
CNRio7 小时前
Day 46:Git的高级技巧:使用Git的filter-branch重写历史
大数据·git·elasticsearch
我爱娃哈哈8 小时前
SpringBoot集成:5分钟实现HTML转PDF功能
spring boot·pdf·html
CNRio9 小时前
Day 44:Git的高级技巧:使用Git的reflog找回丢失的提交
大数据·git·elasticsearch