mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-06-22 20:12:11 +00:00
DATAES-684 Implement bulk request from reactive client
Original PR: #342 * DATAES-684 Implement bulk request from reactive client * Update src/main/java/org/springframework/data/elasticsearch/client/reactive/ReactiveElasticsearchClient.java Co-Authored-By: Peter-Josef Meisch <pj.meisch@sothawo.com> * DATAES-684 Implement bulk request from reactive client Added author (cherry picked from commit 6ae424428ccc45d72b80dcd3ddb7e3fbc6f32073)
This commit is contained in:
parent
3b833f6f63
commit
f82dd229d9
@ -58,6 +58,8 @@ import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
|
|||||||
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
|
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
|
||||||
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
|
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
|
||||||
import org.elasticsearch.action.admin.indices.refresh.RefreshResponse;
|
import org.elasticsearch.action.admin.indices.refresh.RefreshResponse;
|
||||||
|
import org.elasticsearch.action.bulk.BulkRequest;
|
||||||
|
import org.elasticsearch.action.bulk.BulkResponse;
|
||||||
import org.elasticsearch.action.delete.DeleteRequest;
|
import org.elasticsearch.action.delete.DeleteRequest;
|
||||||
import org.elasticsearch.action.delete.DeleteResponse;
|
import org.elasticsearch.action.delete.DeleteResponse;
|
||||||
import org.elasticsearch.action.get.GetRequest;
|
import org.elasticsearch.action.get.GetRequest;
|
||||||
@ -122,6 +124,7 @@ import org.springframework.web.reactive.function.client.WebClient.RequestBodySpe
|
|||||||
*
|
*
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
|
* @author Henrique Amaral
|
||||||
* @since 3.2
|
* @since 3.2
|
||||||
* @see ClientConfiguration
|
* @see ClientConfiguration
|
||||||
* @see ReactiveRestClients
|
* @see ReactiveRestClients
|
||||||
@ -423,6 +426,16 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
|||||||
.publishNext();
|
.publishNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#bulk(org.springframework.http.HttpHeaders, org.elasticsearch.action.bulk.BulkRequest)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Mono<BulkResponse> bulk(HttpHeaders headers, BulkRequest bulkRequest) {
|
||||||
|
return sendRequest(bulkRequest, RequestCreator.bulk(), BulkResponse.class, headers) //
|
||||||
|
.publishNext();
|
||||||
|
}
|
||||||
|
|
||||||
// --> INDICES
|
// --> INDICES
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -742,6 +755,18 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Function<BulkRequest, Request> bulk() {
|
||||||
|
|
||||||
|
return request -> {
|
||||||
|
|
||||||
|
try {
|
||||||
|
return RequestConverters.bulk(request);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticsearchException("Could not parse request", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// --> INDICES
|
// --> INDICES
|
||||||
|
|
||||||
static Function<GetIndexRequest, Request> indexExists() {
|
static Function<GetIndexRequest, Request> indexExists() {
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.elasticsearch.client.reactive;
|
package org.springframework.data.elasticsearch.client.reactive;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.bulk.BulkRequest;
|
||||||
|
import org.elasticsearch.action.bulk.BulkResponse;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
@ -58,6 +60,7 @@ import org.springframework.web.reactive.function.client.WebClient;
|
|||||||
*
|
*
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
|
* @author Henrique Amaral
|
||||||
* @since 3.2
|
* @since 3.2
|
||||||
* @see ClientConfiguration
|
* @see ClientConfiguration
|
||||||
* @see ReactiveRestClients
|
* @see ReactiveRestClients
|
||||||
@ -430,6 +433,44 @@ public interface ReactiveElasticsearchClient {
|
|||||||
*/
|
*/
|
||||||
Mono<BulkByScrollResponse> deleteBy(HttpHeaders headers, DeleteByQueryRequest deleteRequest);
|
Mono<BulkByScrollResponse> deleteBy(HttpHeaders headers, DeleteByQueryRequest deleteRequest);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a {@link BulkRequest} against the {@literal bulk} API.
|
||||||
|
*
|
||||||
|
* @param consumer never {@literal null}.
|
||||||
|
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html">Bulk
|
||||||
|
* API on elastic.co</a>
|
||||||
|
* @return a {@link Mono} emitting the emitting operation response.
|
||||||
|
*/
|
||||||
|
default Mono<BulkResponse> bulk(Consumer<BulkRequest> consumer) {
|
||||||
|
|
||||||
|
BulkRequest request = new BulkRequest();
|
||||||
|
consumer.accept(request);
|
||||||
|
return bulk(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a {@link BulkRequest} against the {@literal bulk} API.
|
||||||
|
*
|
||||||
|
* @param bulkRequest must not be {@literal null}.
|
||||||
|
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html">Bulk
|
||||||
|
* API on elastic.co</a>
|
||||||
|
* @return a {@link Mono} emitting the emitting operation response.
|
||||||
|
*/
|
||||||
|
default Mono<BulkResponse> bulk(BulkRequest bulkRequest) {
|
||||||
|
return bulk(HttpHeaders.EMPTY, bulkRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a {@link BulkRequest} against the {@literal bulk} API.
|
||||||
|
*
|
||||||
|
* @param headers Use {@link HttpHeaders} to provide eg. authentication data. Must not be {@literal null}.
|
||||||
|
* @param bulkRequest must not be {@literal null}.
|
||||||
|
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html">Bulk
|
||||||
|
* API on elastic.co</a>
|
||||||
|
* @return a {@link Mono} emitting operation response.
|
||||||
|
*/
|
||||||
|
Mono<BulkResponse> bulk(HttpHeaders headers, BulkRequest bulkRequest);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compose the actual command/s to run against Elasticsearch using the underlying {@link WebClient connection}.
|
* Compose the actual command/s to run against Elasticsearch using the underlying {@link WebClient connection}.
|
||||||
* {@link #execute(ReactiveElasticsearchClientCallback) Execute} selects an active server from the available ones and
|
* {@link #execute(ReactiveElasticsearchClientCallback) Execute} selects an active server from the available ones and
|
||||||
|
@ -18,10 +18,12 @@ package org.springframework.data.elasticsearch.client.reactive;
|
|||||||
import static org.assertj.core.api.Assertions.*;
|
import static org.assertj.core.api.Assertions.*;
|
||||||
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
import org.elasticsearch.action.bulk.BulkRequest;
|
||||||
import reactor.test.StepVerifier;
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -65,7 +67,7 @@ import org.springframework.test.context.junit4.SpringRunner;
|
|||||||
/**
|
/**
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @currentRead Fool's Fate - Robin Hobb
|
* @author Henrique Amaral
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringRunner.class)
|
@RunWith(SpringRunner.class)
|
||||||
@ContextConfiguration("classpath:infrastructure.xml")
|
@ContextConfiguration("classpath:infrastructure.xml")
|
||||||
@ -653,6 +655,34 @@ public class ReactiveElasticsearchClientTests {
|
|||||||
.verifyError(ElasticsearchStatusException.class);
|
.verifyError(ElasticsearchStatusException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // DATAES-684
|
||||||
|
public void bulkShouldUpdateExistingDocument() {
|
||||||
|
String idFirstDoc = addSourceDocument().ofType(TYPE_I).to(INDEX_I);
|
||||||
|
String idSecondDoc = addSourceDocument().ofType(TYPE_I).to(INDEX_I);
|
||||||
|
|
||||||
|
UpdateRequest requestFirstDoc = new UpdateRequest(INDEX_I, TYPE_I, idFirstDoc) //
|
||||||
|
.doc(Collections.singletonMap("dutiful", "farseer"));
|
||||||
|
UpdateRequest requestSecondDoc = new UpdateRequest(INDEX_I, TYPE_I, idSecondDoc) //
|
||||||
|
.doc(Collections.singletonMap("secondDocUpdate", "secondDocUpdatePartTwo"));
|
||||||
|
|
||||||
|
BulkRequest bulkRequest = new BulkRequest();
|
||||||
|
bulkRequest.add(requestFirstDoc);
|
||||||
|
bulkRequest.add(requestSecondDoc);
|
||||||
|
|
||||||
|
client.bulk(bulkRequest)
|
||||||
|
.as(StepVerifier::create) //
|
||||||
|
.consumeNextWith(it -> {
|
||||||
|
assertThat(it.status()).isEqualTo(RestStatus.OK);
|
||||||
|
assertThat(it.hasFailures()).isFalse();
|
||||||
|
|
||||||
|
Arrays.stream(it.getItems()).forEach(itemResponse-> {
|
||||||
|
assertThat(itemResponse.status()).isEqualTo(RestStatus.OK);
|
||||||
|
assertThat(itemResponse.getVersion()).isEqualTo(2);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
private AddToIndexOfType addSourceDocument() {
|
private AddToIndexOfType addSourceDocument() {
|
||||||
return add(DOC_SOURCE);
|
return add(DOC_SOURCE);
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@ import static org.mockito.ArgumentMatchers.*;
|
|||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
import static org.springframework.data.elasticsearch.client.reactive.ReactiveMockClientTestsUtils.MockWebClientProvider.Receive.*;
|
import static org.springframework.data.elasticsearch.client.reactive.ReactiveMockClientTestsUtils.MockWebClientProvider.Receive.*;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.bulk.BulkRequest;
|
||||||
|
import org.elasticsearch.rest.RestStatus;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.test.StepVerifier;
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
@ -51,7 +53,7 @@ import org.springframework.util.StreamUtils;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @currentRead Golden Fool - Robin Hobb
|
* @author Henrique Amaral
|
||||||
*/
|
*/
|
||||||
public class ReactiveElasticsearchClientUnitTests {
|
public class ReactiveElasticsearchClientUnitTests {
|
||||||
|
|
||||||
@ -623,4 +625,26 @@ public class ReactiveElasticsearchClientUnitTests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // DATAES-684
|
||||||
|
public void bulkShouldEmitResponseCorrectly() {
|
||||||
|
|
||||||
|
hostProvider.when(HOST) //
|
||||||
|
.receiveBulkOk();
|
||||||
|
|
||||||
|
final UpdateRequest updateRequest = new UpdateRequest("twitter", "doc", "1")
|
||||||
|
.doc(Collections.singletonMap("user", "cstrobl"));
|
||||||
|
final BulkRequest bulkRequest = new BulkRequest();
|
||||||
|
bulkRequest.add(updateRequest);
|
||||||
|
|
||||||
|
client.bulk(bulkRequest)
|
||||||
|
.as(StepVerifier::create) //
|
||||||
|
.consumeNextWith(bulkResponse -> {
|
||||||
|
|
||||||
|
assertThat(bulkResponse.status()).isEqualTo(RestStatus.OK);
|
||||||
|
assertThat(bulkResponse.hasFailures()).isFalse();
|
||||||
|
|
||||||
|
}) //
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,7 @@ import org.springframework.web.util.UriBuilder;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
|
* @author Henrique Amaral
|
||||||
*/
|
*/
|
||||||
public class ReactiveMockClientTestsUtils {
|
public class ReactiveMockClientTestsUtils {
|
||||||
|
|
||||||
@ -361,6 +362,12 @@ public class ReactiveMockClientTestsUtils {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default Receive receiveBulkOk() {
|
||||||
|
|
||||||
|
return receiveJsonFromFile("bulk-ok") //
|
||||||
|
.receive(Receive::ok);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Receive {
|
public interface Receive {
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"took": 30,
|
||||||
|
"errors": false,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"update": {
|
||||||
|
"_index": "twitter",
|
||||||
|
"_type": "doc",
|
||||||
|
"_id": "1",
|
||||||
|
"_version": 2,
|
||||||
|
"result": "updated",
|
||||||
|
"_shards": {
|
||||||
|
"total": 2,
|
||||||
|
"successful": 1,
|
||||||
|
"failed": 0
|
||||||
|
},
|
||||||
|
"_seq_no": 2,
|
||||||
|
"_primary_term": 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user