Compare commits

...

30 Commits

Author SHA1 Message Date
Jens Schauder
060cab76d5 DATAES-692 - Release version 3.2.3 (Moore SR3). 2019-12-04 14:12:24 +01:00
Jens Schauder
afb8a35eac DATAES-692 - Prepare 3.2.3 (Moore SR3). 2019-12-04 14:11:44 +01:00
Jens Schauder
1c0dd71020 DATAES-692 - Updated changelog. 2019-12-04 14:11:42 +01:00
Jens Schauder
1633668d7f DATAES-691 - Updated changelog. 2019-12-04 12:09:51 +01:00
Peter-Josef Meisch
6756f792c8
DATAES-699 - Fix count implementation.
Original PR: #349
2019-12-01 10:03:56 +01:00
Peter-Josef Meisch
bae4db8a7f DATAES-700 - Enable proxy support for RestClient. 2019-11-30 23:30:59 +01:00
Mark Paluch
c47fd2cfce DATAES-685 - After release cleanups. 2019-11-18 12:42:05 +01:00
Mark Paluch
cb08bb7196 DATAES-685 - Prepare next development iteration. 2019-11-18 12:42:04 +01:00
Mark Paluch
f3500623ff DATAES-685 - Release version 3.2.2 (Moore SR2). 2019-11-18 12:32:12 +01:00
Mark Paluch
4c4cbed43b DATAES-685 - Prepare 3.2.2 (Moore SR2). 2019-11-18 12:31:53 +01:00
Mark Paluch
23fb5689b7 DATAES-685 - Updated changelog. 2019-11-18 12:31:52 +01:00
Mark Paluch
b551466f94 DATAES-683 - Updated changelog. 2019-11-18 12:16:28 +01:00
Peter-Josef Meisch
0a7af69d69 DATAES-680 - Fix missing import. 2019-11-08 17:03:37 +01:00
Peter-Josef Meisch
2cf42a4763 DATAES-680 - ReactiveElasticsearchTemplate-should-use-the-count-API.
Original PR: #341

(cherry picked from commit 62385edaa568e9e3ebbfc56ad59e76ffd72b47f8)
2019-11-07 17:07:39 +01:00
Peter-Josef Meisch
6f0d1ee9e7 DATAES-684 - Polishing.
(cherry picked from commit 24751972a8f266281e948eaf5f73f66003d4b896)
2019-11-05 10:41:21 +01:00
Henrique Amaral
f82dd229d9 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)
2019-11-05 10:39:40 +01:00
Christoph Strobl
3b833f6f63 DATAES-662 - After release cleanups. 2019-11-04 15:34:27 +01:00
Christoph Strobl
2517fd5c90 DATAES-662 - Prepare next development iteration. 2019-11-04 15:34:26 +01:00
Christoph Strobl
4e572679dd DATAES-662 - Release version 3.2.1 (Moore SR1). 2019-11-04 14:55:02 +01:00
Christoph Strobl
de9c664d1e DATAES-662 - Prepare 3.2.1 (Moore SR1). 2019-11-04 14:54:16 +01:00
Christoph Strobl
8187c5362a DATAES-662 - Updated changelog. 2019-11-04 14:54:15 +01:00
Christoph Strobl
a8eb260bbd DATAES-660 - Updated changelog. 2019-11-04 10:34:54 +01:00
Peter-Josef Meisch
bb944f595f
DATAES-679 - Upgrade_to_Elasticsearch_6.8.4.
Original PR: #339
2019-10-31 17:40:24 +01:00
Henrique Amaral
598626238b DATAES-673 Create a Ssl Rest Client using SslContext and HostnameVerifier 2019-10-23 19:22:34 +02:00
Gyula Csörögi
a451f8dca4 DATAES-671 - Missing indicesOptions support for scrolling queries.
Original PR: #332
2019-10-16 09:00:44 +02:00
Peter-Josef Meisch
4fd070c332
DATAES-670 - Fix version compatibility matrix in documentation.
Original PR: #330
2019-10-12 10:42:27 +02:00
Mark Paluch
091413dd69 DATAES-665 - Fix plugin ordering to deploy Javadoc. 2019-10-01 08:39:10 +02:00
Greg Turnquist
ff74425132
DATAES-625 - Create CI job. 2019-09-30 14:23:41 -05:00
Mark Paluch
6f4d1dcc57 DATAES-625 - After release cleanups. 2019-09-30 16:17:54 +02:00
Mark Paluch
9713e33fed DATAES-625 - Prepare next development iteration. 2019-09-30 16:17:53 +02:00
39 changed files with 704 additions and 116 deletions

8
Jenkinsfile vendored
View File

