SpringBoot 使用JestClient操作Elasticsearch

1.Jest介紹

image

操作Elasticsearch的客戶端有很多,SpringBoot也提供了方式去操作,這里介紹另外一種方式去使用Elasticsearch --- JestClient

JestClient是一款基于HTTP方式操作的Elasticsearch的客戶端,支持同步和異步操作,同時(shí)也可以結(jié)合ElasticSearch的依賴進(jìn)行操作Elasticsearch。

支持多個(gè)版本的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 前置工作

首先啟動(dòng)Elasticsearch,我這里是在本地啟動(dòng)的Elasticsearch,版本是6.8.2,為了方便查看數(shù)據(jù),這里使用Elasticsearch-Head插件,如下圖所示。

image

2.2 添加Jest依賴

創(chuàng)建項(xiàng)目,在pom文件中加入Jest依賴(這里根據(jù)上面版本對(duì)應(yīng)添加依賴),這里額外添加量了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相關(guān)配置,其中uris配置Elasticsearch的HTTP端口,如本文添加的配置:

spring.application.name=springboot_jestclient
# 應(yīng)用服務(wù)web訪問端口
server.port=8888

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

到這里其實(shí)已經(jīng)整合完成了,是不是非常簡單?

3.Elasticsearch基本操作

接下介紹如何操作Elasticsearch,這里分別介紹如下幾部分內(nèi)容:

  • 索引文檔
  • 索引類操作
  • 文檔類操作
  • 查詢操作

3.1 文檔實(shí)體

這里創(chuàng)建一個(gè)Book文檔做為示例,其中@JestId為文檔id,即Elasticsearch中的_id字段,本文BookDocument內(nèi)容如下:

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;
}

為了方便操作,這里創(chuàng)建了一個(gè)request對(duì)象進(jìn)行操作,如下:

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;
}

在使用相關(guān)操作時(shí),其實(shí)都是通過io.searchbox.client.JestClient#execute來進(jìn)行操作(需要注意,這里沒有對(duì)JestClient進(jìn)行配置,只是使用的默認(rèn)的配置),將對(duì)應(yīng)動(dòng)作當(dāng)做參數(shù)傳入,接下來介紹幾個(gè)常用的動(dòng)作。

3.2 索引類操作

結(jié)合MySQL來看的話,索引可以理解為一個(gè)數(shù)據(jù)庫,索引相關(guān)的操作可能不是很多,這里介紹相對(duì)比較常用的是創(chuàng)建索引和刪除索引,如下:

3.2.1 創(chuàng)建索引

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

3.2.2 刪除索引

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

通過上面兩個(gè)操作可以看到,都是通過使用對(duì)應(yīng)的Index實(shí)體來操作對(duì)應(yīng)實(shí)體,當(dāng)然還有一些不是很常用的,如果有需要可以查看相關(guān)文檔進(jìn)行使用,這里不一一介紹了,完整s示例內(nèi)容如下:

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 文檔類操作

文檔相當(dāng)于MySQL中的行記錄,也就是說一條數(shù)據(jù),由于新增和修改在同一個(gè)方法內(nèi),所以這里也是對(duì)新增(和修改)和刪除方法進(jìn)行介紹,如下:

3.3.1 新增或修改文檔

首先會(huì)判斷索引是否存在,不存在的話會(huì)根據(jù)索引文檔進(jìn)行創(chuàng)建索引,然后進(jìn)行新增或修改操作,如果沒有指定id的話(上文說的注解@JestId字段),會(huì)自動(dòng)生成一個(gè)id。

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

這里使用新增文檔創(chuàng)建三條數(shù)據(jù)方便后面查詢,如下:

{
    "indexName": "book",
    "typeName": "book",
    "body": {"id":"test0001","bookName":"數(shù)學(xué)書","bookAuthor":"復(fù)旦大學(xué)","pages":100,"desc":"復(fù)旦大學(xué)的數(shù)學(xué)書"}
}
{
    "indexName": "book",
    "typeName": "book",
    "body": {"id":"test0003","bookName":"語文書","bookAuthor":"北京大學(xué)","pages":100,"desc":"北京大學(xué)的語文書"}
}
{
    "indexName": "book",
    "typeName": "book",
    "body": {"id":"test0003","bookName":"英文書","bookAuthor":"清華大學(xué)","pages":200,"desc":"清華大學(xué)的英文書"}
}

3.3.2 刪除文檔(根據(jù)id)

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

完整示例內(nèi)容如下:

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 查詢操作

查詢操作可能是對(duì)Elasticsearch最需要使用的場(chǎng)景,這里舉一個(gè)簡單的場(chǎng)景,輸入關(guān)鍵字,查詢對(duì)應(yīng)book文檔,關(guān)鍵字匹配(bookName,bookAuthor,desc)三個(gè)字段,這里結(jié)合Elasticsearch官方依賴進(jìn)行操作,完整示例如下:


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
        }
    }
}

查詢的結(jié)構(gòu)只有一條,與在Elasticsearch-Head中查詢一致,如圖

image

4.一些建議

相關(guān)操作Elasticsearch的客戶端有很多,這里就不做相關(guān)對(duì)比了,JestClient本人也在真實(shí)上線項(xiàng)目中使用過,這里只是在使用過幾種的前提下做出幾點(diǎn)建議:

  • Elastic官方已經(jīng)開始建議使用HTTP方式去操作Elasticsearch了
  • 當(dāng)初選擇這種的原因是考慮到更好的去擴(kuò)展版本,封裝響應(yīng)的操作類可以兼容更多的版本。
  • 在高版本的Elasticsearch中,有一些文檔類型的內(nèi)容被單獨(dú)抽離出來了,比如父子文檔。

5.源碼

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容