elasticsearch[一]-索引庫操作(輕松創(chuàng)建)、文檔增刪改查、批量寫入(效率倍增)
1、初始化 RestClient
在 elasticsearch 提供的 API 中,與 elasticsearch 一切交互都封裝在一個名為 RestHighLevelClient 的類中,必須先完成這個對象的初始化,建立與 elasticsearch 的連接。
分為三步:
1)引入 es 的 RestHighLevelClient 依賴:
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
2)因為 SpringBoot 默認的 ES 版本是 7.6.2,所以我們需要覆蓋默認的 ES 版本:
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>7.12.1</elasticsearch.version>
</properties>
3)初始化 RestHighLevelClient:
初始化的代碼如下:
RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://xxx.xxx.xxx.xxx:9200")
));
這里為了單元測試方便,我們創(chuàng)建一個測試類 HotelIndexTest,然后將初始化的代碼編寫在 @BeforeEach 方法中:
package cn.itcast.hotel;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestHighLevelClient;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.IOException;
public class HotelIndexTest {
private RestHighLevelClient client;
@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://xxx.xxx.xxx.xxx:9200")
));
}
@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}
1.1、創(chuàng)建索引庫
創(chuàng)建索引庫的 API 如下:
代碼分為三步:
- 1)創(chuàng)建 Request 對象。因為是創(chuàng)建索引庫的操作,因此 Request 是 CreateIndexRequest。
- 2)添加請求參數(shù),其實就是 DSL 的 JSON 參數(shù)部分。因為 json 字符串很長,這里是定義了靜態(tài)字符串常量 MAPPING_TEMPLATE,讓代碼看起來更加優(yōu)雅。
- 3)發(fā)送請求,client.indices() 方法的返回值是 IndicesClient 類型,封裝了所有與索引庫操作有關(guān)的方法。
完整示例
在 hotel-demo 的 cn.itcast.hotel.constants 包下,創(chuàng)建一個類,定義 mapping 映射的 JSON 字符串常量:
package cn.itcast.hotel.constants;
public class HotelConstants {
public static final String MAPPING_TEMPLATE = "{\n" +
" \"mappings\": {\n" +
" \"properties\": {\n" +
" \"id\": {\n" +
" \"type\": \"keyword\"\n" +
" },\n" +
" \"name\":{\n" +
" \"type\": \"text\",\n" +
" \"analyzer\": \"ik_max_word\",\n" +
" \"copy_to\": \"all\"\n" +
" },\n" +
" \"address\":{\n" +
" \"type\": \"keyword\",\n" +
" \"index\": false\n" +
" },\n" +
" \"price\":{\n" +
" \"type\": \"integer\"\n" +
" },\n" +
" \"score\":{\n" +
" \"type\": \"integer\"\n" +
" },\n" +
" \"brand\":{\n" +
" \"type\": \"keyword\",\n" +
" \"copy_to\": \"all\"\n" +
" },\n" +
" \"city\":{\n" +
" \"type\": \"keyword\",\n" +
" \"copy_to\": \"all\"\n" +
" },\n" +
" \"starName\":{\n" +
" \"type\": \"keyword\"\n" +
" },\n" +
" \"business\":{\n" +
" \"type\": \"keyword\"\n" +
" },\n" +
" \"location\":{\n" +
" \"type\": \"geo_point\"\n" +
" },\n" +
" \"pic\":{\n" +
" \"type\": \"keyword\",\n" +
" \"index\": false\n" +
" },\n" +
" \"all\":{\n" +
" \"type\": \"text\",\n" +
" \"analyzer\": \"ik_max_word\"\n" +
" }\n" +
" }\n" +
" }\n" +
"}";
}
在 hotel-demo 中的 HotelIndexTest 測試類中,編寫單元測試,實現(xiàn)創(chuàng)建索引:
@Test
void createHotelIndex() throws IOException {
// 1.創(chuàng)建Request對象
CreateIndexRequest request = new CreateIndexRequest("hotel");
// 2.準備請求的參數(shù):DSL語句
request.source(MAPPING_TEMPLATE, XContentType.JSON);
// 3.發(fā)送請求
client.indices().create(request, RequestOptions.DEFAULT);
}
1.2、刪除索引庫
刪除索引庫的 DSL 語句非常簡單:
DELETE /hotel
與創(chuàng)建索引庫相比:
- 請求方式從 PUT 變?yōu)?DELTE
- 請求路徑不變
- 無請求參數(shù)
所以代碼的差異,注意體現(xiàn)在 Request 對象上。依然是三步走:
- 1)創(chuàng)建 Request 對象。這次是 DeleteIndexRequest 對象
- 2)準備參數(shù)。這里是無參
- 3)發(fā)送請求。改用 delete 方法
在 hotel-demo 中的 HotelIndexTest 測試類中,編寫單元測試,實現(xiàn)刪除索引:
@Test
void testDeleteHotelIndex() throws IOException {
// 1.創(chuàng)建Request對象
DeleteIndexRequest request = new DeleteIndexRequest("hotel");
// 2.發(fā)送請求
client.indices().delete(request, RequestOptions.DEFAULT);
}
1.3、判斷索引庫是否存在
判斷索引庫是否存在,本質(zhì)就是查詢,對應(yīng)的 DSL 是:
GET /hotel
因此與刪除的 Java 代碼流程是類似的。依然是三步走:
- 1)創(chuàng)建 Request 對象。這次是 GetIndexRequest 對象
- 2)準備參數(shù)。這里是無參
- 3)發(fā)送請求。改用 exists 方法
@Test
void testExistsHotelIndex() throws IOException {
// 1.創(chuàng)建Request對象
GetIndexRequest request = new GetIndexRequest("hotel");
// 2.發(fā)送請求
boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
// 3.輸出
System.err.println(exists ? "索引庫已經(jīng)存在!" : "索引庫不存在!");
}
1.4、總結(jié)
JavaRestClient 操作 elasticsearch 的流程基本類似。核心是 client.indices() 方法來獲取索引庫的操作對象。
索引庫操作的基本步驟:
- 初始化 RestHighLevelClient
- 創(chuàng)建 XxxIndexRequest。XXX 是 Create、Get、Delete
- 準備 DSL( Create 時需要,其它是無參)
- 發(fā)送請求。調(diào)用 RestHighLevelClient#indices().xxx() 方法,xxx 是 create、exists、delete
2、RestClient 操作文檔
為了與索引庫操作分離,我們再次參加一個測試類,做兩件事情:
- 初始化 RestHighLevelClient
- 我們的酒店數(shù)據(jù)在數(shù)據(jù)庫,需要利用 IHotelService 去查詢,所以注入這個接口
package cn.itcast.hotel;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.service.IHotelService;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
import java.util.List;
@SpringBootTest
public class HotelDocumentTest {
@Autowired
private IHotelService hotelService;
private RestHighLevelClient client;
@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.150.101:9200")
));
}
@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}
2.1、新增文檔
我們要將數(shù)據(jù)庫的酒店數(shù)據(jù)查詢出來,寫入 elasticsearch 中。
2.1.1、索引庫實體類
數(shù)據(jù)庫查詢后的結(jié)果是一個 Hotel 類型的對象。結(jié)構(gòu)如下:
@Data
@TableName("tb_hotel")
public class Hotel {
@TableId(type = IdType.INPUT)
private Long id;
private String name;
private String address;
private Integer price;
private Integer score;
private String brand;
private String city;
private String starName;
private String business;
private String longitude;
private String latitude;
private String pic;
}
與我們的索引庫結(jié)構(gòu)存在差異:
- longitude 和 latitude 需要合并為 location
因此,我們需要定義一個新的類型,與索引庫結(jié)構(gòu)吻合:
package cn.itcast.hotel.pojo;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class HotelDoc {
private Long id;
private String name;
private String address;
private Integer price;
private Integer score;
private String brand;
private String city;
private String starName;
private String business;
private String location;
private String pic;
public HotelDoc(Hotel hotel) {
this.id = hotel.getId();
this.name = hotel.getName();
this.address = hotel.getAddress();
this.price = hotel.getPrice();
this.score = hotel.getScore();
this.brand = hotel.getBrand();
this.city = hotel.getCity();
this.starName = hotel.getStarName();
this.business = hotel.getBusiness();
this.location = hotel.getLatitude() + ", " + hotel.getLongitude();
this.pic = hotel.getPic();
}
}
2.1.2. 語法說明
新增文檔的 DSL 語句如下:
POST /{索引庫名}/_doc/1
{
"name": "Jack",
"age": 21
}
對應(yīng)的 java 代碼如圖:
可以看到與創(chuàng)建索引庫類似,同樣是三步走:
- 1)創(chuàng)建 Request 對象
- 2)準備請求參數(shù),也就是 DSL 中的 JSON 文檔
- 3)發(fā)送請求
變化的地方在于,這里直接使用 client.xxx() 的 API,不再需要 client.indices() 了。
2.1.3、完整代碼
我們導(dǎo)入酒店數(shù)據(jù),基本流程一致,但是需要考慮幾點變化:
- 酒店數(shù)據(jù)來自于數(shù)據(jù)庫,我們需要先查詢出來,得到 hotel 對象
- hotel 對象需要轉(zhuǎn)為 HotelDoc 對象
- HotelDoc 需要序列化為 json 格式
因此,代碼整體步驟如下:
- 1)根據(jù) id 查詢酒店數(shù)據(jù) Hotel
- 2)將 Hotel 封裝為 HotelDoc
- 3)將 HotelDoc 序列化為 JSON
- 4)創(chuàng)建 IndexRequest,指定索引庫名和 id
- 5)準備請求參數(shù),也就是 JSON 文檔
- 6)發(fā)送請求
在 hotel-demo 的 HotelDocumentTest 測試類中,編寫單元測試:
@Test
void testAddDocument() throws IOException {
// 1.根據(jù)id查詢酒店數(shù)據(jù)
Hotel hotel = hotelService.getById(61083L);
// 2.轉(zhuǎn)換為文檔類型
HotelDoc hotelDoc = new HotelDoc(hotel);
// 3.將HotelDoc轉(zhuǎn)json
String json = JSON.toJSONString(hotelDoc);
// 1.準備Request對象
IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());
// 2.準備Json文檔
request.source(json, XContentType.JSON);
// 3.發(fā)送請求
client.index(request, RequestOptions.DEFAULT);
}
2.2、查詢文檔
2.2.1、語法說明
查詢的 DSL 語句如下:
GET /hotel/_doc/{id}
非常簡單,因此代碼大概分兩步:
- 準備 Request 對象
- 發(fā)送請求
不過查詢的目的是得到結(jié)果,解析為 HotelDoc,因此難點是結(jié)果的解析。完整代碼如下:
可以看到,結(jié)果是一個 JSON,其中文檔放在一個_source
屬性中,因此解析就是拿到_source
,反序列化為 Java 對象即可。
與之前類似,也是三步走:
- 1)準備 Request 對象。這次是查詢,所以是 GetRequest
- 2)發(fā)送請求,得到結(jié)果。因為是查詢,這里調(diào)用 client.get() 方法
- 3)解析結(jié)果,就是對 JSON 做反序列化
2.2.2、完整代碼
在 hotel-demo 的 HotelDocumentTest 測試類中,編寫單元測試:
@Test
void testGetDocumentById() throws IOException {
// 1.準備Request
GetRequest request = new GetRequest("hotel", "61082");
// 2.發(fā)送請求,得到響應(yīng)
GetResponse response = client.get(request, RequestOptions.DEFAULT);
// 3.解析響應(yīng)結(jié)果
String json = response.getSourceAsString();
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println(hotelDoc);
}
2.3. 刪除文檔
刪除的 DSL 為是這樣的:
DELETE /hotel/_doc/{id}
與查詢相比,僅僅是請求方式從 DELETE 變成 GET,可以想象 Java 代碼應(yīng)該依然是三步走:
- 1)準備 Request 對象,因為是刪除,這次是 DeleteRequest 對象。要指定索引庫名和 id
- 2)準備參數(shù),無參
- 3)發(fā)送請求。因為是刪除,所以是 client.delete() 方法
在 hotel-demo 的 HotelDocumentTest 測試類中,編寫單元測試:
@Test
void testDeleteDocument() throws IOException {
// 1.準備Request
DeleteRequest request = new DeleteRequest("hotel", "61083");
// 2.發(fā)送請求
client.delete(request, RequestOptions.DEFAULT);
}
2.4、修改文檔
2.4.1、語法說明
修改我們講過兩種方式:
- 全量修改:本質(zhì)是先根據(jù) id 刪除,再新增
- 增量修改:修改文檔中的指定字段值
在 RestClient 的 API 中,全量修改與新增的 API 完全一致,判斷依據(jù)是 ID:
- 如果新增時,ID 已經(jīng)存在,則修改
- 如果新增時,ID 不存在,則新增
這里不再贅述,我們主要關(guān)注增量修改。
代碼示例如圖:
與之前類似,也是三步走:
- 1)準備 Request 對象。這次是修改,所以是 UpdateRequest
- 2)準備參數(shù)。也就是 JSON 文檔,里面包含要修改的字段
- 3)更新文檔。這里調(diào)用 client.update() 方法
2.4.2. 完整代碼
在 hotel-demo 的 HotelDocumentTest 測試類中,編寫單元測試:
@Test
void testUpdateDocument() throws IOException {
// 1.準備Request
UpdateRequest request = new UpdateRequest("hotel", "61083");
// 2.準備請求參數(shù)
request.doc(
"price", "952",
"starName", "四鉆"
);
// 3.發(fā)送請求
client.update(request, RequestOptions.DEFAULT);
}
2.5、批量導(dǎo)入文檔
案例需求:利用 BulkRequest 批量將數(shù)據(jù)庫數(shù)據(jù)導(dǎo)入到索引庫中。
步驟如下:
-
利用 mybatis-plus 查詢酒店數(shù)據(jù)
-
將查詢到的酒店數(shù)據(jù)(Hotel)轉(zhuǎn)換為文檔類型數(shù)據(jù)(HotelDoc)
-
利用 JavaRestClient 中的 BulkRequest 批處理,實現(xiàn)批量新增文檔
2.5.1. 語法說明
批量處理 BulkRequest,其本質(zhì)就是將多個普通的 CRUD 請求組合在一起發(fā)送。
其中提供了一個 add 方法,用來添加其他請求:
可以看到,能添加的請求包括:
- IndexRequest,也就是新增
- UpdateRequest,也就是修改
- DeleteRequest,也就是刪除
因此 Bulk 中添加了多個 IndexRequest,就是批量新增功能了。示例:
其實還是三步走:
- 1)創(chuàng)建 Request 對象。這里是 BulkRequest
- 2)準備參數(shù)。批處理的參數(shù),就是其它 Request 對象,這里就是多個 IndexRequest
- 3)發(fā)起請求。這里是批處理,調(diào)用的方法為 client.bulk() 方法
我們在導(dǎo)入酒店數(shù)據(jù)時,將上述代碼改造成 for 循環(huán)處理即可。
2.5.2. 完整代碼
在 hotel-demo 的 HotelDocumentTest 測試類中,編寫單元測試:
/**
* 批量導(dǎo)入es
* @throws IOException
*/
@Test
void testBatchImportDocument() throws IOException {
// 1、批量查詢數(shù)據(jù)庫數(shù)據(jù)
List<Hotel> list = hotelService.list();
// 2、創(chuàng)建 request 對象
BulkRequest request = new BulkRequest();
// 3、轉(zhuǎn)換文檔格式
for (Hotel hotel : list) {
HotelDoc hotelDoc = new HotelDoc(hotel);
request.add(new IndexRequest("hotel")
.id(hotel.getId().toString())
.source(JSON.toJSONString(hotelDoc), XContentType.JSON));
}
// 4、發(fā)送請求
client.bulk(request, RequestOptions.DEFAULT);
}
2.6. 小結(jié)
文檔操作的基本步驟:文章來源:http://www.zghlxwxcb.cn/news/detail-793081.html
- 初始化 RestHighLevelClient
- 創(chuàng)建 XxxRequest。XXX 是 Index、Get、Update、Delete、Bulk
- 準備參數(shù)(Index、Update、Bulk 時需要)
- 發(fā)送請求。調(diào)用 RestHighLevelClient#.xxx() 方法,xxx 是 index、get、update、delete、bulk
- 解析結(jié)果(Get 時需要)
參考鏈接:https://www.cnblogs.com/DeryKong/p/17002492.html文章來源地址http://www.zghlxwxcb.cn/news/detail-793081.html
到了這里,關(guān)于elasticsearch[一]-索引庫操作(輕松創(chuàng)建)、文檔增刪改查、批量寫入(效率倍增)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!