@ -3,7 +3,7 @@ pipeline {
triggers {
pollSCM 'H/10 * * * *'
upstream(upstreamProjects: "spring-data-commons/master", threshold: hudson.model.Result.SUCCESS)
upstream(upstreamProjects: "spring-data-commons/2.2.x", threshold: hudson.model.Result.SUCCESS)
}
options {
@ -15,7 +15,7 @@ pipeline {
stage("Test") {
when {
anyOf {
branch 'master'
branch '3.2.x'
not { triggeredBy 'UpstreamCause' }
}
}
@ -39,7 +39,7 @@ pipeline {
stage('Release to artifactory') {
when {
anyOf {
branch 'master'
branch '3.2.x'
not { triggeredBy 'UpstreamCause' }
}
}
@ -70,7 +70,7 @@ pipeline {
}
stage('Publish documentation') {
when {
branch 'master'
branch '3.2.x'
}
agent {
docker {

46
pom.xml
View File

@ -5,12 +5,12 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>3.2.0.RELEASE</version>
<version>3.2.3.RELEASE</version>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>2.2.0.RELEASE</version>
<version>2.2.3.RELEASE</version>
</parent>
<name>Spring Data Elasticsearch</name>
@ -19,9 +19,9 @@
<properties>
<commonslang>2.6</commonslang>
<elasticsearch>6.8.1</elasticsearch>
<elasticsearch>6.8.4</elasticsearch>
<log4j>2.9.1</log4j>
<springdata.commons>2.2.0.RELEASE</springdata.commons>
<springdata.commons>2.2.3.RELEASE</springdata.commons>
<netty>4.1.39.Final</netty>
<java-module-name>spring.data.elasticsearch</java-module-name>
</properties>
@ -248,6 +248,24 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8</artifactId>
<version>2.25.1</version>
<scope>test</scope>
<exclusions>
<!-- these exclusions are needed because of Elasticsearch JarHell-->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
<exclusion>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Upgrade xbean to 4.5 to prevent incompatibilities due to ASM versions -->
<dependency>
<groupId>org.apache.xbean</groupId>
@ -258,8 +276,8 @@
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>3.0-alpha-1</version>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
@ -267,14 +285,6 @@
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
</plugin>
<!--
please do not remove this configuration for surefire - we need that to avoid issue with jar hell
-->
@ -292,6 +302,14 @@
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

View File

@ -35,8 +35,8 @@ The following table shows the Elasticsearch versions that are used by Spring Dat
[cols="^,^,^,^",options="header"]
|===
|Spring Data Release Train |Spring Data Elasticsearch |Elasticsearch | Spring Boot
|Moorefootnote:cdv[Currently in development] |3.2.xfootnote:cdv[]|6.8.1 / 7.xfootnote:hrc[via the <<elasticsearch.clients.rest,high-level REST client>>]|2.2.0footnote:cdv[]
|Lovelace |3.1.x |6.2.2 / 7.xfootnote:hrc[]|2.1.x
|Moore |3.2.x |6.8.4 |2.2.x
|Lovelace |3.1.x |6.2.2|2.1.x
|Kayfootnote:oom[Out of maintenance]|3.0.xfootnote:oom[] |5.5.0 |2.0.xfootnote:oom[]
|Ingallsfootnote:oom[]|2.1.xfootnote:oom[] |2.4.0 |1.5.xfootnote:oom[]
|===

View File

@ -21,6 +21,7 @@ import java.time.Duration;
import java.util.List;
import java.util.Optional;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import org.springframework.http.HttpHeaders;
@ -30,6 +31,7 @@ import org.springframework.http.HttpHeaders;
*
* @author Mark Paluch
* @author Peter-Josef Meisch
* @author Henrique Amaral
* @since 3.2
*/
public interface ClientConfiguration {
@ -118,6 +120,13 @@ public interface ClientConfiguration {
*/
Optional<SSLContext> getSslContext();
/**
* Returns the {@link HostnameVerifier} to use. Can be {@link Optional#empty()} if unconfigured.
*
* @return the {@link HostnameVerifier} to use. Can be {@link Optional#empty()} if unconfigured.
*/
Optional<HostnameVerifier> getHostNameVerifier();
/**
* Returns the {@link java.time.Duration connect timeout}.
*
@ -135,6 +144,14 @@ public interface ClientConfiguration {
*/
Duration getSocketTimeout();
/**
* returns an optionally set proxy in the form host:port
*
* @return the optional proxy
* @since 4.0
*/
Optional<String> getProxy();
/**
* @author Christoph Strobl
*/
@ -201,6 +218,16 @@ public interface ClientConfiguration {
* @return the {@link TerminalClientConfigurationBuilder}.
*/
TerminalClientConfigurationBuilder usingSsl(SSLContext sslContext);
/**
* Connect via {@literal https} using the givens {@link SSLContext} and HostnameVerifier {@link HostnameVerifier}
* .<br />
* <strong>NOTE</strong> You need to leave out the protocol in
* {@link ClientConfigurationBuilderWithRequiredEndpoint#connectedTo(String)}.
*
* @return the {@link TerminalClientConfigurationBuilder}.
*/
TerminalClientConfigurationBuilder usingSsl(SSLContext sslContext, HostnameVerifier hostnameVerifier);
}
/**
@ -267,6 +294,12 @@ public interface ClientConfiguration {
*/
TerminalClientConfigurationBuilder withBasicAuth(String username, String password);
/**
* @param proxy a proxy formatted as String {@literal host:port}.
* @return the {@link MaybeSecureClientConfigurationBuilder}.
*/
MaybeSecureClientConfigurationBuilder withProxy(String proxy);
/**
* Build the {@link ClientConfiguration} object.
*

View File

@ -22,6 +22,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationBuilderWithRequiredEndpoint;
@ -37,6 +38,7 @@ import org.springframework.util.Assert;
* @author Christoph Strobl
* @author Mark Paluch
* @author Peter-Josef Meisch
* @author Henrique Amaral
* @since 3.2
*/
class ClientConfigurationBuilder
@ -46,10 +48,12 @@ class ClientConfigurationBuilder
private HttpHeaders headers = HttpHeaders.EMPTY;
private boolean useSsl;
private @Nullable SSLContext sslContext;
private @Nullable HostnameVerifier hostnameVerifier;
private Duration connectTimeout = Duration.ofSeconds(10);
private Duration soTimeout = Duration.ofSeconds(5);
private String username;
private String password;
private String proxy;
/*
* (non-Javadoc)
@ -78,6 +82,13 @@ class ClientConfigurationBuilder
return this;
}
@Override
public MaybeSecureClientConfigurationBuilder withProxy(String proxy) {
Assert.hasLength(proxy, "proxy must not be null or empty");
this.proxy = proxy;
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.elasticsearch.client.ClientConfiguration.MaybeSecureClientConfigurationBuilder#usingSsl()
@ -103,6 +114,22 @@ class ClientConfigurationBuilder
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.elasticsearch.client.ClientConfiguration.MaybeSecureClientConfigurationBuilder#usingSsl(javax.net.ssl.SSLContext, javax.net.ssl.HostnameVerifier)
*/
@Override
public TerminalClientConfigurationBuilder usingSsl(SSLContext sslContext, HostnameVerifier hostnameVerifier) {
Assert.notNull(sslContext, "SSL Context must not be null");
Assert.notNull(hostnameVerifier, "Host Name Verifier must not be null");
this.useSsl = true;
this.sslContext = sslContext;
this.hostnameVerifier = hostnameVerifier;
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.elasticsearch.client.ClientConfiguration.TerminalClientConfigurationBuilder#withDefaultHeaders(org.springframework.http.HttpHeaders)
@ -170,8 +197,8 @@ class ClientConfigurationBuilder
headers.setBasicAuth(username, password);
}
return new DefaultClientConfiguration(this.hosts, this.headers, this.useSsl, this.sslContext, this.soTimeout,
this.connectTimeout);
return new DefaultClientConfiguration(hosts, headers, useSsl, sslContext, soTimeout, connectTimeout,
hostnameVerifier, proxy);
}
private static InetSocketAddress parse(String hostAndPort) {

View File

@ -22,6 +22,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Optional;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import org.springframework.http.HttpHeaders;
@ -42,9 +43,12 @@ class DefaultClientConfiguration implements ClientConfiguration {
private final @Nullable SSLContext sslContext;
private final Duration soTimeout;
private final Duration connectTimeout;
private final @Nullable HostnameVerifier hostnameVerifier;
private final String proxy;
DefaultClientConfiguration(List<InetSocketAddress> hosts, HttpHeaders headers, boolean useSsl,
@Nullable SSLContext sslContext, Duration soTimeout, Duration connectTimeout) {
@Nullable SSLContext sslContext, Duration soTimeout, Duration connectTimeout,
@Nullable HostnameVerifier hostnameVerifier, String proxy) {
this.hosts = Collections.unmodifiableList(new ArrayList<>(hosts));
this.headers = new HttpHeaders(headers);
@ -52,6 +56,8 @@ class DefaultClientConfiguration implements ClientConfiguration {
this.sslContext = sslContext;
this.soTimeout = soTimeout;
this.connectTimeout = connectTimeout;
this.hostnameVerifier = hostnameVerifier;
this.proxy = proxy;
}
/*
@ -90,6 +96,15 @@ class DefaultClientConfiguration implements ClientConfiguration {
return Optional.ofNullable(this.sslContext);
}
/*
* (non-Javadoc)
* @see org.springframework.data.elasticsearch.client.ClientConfiguration#getHostNameVerifier()
*/
@Override
public Optional<HostnameVerifier> getHostNameVerifier() {
return Optional.ofNullable(this.hostnameVerifier);
}
/*
* (non-Javadoc)
* @see org.springframework.data.elasticsearch.client.ClientConfiguration#getConnectTimeout()
@ -108,4 +123,12 @@ class DefaultClientConfiguration implements ClientConfiguration {
return this.soTimeout;
}
/*
* (non-Javadoc)
* @see org.springframework.data.elasticsearch.client.ClientConfiguration#getProxy()
*/
@Override
public Optional<String> getProxy() {
return Optional.ofNullable(proxy);
}
}

View File

@ -24,6 +24,7 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import org.apache.http.Header;
@ -52,6 +53,7 @@ import org.springframework.util.Assert;
*
* @author Christoph Strobl
* @author Mark Paluch
* @author Henrique Amaral
* @since 3.2
*/
public final class RestClients {
@ -87,7 +89,9 @@ public final class RestClients {
builder.setHttpClientConfigCallback(clientBuilder -> {
Optional<SSLContext> sslContext = clientConfiguration.getSslContext();
Optional<HostnameVerifier> hostNameVerifier = clientConfiguration.getHostNameVerifier();
sslContext.ifPresent(clientBuilder::setSSLContext);
hostNameVerifier.ifPresent(clientBuilder::setSSLHostnameVerifier);
if (ClientLogger.isEnabled()) {
@ -114,6 +118,8 @@ public final class RestClients {
clientBuilder.setDefaultRequestConfig(requestConfigBuilder.build());
clientConfiguration.getProxy().map(HttpHost::create).ifPresent(clientBuilder::setProxy);
return clientBuilder;
});

View File

@ -47,7 +47,6 @@ import javax.net.ssl.SSLContext;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
@ -58,6 +57,8 @@ import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
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.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
@ -77,6 +78,8 @@ import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.DeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
@ -122,6 +125,7 @@ import org.springframework.web.reactive.function.client.WebClient.RequestBodySpe
*
* @author Christoph Strobl
* @author Mark Paluch
* @author Henrique Amaral
* @since 3.2
* @see ClientConfiguration
* @see ReactiveRestClients
@ -319,6 +323,17 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
.publishNext();
}
/*
* (non-Javadoc)
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#count(org.springframework.http.HttpHeaders, org.elasticsearch.action.search.SearchRequest)
*/
@Override
public Mono<Long> count(HttpHeaders headers, CountRequest countRequest) {
return sendRequest(countRequest, RequestCreator.count(), CountResponse.class, headers) //
.map(CountResponse::getCount) //
.next();
}
/*
* (non-Javadoc)
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#ping(org.springframework.http.HttpHeaders, org.elasticsearch.action.search.SearchRequest)
@ -423,6 +438,16 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
.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
/*
@ -553,13 +578,12 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
// -->
private <Req extends ActionRequest, Resp extends ActionResponse> Flux<Resp> sendRequest(Req request,
Function<Req, Request> converter, Class<Resp> responseType, HttpHeaders headers) {
private <Req extends ActionRequest, Resp> Flux<Resp> sendRequest(Req request, Function<Req, Request> converter,
Class<Resp> responseType, HttpHeaders headers) {
return sendRequest(converter.apply(request), responseType, headers);
}
private <AR extends ActionResponse> Flux<AR> sendRequest(Request request, Class<AR> responseType,
HttpHeaders headers) {
private <Resp> Flux<Resp> sendRequest(Request request, Class<Resp> responseType, HttpHeaders headers) {
String logId = ClientLogger.newLogId();
@ -742,6 +766,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
static Function<GetIndexRequest, Request> indexExists() {
@ -776,6 +812,10 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
return RequestConverters::flushIndex;
}
static Function<CountRequest, Request> count() {
return RequestConverters::count;
}
}
/**

View File

@ -30,6 +30,8 @@ import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
@ -41,6 +43,7 @@ import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.index.get.GetResult;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
@ -58,6 +61,8 @@ import org.springframework.web.reactive.function.client.WebClient;
*
* @author Christoph Strobl
* @author Mark Paluch
* @author Peter-Josef Meisch
* @author Henrique Amaral
* @since 3.2
* @see ClientConfiguration
* @see ReactiveRestClients
@ -329,6 +334,47 @@ public interface ReactiveElasticsearchClient {
*/
Mono<DeleteResponse> delete(HttpHeaders headers, DeleteRequest deleteRequest);
/**
* Execute a {@link SearchRequest} against the {@literal count} API.
*
* @param consumer new {@literal null}.
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-count.html">Count API on
* elastic.co</a>
* @return the {@link Mono} emitting the count result.
* @since 4.0
*/
default Mono<Long> count(Consumer<CountRequest> consumer) {
CountRequest countRequest = new CountRequest();
consumer.accept(countRequest);
return count(countRequest);
}
/**
* Execute a {@link SearchRequest} against the {@literal count} API.
*
* @param countRequest must not be {@literal null}.
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-count.html">Count API on
* elastic.co</a>
* @return the {@link Mono} emitting the count result.
* @since 4.0
*/
default Mono<Long> count(CountRequest countRequest) {
return count(HttpHeaders.EMPTY, countRequest);
}
/**
* Execute a {@link SearchRequest} against the {@literal count} API.
*
* @param headers Use {@link HttpHeaders} to provide eg. authentication data. Must not be {@literal null}.
* @param countRequest must not be {@literal null}.
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-count.html">Count API on
* elastic.co</a>
* @return the {@link Mono} emitting the count result.
* @since 4.0
*/
Mono<Long> count(HttpHeaders headers, CountRequest countRequest);
/**
* Execute a {@link SearchRequest} against the {@literal search} API.
*
@ -430,6 +476,44 @@ public interface ReactiveElasticsearchClient {
*/
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}.
* {@link #execute(ReactiveElasticsearchClientCallback) Execute} selects an active server from the available ones and

View File

@ -60,6 +60,7 @@ import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.RethrottleRequest;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.cluster.health.ClusterHealthStatus;
import org.elasticsearch.common.Priority;
import org.elasticsearch.common.Strings;
@ -98,6 +99,8 @@ import org.springframework.lang.Nullable;
* <p>
* Only intended for internal use.
*
* @author Christoph Strobl
* @author Peter-Josef Meisch
* @since 3.2
*/
public class RequestConverters {
@ -386,6 +389,32 @@ public class RequestConverters {
return request;
}
/**
* Creates a count request.
*
* @param countRequest the search defining the data to be counted
* @return Elasticsearch count request
* @since 4.0
*/
public static Request count(CountRequest countRequest) {
Request request = new Request(HttpMethod.POST.name(),
endpoint(countRequest.indices(), countRequest.types(), "_count"));
Params params = new Params(request);
addCountRequestParams(params, countRequest);
if (countRequest.source() != null) {
request.setEntity(createEntity(countRequest.source(), REQUEST_BODY_CONTENT_TYPE));
}
return request;
}
private static void addCountRequestParams(Params params, CountRequest countRequest) {
params.withRouting(countRequest.routing());
params.withPreference(countRequest.preference());
params.withIndicesOptions(countRequest.indicesOptions());
}
private static void addSearchRequestParams(Params params, SearchRequest searchRequest) {
params.putParam("typed_keys", "true");
params.withRouting(searchRequest.routing());

View File

@ -598,6 +598,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate
if (elasticsearchQuery != null) {
sourceBuilder.query(elasticsearchQuery);
}
sourceBuilder.size(0);
countRequest.source(sourceBuilder);
try {
@ -616,6 +617,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate
if (elasticsearchFilter != null) {
searchRequest.source().postFilter(elasticsearchFilter);
}
searchRequest.source().size(0);
SearchResponse response;
try {
response = client.search(searchRequest, RequestOptions.DEFAULT);
@ -960,6 +962,10 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate
prepareSort(query, searchSourceBuilder, entity);
}
if (query.getIndicesOptions() != null) {
request.indicesOptions(query.getIndicesOptions());
}
if (query instanceof SearchQuery) {
SearchQuery searchQuery = (SearchQuery) query;

View File

@ -508,6 +508,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate
if (elasticsearchQuery != null) {
countRequestBuilder.setQuery(elasticsearchQuery);
}
countRequestBuilder.setSize(0);
return countRequestBuilder.execute().actionGet().getHits().getTotalHits();
}
@ -521,6 +522,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate
if (elasticsearchFilter != null) {
searchRequestBuilder.setPostFilter(elasticsearchFilter);
}
searchRequestBuilder.setSize(0);
return searchRequestBuilder.execute().actionGet().getHits().getTotalHits();
}
@ -810,6 +812,10 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate
prepareSort(query, requestBuilder, entity);
}
if (query.getIndicesOptions() != null) {
requestBuilder.setIndicesOptions(query.getIndicesOptions());
}
if (query instanceof SearchQuery) {
SearchQuery searchQuery = (SearchQuery) query;

View File

@ -36,6 +36,7 @@ import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.index.get.GetResult;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
@ -247,80 +248,133 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
@Nullable String type) {
return Flux.defer(() -> {
SearchRequest request = prepareSearchRequest(buildSearchRequest(query, entity, index, type));
IndexCoordinates indexCoordinates = operations.determineIndex(entity, index, type);
SearchRequest request = new SearchRequest(indices(query, indexCoordinates::getIndexName));
request.types(indexTypes(query, indexCoordinates::getTypeName));
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(mappedQuery(query, entity));
searchSourceBuilder.version(entity.hasVersionProperty());
searchSourceBuilder.trackScores(query.getTrackScores());
QueryBuilder postFilterQuery = mappedFilterQuery(query, entity);
if (postFilterQuery != null) {
searchSourceBuilder.postFilter(postFilterQuery);
}
if (query.getSourceFilter() != null) {
searchSourceBuilder.fetchSource(query.getSourceFilter().getIncludes(), query.getSourceFilter().getExcludes());
}
if (query instanceof SearchQuery && ((SearchQuery) query).getCollapseBuilder() != null) {
searchSourceBuilder.collapse(((SearchQuery) query).getCollapseBuilder());
}
sort(query, entity).forEach(searchSourceBuilder::sort);
if (query.getMinScore() > 0) {
searchSourceBuilder.minScore(query.getMinScore());
}
if (query.getIndicesOptions() != null) {
request.indicesOptions(query.getIndicesOptions());
}
if (query.getPreference() != null) {
request.preference(query.getPreference());
}
if (query.getSearchType() != null) {
request.searchType(query.getSearchType());
}
Pageable pageable = query.getPageable();
if (pageable.isPaged()) {
long offset = pageable.getOffset();
if (offset > Integer.MAX_VALUE) {
throw new IllegalArgumentException(String.format("Offset must not be more than %s", Integer.MAX_VALUE));
}
searchSourceBuilder.from((int) offset);
searchSourceBuilder.size(pageable.getPageSize());
request.source(searchSourceBuilder);
return doFind(prepareSearchRequest(request));
if (query.getPageable().isPaged()) {
return doFind(request);
} else {
request.source(searchSourceBuilder);
return doScan(prepareSearchRequest(request));
return doScroll(request);
}
});
}
@Override
public Mono<Long> count(Query query, Class<?> entityType, String index, String type) {
return doCount(query, getPersistentEntity(entityType), index, type);
}
private Mono<Long> doCount(Query query, ElasticsearchPersistentEntity<?> entity, @Nullable String index,
@Nullable String type) {
return Mono.defer(() -> {
CountRequest countRequest = buildCountRequest(query, entity, index, type);
CountRequest request = prepareCountRequest(countRequest);
return doCount(request);
});
}
private CountRequest buildCountRequest(Query query, ElasticsearchPersistentEntity<?> entity, @Nullable String index,
@Nullable String type) {
IndexCoordinates indexCoordinates = operations.determineIndex(entity, index, type);
CountRequest request = new CountRequest(indices(query, indexCoordinates::getIndexName));
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(mappedQuery(query, entity));
searchSourceBuilder.trackScores(query.getTrackScores());
QueryBuilder postFilterQuery = mappedFilterQuery(query, entity);
if (postFilterQuery != null) {
searchSourceBuilder.postFilter(postFilterQuery);
}
if (query.getSourceFilter() != null) {
searchSourceBuilder.fetchSource(query.getSourceFilter().getIncludes(), query.getSourceFilter().getExcludes());
}
if (query instanceof SearchQuery && ((SearchQuery) query).getCollapseBuilder() != null) {
searchSourceBuilder.collapse(((SearchQuery) query).getCollapseBuilder());
}
sort(query, entity).forEach(searchSourceBuilder::sort);
if (query.getMinScore() > 0) {
searchSourceBuilder.minScore(query.getMinScore());
}
if (query.getIndicesOptions() != null) {
request.indicesOptions(query.getIndicesOptions());
}
if (query.getPreference() != null) {
request.preference(query.getPreference());
}
request.source(searchSourceBuilder);
return request;
}
private SearchRequest buildSearchRequest(Query query, ElasticsearchPersistentEntity<?> entity, @Nullable String index,
@Nullable String type) {
IndexCoordinates indexCoordinates = operations.determineIndex(entity, index, type);
SearchRequest request = new SearchRequest(indices(query, indexCoordinates::getIndexName));
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(mappedQuery(query, entity));
searchSourceBuilder.version(entity.hasVersionProperty());
searchSourceBuilder.trackScores(query.getTrackScores());
QueryBuilder postFilterQuery = mappedFilterQuery(query, entity);
if (postFilterQuery != null) {
searchSourceBuilder.postFilter(postFilterQuery);
}
if (query.getSourceFilter() != null) {
searchSourceBuilder.fetchSource(query.getSourceFilter().getIncludes(), query.getSourceFilter().getExcludes());
}
if (query instanceof SearchQuery && ((SearchQuery) query).getCollapseBuilder() != null) {
searchSourceBuilder.collapse(((SearchQuery) query).getCollapseBuilder());
}
sort(query, entity).forEach(searchSourceBuilder::sort);
if (query.getMinScore() > 0) {
searchSourceBuilder.minScore(query.getMinScore());
}
if (query.getIndicesOptions() != null) {
request.indicesOptions(query.getIndicesOptions());
}
if (query.getPreference() != null) {
request.preference(query.getPreference());
}
if (query.getSearchType() != null) {
request.searchType(query.getSearchType());
}
Pageable pageable = query.getPageable();
if (pageable.isPaged()) {
long offset = pageable.getOffset();
if (offset > Integer.MAX_VALUE) {
throw new IllegalArgumentException(String.format("Offset must not be more than %s", Integer.MAX_VALUE));
}
searchSourceBuilder.from((int) offset);
searchSourceBuilder.size(pageable.getPageSize());
request.source(searchSourceBuilder);
} else {
request.source(searchSourceBuilder);
}
return request;
}
/*
* (non-Javadoc)
* @see org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations#count(Query, Class, String, String)
*/
@Override
public Mono<Long> count(Query query, Class<?> entityType, String index, String type) {
// TODO: ES 7.0 has a dedicated CountRequest - use that one once available.
return find(query, entityType, index, type).count();
}
/*
* (non-Javadoc)
@ -457,6 +511,22 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
return prepareWriteRequest(request);
}
/**
* Customization hook to modify a generated {@link SearchRequest} prior to its execution. Eg. by setting the
* {@link SearchRequest#indicesOptions(IndicesOptions) indices options} if applicable.
*
* @param request the generated {@link CountRequest}.
* @return never {@literal null}.
*/
protected CountRequest prepareCountRequest(CountRequest request) {
if (indicesOptions == null) {
return request;
}
return request.indicesOptions(indicesOptions);
}
/**
* Customization hook to modify a generated {@link SearchRequest} prior to its execution. Eg. by setting the
* {@link SearchRequest#indicesOptions(IndicesOptions) indices options} if applicable.
@ -557,16 +627,32 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
.onErrorResume(NoSuchIndexException.class, it -> Mono.empty());
}
/**
* Customization hook on the actual execution result {@link Publisher}. <br />
*
* @param request the already prepared {@link CountRequest} ready to be executed.
* @return a {@link Mono} emitting the result of the operation.
*/
protected Mono<Long> doCount(CountRequest request) {
if (QUERY_LOGGER.isDebugEnabled()) {
QUERY_LOGGER.debug("Executing doCount: {}", request);
}
return Mono.from(execute(client -> client.count(request))) //
.onErrorResume(NoSuchIndexException.class, it -> Mono.empty());
}
/**
* Customization hook on the actual execution result {@link Publisher}. <br />
*
* @param request the already prepared {@link SearchRequest} ready to be executed.
* @return a {@link Flux} emitting the result of the operation.
*/
protected Flux<SearchHit> doScan(SearchRequest request) {
protected Flux<SearchHit> doScroll(SearchRequest request) {
if (QUERY_LOGGER.isDebugEnabled()) {
QUERY_LOGGER.debug("Executing doScan: {}", request);
QUERY_LOGGER.debug("Executing doScroll: {}", request);
}
return Flux.from(execute(client -> client.scroll(request))) //
@ -665,9 +751,7 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
elasticsearchQuery = new WrapperQueryBuilder(((StringQuery) query).getSource());
} else if (query instanceof NativeSearchQuery) {
elasticsearchQuery = ((NativeSearchQuery) query).getQuery();
}
else {
} else {
throw new IllegalArgumentException(String.format("Unknown query type '%s'.", query.getClass()));
}

View File

@ -1,6 +1,45 @@
Spring Data Elasticsearch Changelog
===================================
Changes in version 3.2.3.RELEASE (2019-12-04)
---------------------------------------------
* DATAES-700 - Enable proxy support for RestClient.
* DATAES-699 - ElasticsearchRestTemplate.count(..) returns all documents instead of just total hits number.
* DATAES-692 - Release 3.2.3 (Moore SR3).
Changes in version 3.1.14.RELEASE (2019-12-04)
----------------------------------------------
* DATAES-691 - Release 3.1.14 (Lovelace SR14).
Changes in version 3.2.2.RELEASE (2019-11-18)
---------------------------------------------
* DATAES-685 - Release 3.2.2 (Moore SR2).
* DATAES-684 - Implement Bulk Request for Reactive.
* DATAES-680 - ReactiveElasticsearchTemplate should use the count API.
Changes in version 3.1.13.RELEASE (2019-11-18)
----------------------------------------------
* DATAES-683 - Release 3.1.13 (Lovelace SR13).
Changes in version 3.2.1.RELEASE (2019-11-04)
---------------------------------------------
* DATAES-679 - Upgrade to Elasticsearch 6.8.4.
* DATAES-673 - Create a Ssl Rest Client using SslContext and HostnameVerifier.
* DATAES-671 - Missing indicesOptions support for scrolling queries.
* DATAES-670 - fix version compatibility matrix in documentation.
* DATAES-665 - Javadoc not deployed.
* DATAES-662 - Release 3.2.1 (Moore SR1).
Changes in version 3.1.12.RELEASE (2019-11-04)
----------------------------------------------
* DATAES-660 - Release 3.1.12 (Lovelace SR12).
Changes in version 3.2.0.RELEASE (2019-09-30)
---------------------------------------------
* DATAES-657 - Sort by _score not supported by ElasticsearchRestTemplate.
@ -883,3 +922,5 @@ Release Notes - Spring Data Elasticsearch - Version 1.0 M1 (2014-02-07)
* #8 - java.lang.NoSuchMethodError: org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty.isVersionProperty()Z
* #7 - Missing core types in org.springframework.data.elasticsearch.annotations.FieldType
* #6 - spirng-data-elasticsearch with elasticsearch-river-mongodb

View File

@ -1,4 +1,4 @@
Spring Data Elasticsearch 3.2 GA
Spring Data Elasticsearch 3.2.3
Copyright (c) [2013-2019] Pivotal Software, Inc.
This product is licensed to you under the Apache License, Version 2.0 (the "License").
@ -8,3 +8,4 @@ This product may include a number of subcomponents with
separate copyright notices and license terms. Your use of the source
code for the these subcomponents is subject to the terms and
conditions of the subcomponent's license, as noted in the LICENSE file.

View File

@ -23,6 +23,7 @@ import java.time.Duration;
import javax.net.ssl.SSLContext;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
@ -31,6 +32,7 @@ import org.springframework.http.HttpHeaders;
*
* @author Mark Paluch
* @author Peter-Josef Meisch
* @author Henrique Amaral
*/
public class ClientConfigurationUnitTests {
@ -42,7 +44,7 @@ public class ClientConfigurationUnitTests {
assertThat(clientConfiguration.getEndpoints()).containsOnly(InetSocketAddress.createUnresolved("localhost", 9200));
}
@Test // DATAES-488, DATAES-504
@Test // DATAES-488, DATAES-504, DATAES-650, DATAES-700
public void shouldCreateCustomizedConfiguration() {
HttpHeaders headers = new HttpHeaders();
@ -52,7 +54,8 @@ public class ClientConfigurationUnitTests {
.connectedTo("foo", "bar") //
.usingSsl() //
.withDefaultHeaders(headers) //
.withConnectTimeout(Duration.ofDays(1)).withSocketTimeout(Duration.ofDays(2)).build();
.withConnectTimeout(Duration.ofDays(1)).withSocketTimeout(Duration.ofDays(2)) //
.withProxy("localhost:8080").build();
assertThat(clientConfiguration.getEndpoints()).containsOnly(InetSocketAddress.createUnresolved("foo", 9200),
InetSocketAddress.createUnresolved("bar", 9200));
@ -60,6 +63,7 @@ public class ClientConfigurationUnitTests {
assertThat(clientConfiguration.getDefaultHeaders().get("foo")).containsOnly("bar");
assertThat(clientConfiguration.getConnectTimeout()).isEqualTo(Duration.ofDays(1));
assertThat(clientConfiguration.getSocketTimeout()).isEqualTo(Duration.ofDays(2));
assertThat(clientConfiguration.getProxy()).contains("localhost:8080");
}
@Test // DATAES-488, DATAES-504
@ -117,6 +121,25 @@ public class ClientConfigurationUnitTests {
assertThat(defaultHeaders.get(HttpHeaders.AUTHORIZATION)).isNull();
}
@Test // DATAES-673
public void shouldCreateSslConfigurationWithHostnameVerifier() {
SSLContext sslContext = mock(SSLContext.class);
ClientConfiguration clientConfiguration = ClientConfiguration.builder() //
.connectedTo("foo", "bar") //
.usingSsl(sslContext, NoopHostnameVerifier.INSTANCE) //
.build();
assertThat(clientConfiguration.getEndpoints()).containsOnly(InetSocketAddress.createUnresolved("foo", 9200),
InetSocketAddress.createUnresolved("bar", 9200));
assertThat(clientConfiguration.useSsl()).isTrue();
assertThat(clientConfiguration.getSslContext()).contains(sslContext);
assertThat(clientConfiguration.getConnectTimeout()).isEqualTo(Duration.ofSeconds(10));
assertThat(clientConfiguration.getSocketTimeout()).isEqualTo(Duration.ofSeconds(5));
assertThat(clientConfiguration.getHostNameVerifier()).contains(NoopHostnameVerifier.INSTANCE);
}
private static String buildBasicAuth(String username, String password) {
HttpHeaders headers = new HttpHeaders();

View File

@ -0,0 +1,48 @@
package org.springframework.data.elasticsearch.client;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import java.io.IOException;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import org.junit.Test;
/**
* @author Peter-Josef Meisch
*/
public class RestClientsTest {
@Test
// DATAES-700
public void shouldUseConfiguredProxy() throws IOException {
WireMockServer wireMockServer = new WireMockServer(options() //
.dynamicPort() //
.usingFilesUnderDirectory("src/test/resources/wiremock-mappings")); // needed, otherwise Wiremock goes to
// test/resources/mappings
wireMockServer.start();
try {
WireMock.configureFor(wireMockServer.port());
ClientConfigurationBuilder configurationBuilder = new ClientConfigurationBuilder();
ClientConfiguration clientConfiguration = configurationBuilder //
.connectedTo("localhost:9200")//
.withProxy("localhost:" + wireMockServer.port()) //
.build();
RestHighLevelClient restClient = RestClients.create(clientConfiguration).rest();
restClient.ping(RequestOptions.DEFAULT);
verify(headRequestedFor(urlEqualTo("/")));
} finally {
wireMockServer.shutdown();
}
}
}

View File

@ -22,6 +22,7 @@ import reactor.test.StepVerifier;
import java.io.IOException;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
@ -32,6 +33,7 @@ import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.Version;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.MultiGetRequest;
@ -65,7 +67,7 @@ import org.springframework.test.context.junit4.SpringRunner;
/**
* @author Christoph Strobl
* @author Mark Paluch
* @currentRead Fool's Fate - Robin Hobb
* @author Henrique Amaral
*/
@RunWith(SpringRunner.class)
@ContextConfiguration("classpath:infrastructure.xml")
@ -653,6 +655,32 @@ public class ReactiveElasticsearchClientTests {
.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() {
return add(DOC_SOURCE);
}

View File

@ -20,6 +20,7 @@ import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import static org.springframework.data.elasticsearch.client.reactive.ReactiveMockClientTestsUtils.MockWebClientProvider.Receive.*;
import org.elasticsearch.rest.RestStatus;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
@ -29,6 +30,7 @@ import java.util.Collections;
import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.action.DocWriteResponse.Result;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.MultiGetRequest;
@ -51,7 +53,7 @@ import org.springframework.util.StreamUtils;
/**
* @author Christoph Strobl
* @currentRead Golden Fool - Robin Hobb
* @author Henrique Amaral
*/
public class ReactiveElasticsearchClientUnitTests {
@ -623,4 +625,25 @@ 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();
}
}

View File

@ -60,6 +60,7 @@ import org.springframework.web.util.UriBuilder;
/**
* @author Christoph Strobl
* @author Henrique Amaral
*/
public class ReactiveMockClientTestsUtils {
@ -361,6 +362,12 @@ public class ReactiveMockClientTestsUtils {
});
}
default Receive receiveBulkOk() {
return receiveJsonFromFile("bulk-ok") //
.receive(Receive::ok);
}
}
public interface Receive {

View File

@ -1709,6 +1709,44 @@ public class ElasticsearchTemplateTests {
elasticsearchTemplate.clearScroll(scroll.getScrollId());
}
@Test // DATAES-671
public void shouldPassIndicesOptionsForGivenSearchScrollQuery() {
// given
long scrollTimeInMillis = 3000;
String documentId = randomNumeric(5);
SampleEntity sampleEntity = SampleEntity.builder().id(documentId).message("some message")
.version(System.currentTimeMillis()).build();
IndexQuery idxQuery = new IndexQueryBuilder().withIndexName(INDEX_1_NAME).withId(sampleEntity.getId())
.withObject(sampleEntity).build();
elasticsearchTemplate.index(idxQuery);
elasticsearchTemplate.refresh(INDEX_1_NAME);
// when
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery())
.withIndices(INDEX_1_NAME, INDEX_2_NAME).withIndicesOptions(IndicesOptions.lenientExpandOpen()).build();
List<SampleEntity> entities = new ArrayList<>();
ScrolledPage<SampleEntity> scroll = elasticsearchTemplate.startScroll(scrollTimeInMillis, searchQuery,
SampleEntity.class, searchResultMapper);
entities.addAll(scroll.getContent());
while (scroll.hasContent()) {
scroll = elasticsearchTemplate.continueScroll(scroll.getScrollId(), scrollTimeInMillis, SampleEntity.class,
searchResultMapper);
entities.addAll(scroll.getContent());
}
// then
assertThat(entities).isNotNull();
assertThat(entities.size()).isGreaterThanOrEqualTo(1);
}
@Test // DATAES-479
public void shouldHonorTheHighlightBuilderOptions() {

View File

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

View File

@ -20,7 +20,7 @@
description=Adds "built in" analyzers to Elasticsearch.
#
# 'version': plugin's version
version=6.8.1
version=6.8.4
#
# 'name': the plugin name
name=analysis-common
@ -35,7 +35,7 @@ classname=org.elasticsearch.analysis.common.CommonAnalysisPlugin
java.version=1.8
#
# 'elasticsearch.version': version of elasticsearch compiled against
elasticsearch.version=6.8.1
elasticsearch.version=6.8.4
### optional elements for plugins:
#
# 'extended.plugins': other plugins this plugin extends through SPI

View File

@ -20,7 +20,7 @@
description=Module for ingest processors that do not require additional security permissions or have large dependencies and resources
#
# 'version': plugin's version
version=6.8.1
version=6.8.4
#
# 'name': the plugin name
name=ingest-common
@ -35,7 +35,7 @@ classname=org.elasticsearch.ingest.common.IngestCommonPlugin
java.version=1.8
#
# 'elasticsearch.version': version of elasticsearch compiled against
elasticsearch.version=6.8.1
elasticsearch.version=6.8.4
### optional elements for plugins:
#
# 'extended.plugins': other plugins this plugin extends through SPI

View File

@ -20,7 +20,7 @@
description=Lucene expressions integration for Elasticsearch
#
# 'version': plugin's version
version=6.8.1
version=6.8.4
#
# 'name': the plugin name
name=lang-expression
@ -35,7 +35,7 @@ classname=org.elasticsearch.script.expression.ExpressionPlugin
java.version=1.8
#
# 'elasticsearch.version': version of elasticsearch compiled against
elasticsearch.version=6.8.1
elasticsearch.version=6.8.4
### optional elements for plugins:
#
# 'extended.plugins': other plugins this plugin extends through SPI

View File

@ -20,7 +20,7 @@
description=An easy, safe and fast scripting language for Elasticsearch
#
# 'version': plugin's version
version=6.8.1
version=6.8.4
#
# 'name': the plugin name
name=lang-painless
@ -35,7 +35,7 @@ classname=org.elasticsearch.painless.PainlessPlugin
java.version=1.8
#
# 'elasticsearch.version': version of elasticsearch compiled against
elasticsearch.version=6.8.1
elasticsearch.version=6.8.4
### optional elements for plugins:
#
# 'extended.plugins': other plugins this plugin extends through SPI

View File

@ -20,7 +20,7 @@
description=Adds advanced field mappers
#
# 'version': plugin's version
version=6.8.1
version=6.8.4
#
# 'name': the plugin name
name=mapper-extras
@ -35,7 +35,7 @@ classname=org.elasticsearch.index.mapper.MapperExtrasPlugin
java.version=1.8
#
# 'elasticsearch.version': version of elasticsearch compiled against
elasticsearch.version=6.8.1
elasticsearch.version=6.8.4
### optional elements for plugins:
#
# 'extended.plugins': other plugins this plugin extends through SPI

View File

@ -20,7 +20,7 @@
description=The Reindex module adds APIs to reindex from one index to another or update documents in place.
#
# 'version': plugin's version
version=6.8.1
version=6.8.4
#
# 'name': the plugin name
name=reindex
@ -35,7 +35,7 @@ classname=org.elasticsearch.index.reindex.ReindexPlugin
java.version=1.8
#
# 'elasticsearch.version': version of elasticsearch compiled against
elasticsearch.version=6.8.1
elasticsearch.version=6.8.4
### optional elements for plugins:
#
# 'extended.plugins': other plugins this plugin extends through SPI

View File

@ -20,7 +20,7 @@
description=Module for URL repository
#
# 'version': plugin's version
version=6.8.1
version=6.8.4
#
# 'name': the plugin name
name=repository-url
@ -35,7 +35,7 @@ classname=org.elasticsearch.plugin.repository.url.URLRepositoryPlugin
java.version=1.8
#
# 'elasticsearch.version': version of elasticsearch compiled against
elasticsearch.version=6.8.1
elasticsearch.version=6.8.4
### optional elements for plugins:
#
# 'extended.plugins': other plugins this plugin extends through SPI