拾忆Elasticsearch03:SpringBoot整合 Elasticsearch

1、 查看文档

1.1 elasticsearch官方文档

我们进入elasticsearch的官方文档,可以看到一个与客户端相关的东西
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第1张图片
进入,可以看到有很多客户端,我们这里使用Java restful风格的客户端。
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第2张图片
发现7.17版本里面只有一个高级客户端

拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第3张图片
查看一个低级版本,里面还有一个低级版本
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第4张图片
可以看到低级客户端里面东西很少
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第5张图片
我们这里使用高级客户端,至于新版本里面为什么抛弃低级客户端,不去探究。展开高级客户端,发现里面有个getting start和一大堆API
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第6张图片
展开getting start

拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第7张图片

查看maven依赖,找到了原生的依赖。
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第8张图片

高级Java REST客户端依赖于以下构件及其传递依赖项:
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第9张图片
初始化阶段,我们创建RestHighLevelClient实例需要一个REST低级客户端构建器;如果是集群,可以构建多个HttpHost实例,使用完毕,调用close()关闭,释放资源。
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第10张图片
更多的内容,感兴趣可以自行查看。

1.2 Spring Data ElasticSearch

Spring Data for Elasticsearch is part of the umbrella Spring Data project which aims to provide a familiar and consistent Spring-based programming model for for new datastores while retaining store-specific features and capabilities. The Spring Data Elasticsearch project provides integration with the Elasticsearch search engine.

Spring Data ElasticSearch是Spring对原生JAVA操作Elasticsearch封装之后的产物。它通过对原生API的封装,使得JAVA程序员可以简单的对Elasticsearch进行操作。

2、SpringBoot环境搭建

2.1 创建项目

我们先创建一个空的maven项目
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第11张图片
然后在这个空项目下创建子模块
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第12张图片

拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第13张图片
勾上你想要的
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第14张图片
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第15张图片

2.2 环境配置

拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第16张图片
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第17张图片
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第18张图片
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第19张图片

2.3 导入依赖

创建模块时,我们勾选了NoSQL的starter data elasticsearch,自动给我们导入了依赖。
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第20张图片

我们进入spring-boot-starter-data-elasticsearch
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第21张图片

进入spring-data-elasticsearch,在这里,我们看到了它导入了elasticsearch的高级客户端依赖,也就是我们前面说的原生依赖
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第22张图片

打开 maven导入的依赖目录,可以看到spring-data-elasticsearch 2.7.2导入的7.17.4client
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第23张图片
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第24张图片

注意,我们前面(就是上一篇)使用的elasticsearch7.6.2,这里我们把它改成7.6.2,保持版本一致。在pom中改成自己想要的版本即可。但修改elasticsearch版本,像我上面2.7.2的Springboot改不了7.6.2的elasticsearch。
查看elasticsearch、springboot、Spring data三者版本对应
https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#preface.requirements
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第25张图片

修改springboot和elasticsearch的版本。
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第26张图片
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第27张图片
修改成功。

我们在这里提前导入fastjson,后续需要。

<dependency>
	<groupId>com.alibabagroupId>
	<artifactId>fastjsonartifactId>
	<version>1.1.41version>
dependency>

完整pom


<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.0modelVersion>
    <groupId>com.goodwingroupId>
    <artifactId>es-apiartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>es-apiname>
    <description>Demo project for Spring Bootdescription>

    <properties>
        <java.version>1.8java.version>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASEspring-boot.version>
        <elasticsearch.version>7.6.2elasticsearch.version>
    properties>

    <dependencies>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-elasticsearchartifactId>
        dependency>

        
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>fastjsonartifactId>
            <version>1.1.41version>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-devtoolsartifactId>
            <scope>runtimescope>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-configuration-processorartifactId>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintagegroupId>
                    <artifactId>junit-vintage-engineartifactId>
                exclusion>
            exclusions>
        dependency>
    dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-dependenciesartifactId>
                <version>${spring-boot.version}version>
                <type>pomtype>
                <scope>importscope>
            dependency>
        dependencies>
    dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-compiler-pluginartifactId>
                <version>3.8.1version>
                <configuration>
                    <source>1.8source>
                    <target>1.8target>
                    <encoding>UTF-8encoding>
                configuration>
            plugin>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
                <version>2.3.7.RELEASEversion>
                <configuration>
                    <mainClass>com.goodwin.EsApiApplicationmainClass>
                configuration>
                <executions>
                    <execution>
                        <id>repackageid>
                        <goals>
                            <goal>repackagegoal>
                        goals>
                    execution>
                executions>
            plugin>
        plugins>
    build>
