1.Jest介紹
操作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插件,如下圖所示。
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中查詢一致,如圖
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