2

SpringBoot 使用JestClient操作Elasticsearch

 4 years ago
source link: https://www.dalaoyang.cn/article/118
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

1.Jest介绍

zuaiyqi.png!web

操作Elasticsearch的客户端有很多,SpringBoot也提供了方式去操作,这里介绍另外一种方式去使用Elasticsearch — JestClient

JestClient是一款基于HTTP方式操作的Elasticsearch的客户端,支持同步和异步操作,同时也可以结合ElasticSearch的依赖进行操作Elasticsearch。

支持多个版本的Elasticsearch,如下:

Jest Version Elasticsearch Version >= 6.0.0 6 >= 5.0.0 5 >= 2.0.0 2 0.1.0 - 1.0.0 1 <= 0.0.6 < 1

更多信息可以查看github,地址是: https://github.com/searchbox-io/Jest

2.SpringBoot整合JestClient

接下来介绍如何在SpringBoot中使用JestClient操作Elasticsearch。

2.1 前置工作

首先启动Elasticsearch,我这里是在本地启动的Elasticsearch,版本是6.8.2,为了方便查看数据,这里使用Elasticsearch-Head插件,如下图所示。

eIVvUn7.png!web

2.2 添加Jest依赖

创建项目,在pom文件中加入Jest依赖(这里根据上面版本对应添加依赖),这里额外添加量了elasticsearch和lombok为了方便操作,如下:

<?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>
    <groupId>com.dalaoyang</groupId>
    <artifactId>springboot_jestclient</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot_jestclient</name>
    <description>springboot_jestclient</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.2.6.RELEASE</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </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>

        <dependency>
            <groupId>io.searchbox</groupId>
            <artifactId>jest</artifactId>
            <version>6.3.1</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.10</version>
        </dependency>

        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>6.8.2</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.2.6.RELEASE</version>
            </plugin>
        </plugins>
    </build>

</project>

2.3 配置文件

在配置文件中添加elasticsearch相关配置,其中uris配置Elasticsearch的HTTP端口,如本文添加的配置:

spring.application.name=springboot_jestclient
# 应用服务web访问端口
server.port=8888

spring.elasticsearch.rest.uris=http://localhost:9200
spring.elasticsearch.jest.username=elastic
spring.elasticsearch.jest.password=elastic

到这里其实已经整合完成了,是不是非常简单?

3.Elasticsearch基本操作

接下介绍如何操作Elasticsearch,这里分别介绍如下几部分内容:

  • 索引文档
  • 索引类操作
  • 文档类操作
  • 查询操作

3.1 文档实体

这里创建一个Book文档做为示例,其中@JestId为文档id,即Elasticsearch中的_id字段,本文BookDocument内容如下:

package com.dalaoyang.document;

import io.searchbox.annotations.JestId;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class BookDocument {

    @JestId
    private String id;
    private String bookName;
    private String bookAuthor;
    private Integer pages;
    private String desc;
}

为了方便操作,这里创建了一个request对象进行操作,如下:

package com.dalaoyang.model;

import com.dalaoyang.document.BookDocument;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class BookRequest {

    //删除文档用
    private String id;
    //查询用
    private String keyword;
    private String indexName;
    private String typeName;
    //新增文档用
    private BookDocument body;
}

在使用相关操作时,其实都是通过io.searchbox.client.JestClient#execute来进行操作(需要注意,这里没有对JestClient进行配置,只是使用的默认的配置),将对应动作当做参数传入,接下来介绍几个常用的动作。

3.2 索引类操作

结合MySQL来看的话,索引可以理解为一个数据库,索引相关的操作可能不是很多,这里介绍相对比较常用的是创建索引和删除索引,如下:

3.2.1 创建索引

CreateIndex createIndex = new CreateIndex.Builder(indexName).build();

3.2.2 删除索引

DeleteIndex deleteIndex = new DeleteIndex.Builder(indexName).build();

通过上面两个操作可以看到,都是通过使用对应的Index实体来操作对应实体,当然还有一些不是很常用的,如果有需要可以查看相关文档进行使用,这里不一一介绍了,完整s示例内容如下:

package com.dalaoyang.web;

import io.searchbox.client.JestClient;
import io.searchbox.client.JestResult;
import io.searchbox.indices.CreateIndex;
import io.searchbox.indices.DeleteIndex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IndexController {

    @Autowired
    private JestClient jestClient;

    @GetMapping("createIndex")
    public String createIndex(String indexName) throws Exception{
        CreateIndex createIndex = new CreateIndex.Builder(indexName).build();
        JestResult result = jestClient.execute(createIndex);
        return result.getJsonString();
    }

    @GetMapping("deleteIndex")
    public String deleteIndex(String indexName) throws Exception{
        DeleteIndex deleteIndex = new DeleteIndex.Builder(indexName).build();
        JestResult result = jestClient.execute(deleteIndex);
        return result.getJsonString();
    }
}

