SpringBoot集成ES

SpringBoot集成ES

版权申明:本文为原创文章,转载请注明原文出处

原文链接:https://blog.it-follower.com/posts/52687060.html

软件版本信息

  • SpringBoot:2.3.0.RELEASE
  • elasticsearch:7.6.2
  • ik分词器:7.6.2

注意:ik分词器的版本必须和ES版本保持一致,否则会启动报错的。

创建Spring Boot项目

利用IDEA创建Spring Boot项目,选择如下三个依赖Lombok(可选)、Web、ES

或者也可以用手动添加pom依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.itf.demo</groupId>
<artifactId>spring-boot-demo-es</artifactId>
<version>1.0.0</version>
<name>spring-boot-demo-es</name>
<description>Spring Boot 集成ES</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

指定ES集群

Elasticsearch 7中TransportClient被标记为了过时,并且未来就在Elasticsearch 8中移除,官网强烈推荐我们使用High Level REST Client来连接到ES集群(参考官网文档:官网说明)。所以我们不推荐使用过时的spring.data.elasticsearch.cluster-name来指定ES集群,而是使用Java Bean的方式来创建一个连接ES的客户端。创建一个EsConfig类,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.itf.demo.es;

import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.RestClients;

/**
* ES rest客户端配置
*
* @author ye17186
* @date 2020-05-26
*/
@Configuration
public class EsConfig {

@Bean
public RestHighLevelClient client() {
// ES默认端口为9200
ClientConfiguration clientConfig = ClientConfiguration.builder().connectedTo("127.0.0.1:9200").build();
return RestClients.create(clientConfig).rest();
}
}

到此,我们的Spring Boot就完成了ES的集成。

ES相关操作功能

  1. 创建一个EsDemoController,提供创建索引、新建文档、检索文档三个功能。内容如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    package com.itf.demo.es;

    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import org.elasticsearch.action.index.IndexRequest;
    import org.elasticsearch.action.index.IndexResponse;
    import org.elasticsearch.action.search.SearchRequest;
    import org.elasticsearch.action.search.SearchResponse;
    import org.elasticsearch.client.RequestOptions;
    import org.elasticsearch.client.RestHighLevelClient;
    import org.elasticsearch.client.indices.CreateIndexRequest;
    import org.elasticsearch.client.indices.CreateIndexResponse;
    import org.elasticsearch.common.settings.Settings;
    import org.elasticsearch.index.query.MultiMatchQueryBuilder;
    import org.elasticsearch.search.builder.SearchSourceBuilder;
    import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.web.bind.annotation.PutMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;

    /**
    * @author ye17186
    * @date 2020-05-27
    */
    @RestController
    @RequestMapping("/es")
    public class EsDemoController {


    /**
    * ik分词器配置文件
    */
    private static final String IK_SETTINGS_FILE = "es-index-settings-ik.yml";

    private static final String DOC_FIELD_TITLE = "title";
    private static final String DOC_FIELD_CONTENT = "content";
    private static final String DOC_FIELD_DESCRIPTION = "description";

    private static final String HIGHLIGHT_PRE_TAG = "<span class=\"highlight\">";
    private static final String HIGHLIGHT_POST_TAG = "</span>";

    @Autowired
    RestHighLevelClient client;

    /**
    * 创建索引
    *
    * @param addIndexRequest 请求体
    * @return 创建结果
    * @throws IOException es异常
    */
    @PutMapping("/index")
    public CreateIndexResponse index(@RequestBody AddIndexRequest addIndexRequest) throws IOException {

    CreateIndexRequest request = new CreateIndexRequest(addIndexRequest.getIndex());
    if (addIndexRequest.getIk()) {
    Settings settings = Settings.builder().loadFromStream(IK_SETTINGS_FILE, new ClassPathResource(IK_SETTINGS_FILE).getInputStream(), true).build();
    request.settings(settings);
    }
    return client.indices().create(request, RequestOptions.DEFAULT);
    }

    /**
    * 新建一个文档
    *
    * @param addRequest 请求体
    * @return 新建结果
    * @throws IOException es异常
    */
    @PutMapping("/doc")
    public AddDocResponse doc(@RequestBody AddDocRequest addRequest) throws IOException {

    Map<String, String> doc = new HashMap<>();
    doc.put(DOC_FIELD_TITLE, addRequest.getDoc().getTitle());
    doc.put(DOC_FIELD_CONTENT, addRequest.getDoc().getContent());
    doc.put(DOC_FIELD_DESCRIPTION, addRequest.getDoc().getDescription());
    IndexRequest request = new IndexRequest().index(addRequest.getIndex()).source(doc);
    IndexResponse result = client.index(request, RequestOptions.DEFAULT);

    AddDocResponse response = new AddDocResponse();
    response.setId(result.getId());
    response.setIndex(result.getIndex());
    return response;
    }

    /**
    * 搜索文档
    *
    * @param searchDocRequest 搜索对象
    * @return 文档列表
    * @throws IOException es异常
    */
    @RequestMapping("/search")
    public List<DemoDoc> search(SearchDocRequest searchDocRequest) throws IOException {

    SearchSourceBuilder builder = new SearchSourceBuilder();

    // 1、构造查询条件(只搜索标题和正文内容,不搜索文档描述)
    MultiMatchQueryBuilder qBuilder = new MultiMatchQueryBuilder(searchDocRequest.getKey(), DOC_FIELD_TITLE, DOC_FIELD_CONTENT, DOC_FIELD_DESCRIPTION);
    builder.query(qBuilder);

    // 构建高亮效果
    if (Boolean.TRUE.equals(searchDocRequest.isHighlight())) {
    HighlightBuilder hBuilder = new HighlightBuilder().field(DOC_FIELD_TITLE).field(DOC_FIELD_CONTENT);
    hBuilder.preTags(HIGHLIGHT_PRE_TAG);
    hBuilder.postTags(HIGHLIGHT_POST_TAG);
    builder.highlighter(hBuilder);
    }

    SearchRequest request = new SearchRequest();
    request.indices(searchDocRequest.getIndex());
    request.source(builder);

    SearchResponse esResponse = client.search(request, RequestOptions.DEFAULT);

    List<DemoDoc> list = new ArrayList<>();
    esResponse.getHits().forEach(item -> {
    DemoDoc doc = new DemoDoc();
    Map<String, Object> docObj = item.getSourceAsMap();
    doc.setEsId(item.getId());
    doc.setDescription((String) docObj.get(DOC_FIELD_DESCRIPTION));

    // 处理高亮结果
    if (Boolean.TRUE.equals(searchDocRequest.isHighlight())) {
    item.getHighlightFields().forEach((k, v) -> {
    String text = v.fragments()[0].toString();
    if (DOC_FIELD_TITLE.equals(k)) {
    doc.setTitle(text);
    } else if (DOC_FIELD_CONTENT.equals(k)) {
    doc.setContent(text);
    }
    });
    } else {
    doc.setTitle((String) docObj.get(DOC_FIELD_TITLE));
    doc.setContent((String) docObj.get(DOC_FIELD_CONTENT));
    }

    list.add(doc);
    });
    return list;
    }
    }

    里面有一些实体类,我们贴出来:

    • 创建索引请求:AddIndexRequest

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      package com.itf.demo.es;

      import java.io.Serializable;
      import lombok.Data;

      /**
      * @author ye17186
      * @date 2020-05-26
      */
      @Data
      public class AddIndexRequest implements Serializable {

      private static final long serialVersionUID = -1302118006477723757L;
      /**
      * 索引名
      */
      private String index;

      /**
      * 是否使用ik分词
      */
      private Boolean ik;
      }
    • 创建文档请求:AddDocRequest

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      package com.itf.demo.es;

      import java.io.Serializable;
      import lombok.Data;

      /**
      * @author ye17186
      * @date 2020-05-26
      */
      @Data
      public class AddDocRequest implements Serializable {

      private static final long serialVersionUID = 962783059289210959L;
      /**
      * es索引
      */
      private String index;

      /**
      * 文档对象
      */
      private DemoDoc doc;

      }
    • 文档对象:DemoDoc

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      package com.itf.demo.es;

      import java.io.Serializable;
      import lombok.Data;

      /**
      * @author ye17186
      * @date 2020-05-27
      */
      @Data
      public class DemoDoc implements Serializable {

      private static final long serialVersionUID = -4405978680214369148L;

      private String esId;
      /**
      * 文档标题
      */
      private String title;

      /**
      * 文档内容
      */
      private String content;

      /**
      * 文档描述
      */
      private String description;

      }
    • 创建文档响应:AddDocResponse

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      package com.itf.demo.es;

      import java.io.Serializable;
      import lombok.Data;

      /**
      * @author ye17186
      * @date 2020-05-26
      */
      @Data
      public class AddDocResponse implements Serializable {

      private static final long serialVersionUID = 190213968835835783L;
      /**
      * es索引
      */
      private String index;

      /**
      * 文档ID
      */
      private String id;
      }
    • 检索文档请求:SearchDocRequest

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      package com.itf.demo.es;

      import java.io.Serializable;
      import lombok.Data;

      /**
      * @author ye17186
      * @date 2020-05-26
      */
      @Data
      public class SearchDocRequest implements Serializable {

      private static final long serialVersionUID = 3713476005328602810L;
      /**
      * es索引
      */
      private String index;

      /**
      * 搜索关键字
      */
      private String key;

      /**
      * 是否高亮
      */
      private boolean highlight;

      }
    • 检索文档响应:SearchDocResponse

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      package com.itf.demo.es;

      import java.io.Serializable;
      import java.util.List;
      import lombok.Data;

      /**
      * @author ye17186
      * @date 2020-05-26
      */
      @Data
      public class SearchDocResponse implements Serializable {

      private static final long serialVersionUID = -2746189513729052108L;
      /**
      * es索引
      */
      private String index;

      /**
      * 搜索关键字
      */
      private String key;

      /**
      * 匹配到的文档对象
      */
      private List<DemoDoc> docs;

      }

验证

启动该Spring Boot项目,通过Postman等工具访问对应接口。

评论