project>

3、 相关API操作

3.1 创建并编写配置类

RestHighLevelClient在第一节初始化已经见过,我们后续api操作中需要用RestHighLevelClient实例,我们将RestHighLevelClient注入到Spring容器中

拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第28张图片

package com.goodwin.config;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author goodwin
 */
@Configuration
public class EsConfig {
    @Bean
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("127.0.0.1", 9200, "http")
                )
        );
        return client;
    }
}
  @Autowired
  @Qualifier("restHighLevelClient")
  RestHighLevelClient restHighLevelClient;

3.2 索引API操作

3.2.1 创建索引

RestHighLevelClient.indices()提供一个用于访问Indices API的IndicesClient

public final IndicesClient indices() {
	return indicesClient;
}

使用IndicesClient实例,通过下图API可以看到,可以用于创建、删除索引等。
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第29张图片

使用IndicesClientcreate API创建索引。

public CreateIndexResponse create(CreateIndexRequest createIndexRequest,
                                  RequestOptions options) throws IOException {
	return restHighLevelClient.performRequestAndParseEntity(createIndexRequest, IndicesRequestConverters::createIndex, options,
            CreateIndexResponse::fromXContent, emptySet());
}

所以创建索引还需要createIndexRequestRequestOptions 实例。

在这里创建一个people索引。

    @Test
    void testCreateIndex() throws IOException {
        CreateIndexRequest indexRequest = new CreateIndexRequest("people");
        CreateIndexResponse createIndexResponse =
                restHighLevelClient.indices().create(indexRequest, RequestOptions.DEFAULT);
        System.out.println(createIndexResponse.isAcknowledged());   // 查看是否创建成功
        System.out.println(createIndexResponse);                    // 查看返回对象
        restHighLevelClient.close();
    }

输出

true
org.elasticsearch.client.indices.CreateIndexResponse@c4f5c12e

拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第30张图片

3.2.2 判断索引是否存在

根据创建索引的套路,这里直接给出判断索引是否存在的示例,有兴趣的可以自行阅读源码。

    @Test
    void testIndexIsExists() throws IOException {
        boolean exists = restHighLevelClient.indices().exists(
                new GetIndexRequest("people"),
                RequestOptions.DEFAULT);
        System.out.println(exists);
        restHighLevelClient.close();
    }

输出

true

3.2.3 为索引添加结构

    @Test
    void testSetIndex() throws IOException {
        // 创建请求对象
        PutMappingRequest request = new PutMappingRequest("people");
        request.setTimeout(new TimeValue(20, TimeUnit.SECONDS));
        // 设置mapping
        String mappingSource = "{ " +
                "  \"properties\":{ " +
                "    \"id\":{ " +
                "      \"type\":\"integer\", " +
                "      \"store\":true, " +
                "      \"index\":true" +
                "    }," +
                "    \"name\":{ " +
                "      \"type\":\"text\", " +
                "      \"store\":true, " +
                "      \"index\":true," +
                "      \"analyzer\":\"ik_smart\"" +
                "      " +
                "    }," +
                "    \"description\":{" +
                "      \"type\":\"text\", " +
                "      \"store\":true, " +
                "      \"index\":true," +
                "      \"analyzer\":\"ik_smart\"" +
                "    }," +
                "    \"hobby\":{" +
                "      \"type\":\"text\", " +
                "      \"store\":true, " +
                "      \"index\":true," +
                "      \"analyzer\":\"ik_smart\"," +
                "      \"fields\" : {" +
                "          \"keyword\" : {" +
                "            \"type\" : \"text\"" +
                "          }" +
                "        }" +
                "    }" +
                "  }" +
                "}";
        request.source( mappingSource, XContentType.JSON);
        // 发送请求
        AcknowledgedResponse response = restHighLevelClient.indices().putMapping(request,RequestOptions.DEFAULT);
        // 输出返回结果
        System.out.println(response.isAcknowledged());
        // 关闭客户端
        restHighLevelClient.close();
    }

对应这个
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第31张图片
输出

true

拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第32张图片

3.2.4 删除索引

    @Test
    void testDeleteIndex() throws IOException {
        AcknowledgedResponse response = restHighLevelClient.indices().delete(
                new DeleteIndexRequest("people"), 
                RequestOptions.DEFAULT);
        System.out.println(response.isAcknowledged());
        restHighLevelClient.close();
    }

输出

true

3.3 文档API操作

3.3.1 创建一个实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class People {
    private int id;
    private String name;
    private String description;
    private List<String> hobby;
}