3.3 文档类操作

文档相当于MySQL中的行记录,也就是说一条数据,由于新增和修改在同一个方法内,所以这里也是对新增(和修改)和删除方法进行介绍,如下:

3.3.1 新增或修改文档

首先会判断索引是否存在,不存在的话会根据索引文档进行创建索引,然后进行新增或修改操作,如果没有指定id的话(上文说的注解@JestId字段),会自动生成一个id。

Index.Builder builder = new Index.Builder(bookRequest.getBody());
Index index = builder.index(bookRequest.getIndexName()).type(bookRequest.getTypeName()).build();

这里使用新增文档创建三条数据方便后面查询,如下:

{
    "indexName": "book",
    "typeName": "book",
    "body": {"id":"test0001","bookName":"数学书","bookAuthor":"复旦大学","pages":100,"desc":"复旦大学的数学书"}
}
{
    "indexName": "book",
    "typeName": "book",
    "body": {"id":"test0003","bookName":"语文书","bookAuthor":"北京大学","pages":100,"desc":"北京大学的语文书"}
}
{
    "indexName": "book",
    "typeName": "book",
    "body": {"id":"test0003","bookName":"英文书","bookAuthor":"清华大学","pages":200,"desc":"清华大学的英文书"}
}

3.3.2 删除文档(根据id)

Delete index = new Delete.Builder(bookRequest.getId()).index(bookRequest.getIndexName()).type(bookRequest.getTypeName()).build();

完整示例内容如下:

package com.dalaoyang.web;

import com.dalaoyang.model.BookRequest;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestResult;
import io.searchbox.core.Delete;
import io.searchbox.core.Index;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class DocumentController {

    @Autowired
    private JestClient jestClient;

    @PostMapping("saveOrUpdateDocument")
    public String saveOrUpdateDocument(@RequestBody BookRequest bookRequest) throws Exception{
        Index.Builder builder = new Index.Builder(bookRequest.getBody());
        Index index = builder.index(bookRequest.getIndexName()).type(bookRequest.getTypeName()).build();
        JestResult result = jestClient.execute(index);
        return result.getJsonString();
    }

    @PostMapping("deleteDocumentById")
    public String deleteDocumentById(@RequestBody BookRequest bookRequest) throws Exception{
        Delete index = new Delete.Builder(bookRequest.getId()).index(bookRequest.getIndexName()).type(bookRequest.getTypeName()).build();
        JestResult result = jestClient.execute(index);
        return result.getJsonString();
    }
}

3.4 查询操作

查询操作可能是对Elasticsearch最需要使用的场景,这里举一个简单的场景,输入关键字,查询对应book文档,关键字匹配(bookName,bookAuthor,desc)三个字段,这里结合Elasticsearch官方依赖进行操作,完整示例如下:

package com.dalaoyang.web;

import com.dalaoyang.model.BookRequest;
import io.searchbox.client.JestClient;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
public class QueryController {

    @Autowired
    private JestClient jestClient;

    @PostMapping("search")
    public String search(@RequestBody BookRequest bookRequest) throws Exception{
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(new MultiMatchQueryBuilder(bookRequest.getKeyword(), "bookName","bookAuthor","desc"));
        log.info(searchSourceBuilder.toString());
        SearchResult result = jestClient.execute(new Search.Builder(searchSourceBuilder.toString())
                .addIndex(bookRequest.getIndexName())
                .addType(bookRequest.getTypeName())
                .build());
        return result.getJsonString();
    }
}

比如这里搜索清华,这里我打印了一下查询语句,如下:

{
    "query":{
        "multi_match":{
            "query":"清华",
            "fields":[
                "bookAuthor^1.0",
                "bookName^1.0",
                "desc^1.0"
            ],
            "type":"best_fields",
            "operator":"OR",
            "slop":0,
            "prefix_length":0,
            "max_expansions":50,
            "zero_terms_query":"NONE",
            "auto_generate_synonyms_phrase_query":true,
            "fuzzy_transpositions":true,
            "boost":1
        }
    }
}

查询的结构只有一条,与在Elasticsearch-Head中查询一致,如图

JVvmAna.png!web

4.一些建议

相关操作Elasticsearch的客户端有很多,这里就不做相关对比了,JestClient本人也在真实上线项目中使用过,这里只是在使用过几种的前提下做出几点建议:

  • Elastic官方已经开始建议使用HTTP方式去操作Elasticsearch了
  • 当初选择这种的原因是考虑到更好的去扩展版本,封装响应的操作类可以兼容更多的版本。
  • 在高版本的Elasticsearch中,有一些文档类型的内容被单独抽离出来了,比如父子文档。

5.源码

源码地址: https://gitee.com/dalaoyang/springboot_learn/tree/master/springboot_jestclient


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK