1 批量请求(Bulk)
可通过单次请求执行多个操作,如文档索引,文档更新,文档删除等操作。
- 构建请求
- 执行:同步和异步
- 解析响应
在这为了方便,我直接将响应序列化为json了
package study.wyy.esclient.high.document;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.junit.Test;
import study.wyy.esclient.high.BaseTest;
import java.io.IOException;
import java.util.Date;
/**
* @author wyaoyao
* @description
* @date 2021/1/11 17:19
* 文档批量操作
*/
@Slf4j
public class BulkDocumentTest extends BaseTest {
@Test
public void testBulkRequest() throws IOException {
// 1 构建请求BulkRequest
BulkRequest request = buildRequest();
// 2 执行请求
BulkResponse responses = client.bulk(request, RequestOptions.DEFAULT);
log.info("response:{}",objectMapper.writer().writeValueAsString(responses));
// 异步执行:
/*
client.bulkAsync(request, RequestOptions.DEFAULT, new ActionListener<BulkResponse>() {
@Override
public void onResponse(BulkResponse bulkItemResponses) {
}
@Override
public void onFailure(Exception e) {
}
});
*/
}
public BulkRequest buildRequest() throws IOException {
BulkRequest request = new BulkRequest();
// 添加一个IndexRequest,
IndexRequest indexRequest = buildIndexRequest();
request.add(indexRequest);
// 添加一个删除请求
DeleteRequest deleteRequest = buildDeleteRequest();
request.add(deleteRequest);
// 当然还可以添加更新请求:就不做测试了
//request.add(new UpdateRequest())
// 其他可选配置:超时时间,刷新策略,分片副本数量,全局路由等
// 超时时间
request.timeout(TimeValue.timeValueMinutes(2));
// 刷新策略
request.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
// 设置在继续执行索引/更新/删除操作之前必须处于活动状态的分片副本数量
request.waitForActiveShards(2);
return request;
}
public DeleteRequest buildDeleteRequest() {
DeleteRequest request = new DeleteRequest("books");
// 设置id
request.id("1");
return request;
}
public IndexRequest buildIndexRequest() throws IOException {
IndexRequest indexRequest = new IndexRequest("books");
// 设置id
indexRequest.id("4");
XContentBuilder xContentBuilder = XContentFactory.jsonBuilder();
xContentBuilder.startObject();
xContentBuilder.field("id", 4L);
xContentBuilder.field("title", "Python基础教程");
xContentBuilder.field("language", "python");
xContentBuilder.field("author", "Helant");
xContentBuilder.field("price", 54.50f);
xContentBuilder.field("publish_time", new Date());
xContentBuilder.field("description", "经典的Python入门教程,层次鲜明,结构严谨,内容翔实");
xContentBuilder.endObject();
indexRequest.source(xContentBuilder);
return indexRequest;
}
}
日志输出的json数据:
{
"ingestTookInMillis":-1,
"items":[
{
"id":"4",
"opType":"INDEX",
"response":{
"shardInfo":{
"total":2,
"successful":1,
"failures":[
],
"failed":0,
"fragment":false
},
"shardId":{
"index":{
"name":"books",
"uuid":"_na_",
"fragment":false
},
"id":-1,
"indexName":"books",
"fragment":true
},
"id":"4",
"type":"_doc",
"version":1,
"seqNo":2,
"primaryTerm":1,
"result":"CREATED",
"index":"books",
"fragment":false
},
"failure":null,
"type":"_doc",
"index":"books",
"version":1,
"failureMessage":null,
"itemId":0,
"failed":false,
"fragment":false
},
{
"id":"1",
"opType":"DELETE",
"response":{
"shardInfo":{
"total":2,
"successful":1,
"failures":[
],
"failed":0,
"fragment":false
},
"shardId":{
"index":{
"name":"books",
"uuid":"_na_",
"fragment":false
},
"id":-1,
"indexName":"books",
"fragment":true
},
"id":"1",
"type":"_doc",
"version":8,
"seqNo":17,
"primaryTerm":1,
"result":"DELETED",
"index":"books",
"fragment":false
},
"failure":null,
"type":"_doc",
"index":"books",
"version":8,
"failureMessage":null,
"itemId":1,
"failed":false,
"fragment":false
}
],
"took":{
"hours":0,
"minutes":0,
"seconds":0,
"millis":264,
"stringRep":"264ms",
"hoursFrac":0.00007333333333333333,
"microsFrac":264000,
"millisFrac":264,
"secondsFrac":0.264,
"micros":264000,
"days":0,
"minutesFrac":0.0044,
"daysFrac":0.0000030555555555555556,
"nanos":264000000
},
"ingestTook":{
"hours":0,
"minutes":0,
"seconds":0,
"millis":-1,
"stringRep":"-1",
"hoursFrac":-0.00000027777777777777776,
"microsFrac":-1000,
"millisFrac":-1,
"secondsFrac":-0.001,
"micros":-1000,
"days":0,
"minutesFrac":-0.000016666666666666667,
"daysFrac":-0.000000011574074074074074,
"nanos":-1000000
},
"fragment":false
}
2 批量处理器
es还提供了批量处理器来简化批量操作,并且还提供了一个监听器,可以在执行批量请求的前后进行功能增强
package study.wyy.esclient.high.document;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.bulk.BulkProcessor;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.client.RequestOptions;
import org.junit.Test;
import study.wyy.esclient.high.BaseTest;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
/**
* @author wyaoyao
* @description
* @date 2021/1/12 9:50
* 批量请求处理器测试
*/
@Slf4j
public class BulkProcessorTest extends BulkDocumentTest {
public static void main(String[] args) throws IOException, InterruptedException {
new BulkProcessorTest().testBulkProcessor();
}
public void testBulkProcessor() throws IOException, InterruptedException {
// 需要两个参数:BiConsumer,BulkProcessor.Listener
BulkProcessor bulkProcessor = BulkProcessor.builder(new BiConsumer<BulkRequest, ActionListener<BulkResponse>>() {
@Override
public void accept(BulkRequest bulkRequest, ActionListener<BulkResponse> bulkResponseActionListener) {
// 执行请求
client.bulkAsync(bulkRequest, RequestOptions.DEFAULT, bulkResponseActionListener);
}
}, new BulkProcessor.Listener() {
// 执行请求之前的前置处理
@Override
public void beforeBulk(long executionId, BulkRequest request) {
// request: 肯定就是封装的请求参数
// 打印一下这个id
System.out.println("前置处理: " + executionId);
}
// 后置处理
@Override
public void afterBulk(long executionId, BulkRequest request, BulkResponse response) {
System.out.println("后置处理: " + executionId);
}
// 异常处理
@Override
public void afterBulk(long executionId, BulkRequest request, Throwable failure) {
System.out.println("异常处理: " + executionId);
}
}).build();
// 添加一个indexRequest
bulkProcessor.add(buildIndexRequest());
// 添加一个DeleteRequest
bulkProcessor.add(buildDeleteRequest());
bulkProcessor.awaitClose(10L, TimeUnit.SECONDS);
}
}
使用lambda表达式简化:
public void testBulkProcessorWithLambda() throws IOException, InterruptedException {
// 需要两个参数:BiConsumer,BulkProcessor.Listener
BulkProcessor bulkProcessor = BulkProcessor.builder((request,listener)->{
client.bulkAsync(request,RequestOptions.DEFAULT,listener);
}, new BulkProcessor.Listener() {
// 执行请求之前的前置处理
@Override
public void beforeBulk(long executionId, BulkRequest request) {
// request: 肯定就是封装的请求参数
// 打印一下这个id
System.out.println("前置处理: " + executionId);
}
// 后置处理
@Override
public void afterBulk(long executionId, BulkRequest request, BulkResponse response) {
System.out.println("后置处理: " + executionId);
}
// 异常处理
@Override
public void afterBulk(long executionId, BulkRequest request, Throwable failure) {
System.out.println("异常处理: " + executionId);
}
}).build();
// 添加一个indexRequest
bulkProcessor.add(buildIndexRequest());
// 添加一个DeleteRequest
bulkProcessor.add(buildDeleteRequest());
bulkProcessor.awaitClose(10L, TimeUnit.SECONDS);
}
3 批量获取(MultiGet)
package study.wyy.esclient.high.document;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.get.MultiGetItemResponse;
import org.elasticsearch.action.get.MultiGetRequest;
import org.elasticsearch.action.get.MultiGetResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.document.DocumentField;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.junit.Test;
import study.wyy.esclient.high.BaseTest;
import java.io.IOException;
/**
* @author wyaoyao
* @description
* @date 2021/1/12 11:53
*/
@Slf4j
public class MultiGetTest extends BaseTest {
@Test
public void testMultiGetSync() throws IOException {
// 1 构建请求
MultiGetRequest request = new MultiGetRequest();
String[] ids = new String[]{"1", "2", "3"};
// 遍历id,添加到request
for (int i = 0; i < ids.length; i++){
// 参参数一: 索引库名字, 参数二: 文档id
request.add(new MultiGetRequest.Item("books",ids[i]));
// 每个MultiGetRequest.Item,也可以设置source过滤,路由,版本等参数
/*
new MultiGetRequest.Item("books",ids[i])
.version(1)
.routing("hello");
*/
}
// 可选参数
//关闭实时性,默认是开启
request.realtime(false);
// 查询前,是否执行刷新,默认是false
request.refresh(true);
// 2 执行请求
MultiGetResponse response = client.mget(request, RequestOptions.DEFAULT);
// 3 响应解析
MultiGetItemResponse[] responses = response.getResponses();
for (var res :responses) {
String index = res.getIndex();
String id = res.getId();
GetResponse getResponse = res.getResponse();
String s = objectMapper.writer().writeValueAsString(getResponse.getSourceAsMap());
System.out.println(s);
}
}
}
上面遍历中的一个循环的的打印:
{
"author":"Bruce Eckel",
"price":70.2,
"publish_time":"2007-10-01",
"description":"Java学习必读经典,殿堂级著作!赢得了全球程序员的广泛赞誉。",
"language":"java",
"id":"1",
"title":"Java编程思想"
}
同样也支持异步执行:参考之前API的笔记,没有任何区别