3.3.2 文档的新增

下面java代码相当于

PUT /people/_doc/1
{
  "id":1001,
  "name":"邓紫棋",
  "description":"一位创作型歌手,一个天才美女。",
  "hobby":["唱歌","创作"]
}

    @Test
    void testAddDocument() throws IOException {
        // 创建一个People实例
        People people = new People(
                1001,
                "邓紫棋",
                "一位创作型歌手,一个天才美女。",
                Arrays.asList("唱歌", "创作"));
        //实例对应的json字符串
        String jsonString = JSON.toJSONString(people);
        //创建请求
        IndexRequest request = new IndexRequest("people");
        //制定规则 PUT /people/_doc/1
        //设置id
        request.id("1");
        //设置超时
        request.timeout("1s");
        //设置数据源和内容类型
        request.source(jsonString,XContentType.JSON);
        //客户端发送请求,获取响应的结果
        IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);
        //获取建立索引的状态信息
        System.out.println(response.status());
        //查看返回内容
        System.out.println(response.toString());
        restHighLevelClient.close();
    }

输出

CREATED
IndexResponse[index=people,type=_doc,id=1,version=1,result=created,seqNo=0,primaryTerm=1,shards={"total":2,"successful":1,"failed":0}]

3.3.3 查看文档是否存在

    @Test
    void testIsExistDocument() throws IOException {
        GetRequest request = new GetRequest("people", "1");
        //不获取返回的 _source的上下文了
        FetchSourceContext fetchSourceContext = new FetchSourceContext(false);
        //允许设置这个请求的FetchSourceContext,控制是否以及如何返回_source。
        request.fetchSourceContext(fetchSourceContext);
        //显式指定将返回的存储字段。默认情况下,将返回_source字段。
        request.storedFields("_none_");
        boolean exists = restHighLevelClient.exists(request, RequestOptions.DEFAULT);
        System.out.println(exists);
        restHighLevelClient.close();
    }
true

3.3.4 文档的修改

    @Test
    void testUpdateDocument() throws IOException {
        UpdateRequest updateRequest = new UpdateRequest("people","1");
        People people = new People();
        people.setId(1002);
        updateRequest.doc(JSON.toJSONString(people), XContentType.JSON);
        UpdateResponse update = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
        System.out.println(update.status());
        restHighLevelClient.close();
    }
OK

以上相当于,不修改的部分不会丢失。

POST /people/_doc/1/_update
{
  "doc":{
    "id":1002
  }
}

拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第33张图片

3.3.5 文档的删除

    @Test
    void testDeleteDocument() throws IOException {
        DeleteRequest request = new DeleteRequest("people","1");
        request.timeout("1s");
        DeleteResponse response = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
        System.out.println(response.status());
        restHighLevelClient.close();
    }
OK

3.3.6 文档的批量操作

前面文档的新增,使用IndexRequest实例的source方法设置数据源和内容类型,查看源码可以发现在IndexRequest重载了很多source方法。
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第34张图片
但它们最终都走向调用

    public IndexRequest source(BytesReference source, XContentType xContentType) {
        this.source = Objects.requireNonNull(source);
        this.contentType = Objects.requireNonNull(xContentType);
        return this;
    }

可以看到,如果我们企图多次调用source方法来批量添加数据,是不可行的,this.sourcethis.contentType只会指向最后一次设置的数据。修改亦是如此。

查看RestHighLevelClient源码,发现可以使用bulk API执行批量请求。
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第35张图片
上述两个方法都需要我们传入一个BulkRequest对象,在这个类中,重载了很多add方法,它们的参数是XXXRequest,很明显,我们只要批量add上各种Request就可以进行批量操作。
拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第36张图片

下面进行批量添加

    @Test
    void testBulkAddDocument() throws IOException {
        BulkRequest bulkRequest = new BulkRequest("people");
        ArrayList<People> list = new ArrayList<>();
        list.add(new People(1001,
                "邓紫棋",
                "一位创作型歌手,一个天才美女。",
                Arrays.asList("唱歌", "创作")));
        list.add(new People(1002,
                "蔡徐坤",
                "一个穿背带裤的两年半练习生,是一个人气艺人。",
                Arrays.asList("唱","跳","rap","篮球")));
        list.add(new People(1003,
                "小黑子",
                "自诩是ikun,是一类自称是蔡徐坤粉丝的群体,包括俊男美女。",
                Arrays.asList("香精煎鱼","香翅捞饭","油饼","荔枝","美食","卤醋鸡脚")));
        list.add(new People(1004,
                "Gloria",
                "邓紫棋在新专辑《启示录》MV中的虚拟人物,同时也是邓紫棋爸爸给她取得英文名字。",
                Collections.singletonList("未知")));
        for (People people : list) {
            bulkRequest.add(
                    new IndexRequest("people")              //加入一个Request
                    .id(Integer.toString(people.getId()))   //没有设置id 会自定生成一个随机id
                    .source(JSON.toJSONString(people),XContentType.JSON)//设置数据
            );
        }
        BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        System.out.println(bulk.status());
        restHighLevelClient.close();
    }
OK

在这里插入图片描述

3.3.7 文档的搜索

SearchSourceBuilder是一个搜索源构建器,允许轻松构建搜索源,用来设置各种搜索条件。使用SearchRequest中的source(SearchSourceBuilder sourceBuilder)设置搜索请求的源。

SearchSourceBuilder中的一些API

  • SearchSourceBuilder.query(QueryBuilder query)为此请求设置搜索构建器,QueryBuilder 有非常多的实现类XXXQueryBuilder

    拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第37张图片
    拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第38张图片
    拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第39张图片
    这里我们能看到很多在上一篇讲过的,例如bool多条件查询、match模糊匹配、term/terms精确查询等有关的构建器。

  • SearchSourceBuilder.highlighter(HighlightBuilder highlightBuilder)指定高亮构建器

  • SearchSourceBuilder.fetchSource(···)指示响应是否应该包含每个命中的存储的_source
    拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第40张图片

  • SearchSourceBuilder.sort(SortBuilder sort):设置排序
    拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第41张图片

更多方法自行阅读源码。

    @Test
    void testSearchDocument() throws IOException {
        //创建搜索源构建器
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //多条件查询构建器
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        //创建两个模糊匹配构建器
        MatchQueryBuilder matchQueryBuilder1 = new MatchQueryBuilder("name","邓紫棋");
        MatchQueryBuilder matchQueryBuilder2 = new MatchQueryBuilder("description","邓紫棋");
        //将两个MatchQueryBuilder实例丢到boolQueryBuilder中
        boolQueryBuilder.should(matchQueryBuilder1);
        boolQueryBuilder.should(matchQueryBuilder2);

        //设置搜索源构建器的搜索构建器
        searchSourceBuilder.query(boolQueryBuilder);

        //设置高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        //添加字段以高亮显示
        highlightBuilder.field("name");
        highlightBuilder.field("description");
        //设置用于高亮显示的开头和结尾标记。
        highlightBuilder.preTags("");
        highlightBuilder.postTags("");

        //设置搜索源构建器的高亮构建器
        searchSourceBuilder.highlighter(highlightBuilder);

        //设置超时
        searchSourceBuilder.timeout(new TimeValue(2,TimeUnit.SECONDS));
        SearchRequest request = new SearchRequest("people");
        request.source(searchSourceBuilder);

        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);

        //打印执行状态
        System.out.println(response.status());

        //获得结果
        SearchHits hits = response.getHits();

        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsMap());
            //获取高亮
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            //输出高亮
            for (Map.Entry<String, HighlightField> stringHighlightFieldEntry : highlightFields.entrySet()) {
                System.out.println(stringHighlightFieldEntry);
            }
        }
        restHighLevelClient.close();
    }
OK
{name=Gloria, description=邓紫棋在新专辑《启示录》MV中的虚拟人物,同时也是邓紫棋爸爸给她取得英文名字。, id=1004, hobby=[未知]}
description=[description], fragments[[<em>邓紫棋</em>在新专辑《启示录》MV中的虚拟人物,同时也是<em>邓紫棋</em>爸爸给她取得英文名字。]]
{name=邓紫棋, description=一位创作型歌手,一个天才美女。, id=1001, hobby=[唱歌, 创作]}
name=[name], fragments[[<em>邓紫棋</em>]]

以上相当于在kibana执行以下语句

GET /people/_search
{
  "query": {
    "bool": {
        "should": [
          {
            "match": {
              "name": "邓紫棋"
            }
          },
          {
            "match": {
              "description": "邓紫棋"
            }
          }
        ]
    }
  },
  "highlight": {
    "pre_tags": "",
    "post_tags": "",
    "fields": {
      "description": {},
      "name":{}
    }
  }
}

拾忆Elasticsearch03:SpringBoot整合 Elasticsearch_第42张图片

更多复杂搜索请各位自行探究,(¦3[▓▓] 晚安。

你可能感兴趣的:(Elasticsearch,elasticsearch,spring,boot,java,搜索引擎,json)