DATAES-982 - Improve refresh handling.

Original PR: #573.
This commit is contained in:
Peter-Josef Meisch 2020-12-29 13:39:28 +01:00 committed by GitHub
parent 6fd35b56da
commit 90c4a2a4d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 269 additions and 80 deletions

View File

@ -22,28 +22,32 @@ public class TransportClientConfig extends ElasticsearchConfigurationSupport {
@Bean @Bean
public Client elasticsearchClient() throws UnknownHostException { public Client elasticsearchClient() throws UnknownHostException {
Settings settings = Settings.builder().put("cluster.name", "elasticsearch").build(); <1> Settings settings = Settings.builder().put("cluster.name", "elasticsearch").build(); <.>
TransportClient client = new PreBuiltTransportClient(settings); TransportClient client = new PreBuiltTransportClient(settings);
client.addTransportAddress(new TransportAddress(InetAddress.getByName("127.0.0.1"), 9300)); <2> client.addTransportAddress(new TransportAddress(InetAddress.getByName("127.0.0.1"), 9300)); <.>
return client; return client;
} }
@Bean(name = { "elasticsearchOperations", "elasticsearchTemplate" }) @Bean(name = { "elasticsearchOperations", "elasticsearchTemplate" })
public ElasticsearchTemplate elasticsearchTemplate() throws UnknownHostException { public ElasticsearchTemplate elasticsearchTemplate() throws UnknownHostException {
return new ElasticsearchTemplate(elasticsearchClient());
ElasticsearchTemplate template = new ElasticsearchTemplate(elasticsearchClient, elasticsearchConverter);
template.setRefreshPolicy(refreshPolicy()); <.>
return template;
} }
} }
// ... // ...
IndexRequest request = new IndexRequest("spring-data", "elasticsearch", randomID()) IndexRequest request = new IndexRequest("spring-data", "elasticsearch", randomID())
.source(someObject) .source(someObject);
.setRefreshPolicy(IMMEDIATE);
IndexResponse response = client.index(request); IndexResponse response = client.index(request);
---- ----
<1> The `TransportClient` must be configured with the cluster name. <.> The `TransportClient` must be configured with the cluster name.
<2> The host and port to connect the client to. <.> The host and port to connect the client to.
<.> the RefreshPolicy must be set in the `ElasticsearchTemplate` (override `refreshPolicy()` to not use the default)
==== ====
[[elasticsearch.clients.rest]] [[elasticsearch.clients.rest]]
@ -103,39 +107,29 @@ Calls are directly operated on the reactive stack, **not** wrapping async (threa
==== ====
[source,java] [source,java]
---- ----
static class Config { @Configuration
public class ReactiveRestClientConfig extends AbstractReactiveElasticsearchConfiguration {
@Bean @Override
ReactiveElasticsearchClient client() { @Bean
public ReactiveElasticsearchClient reactiveElasticsearchClient() {
ClientConfiguration clientConfiguration = ClientConfiguration.builder() <1> final ClientConfiguration clientConfiguration = ClientConfiguration.builder() <.>
.connectedTo("localhost:9200", "localhost:9291") .connectedTo("localhost:9200") //
.withWebClientConfigurer(webClient -> { <2>
ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder()
.codecs(configurer -> configurer.defaultCodecs()
.maxInMemorySize(-1))
.build(); .build();
return webClient.mutate().exchangeStrategies(exchangeStrategies).build(); return ReactiveRestClients.create(clientConfiguration);
})
.build();
return ReactiveRestClients.create(clientConfiguration); }
}
} }
// ... // ...
Mono<IndexResponse> response = client.index(request -> Mono<IndexResponse> response = client.index(request ->
request.index("spring-data") request.index("spring-data")
.type("elasticsearch")
.id(randomID()) .id(randomID())
.source(singletonMap("feature", "reactive-client")) .source(singletonMap("feature", "reactive-client"));
.setRefreshPolicy(IMMEDIATE);
); );
---- ----
<1> Use the builder to provide cluster addresses, set default `HttpHeaders` or enable SSL. <.> Use the builder to provide cluster addresses, set default `HttpHeaders` or enable SSL.
<2> when configuring a reactive client, the `withWebClientConfigurer` hook can be used to customize the WebClient.
==== ====
NOTE: The ReactiveClient response, especially for search operations, is bound to the `from` (offset) & `size` (limit) options of the request. NOTE: The ReactiveClient response, especially for search operations, is bound to the `from` (offset) & `size` (limit) options of the request.

View File

@ -0,0 +1,32 @@
[[elasticsearch-migration-guide-4.1-4.2]]
= Upgrading from 4.1.x to 4.2.x
This section describes breaking changes from version 4.1.x to 4.2.x and how removed features can be replaced by new introduced features.
[[elasticsearch-migration-guide-4.1-4.2.deprecations]]
== Deprecations
[[elasticsearch-migration-guide-4.1-4.2.removal]]
== Removals
[[elasticsearch-migration-guide-4.1-4.2.breaking-changes]]
== Breaking Changes
=== RefreshPolicy
==== Enum package changed
It was possible in 4.1 to configure the refresh policy for the `ReactiveElasticsearchTemplate` by overriding the method `AbstractReactiveElasticsearchConfiguration.refreshPolicy()` in a custom configuration class. The return value of this method was an instance of the class `org.elasticsearch.action.support.WriteRequest.RefreshPolicy`.
Now the configuration must return `org.springframework.data.elasticsearch.core.RefreshPolicy`. This enum has the same values and triggers the same behaviour as before, so only the `import` statement has to be adjusted.
==== Refresh behaviour
`ElasticsearchOperations` and `ReactiveElasticsearchOperations` now explicitly use the `RefreshPolicy` set on the template for write requests if not null. If the refresh policy is null, then nothing special is done, so the cluster defaults are used. `ElasticsearchOperations` was always using the cluster default before this version.
The provided implementations for `ElasticsearchRepository` and `ReactiveElasticsearchRepository` will do an explicit refresh when the refresh policy is null. This is the same behaviour as in previous versions. If a refresh policy is set, then it will be used by the repositories as well.
==== Refresh configuration
When configuring Spring Data Elasticsearch like described in <<elasticsearch.clients>> by using `ElasticsearchConfigurationSupport`, `AbstractElasticsearchConfiguration` or `AbstractReactiveElasticsearchConfiguration` the refresh policy will be initialized to `null`. Previously the reactive code initialized this to `IMMEDIATE`, now reactive and
non-reactive code show the same behaviour.

View File

@ -6,4 +6,6 @@
include::elasticsearch-migration-guide-3.2-4.0.adoc[] include::elasticsearch-migration-guide-3.2-4.0.adoc[]
include::elasticsearch-migration-guide-4.0-4.1.adoc[] include::elasticsearch-migration-guide-4.0-4.1.adoc[]
include::elasticsearch-migration-guide-4.1-4.2.adoc[]
:leveloffset: -1 :leveloffset: -1

View File

@ -45,6 +45,10 @@ public abstract class AbstractElasticsearchConfiguration extends ElasticsearchCo
@Bean(name = { "elasticsearchOperations", "elasticsearchTemplate" }) @Bean(name = { "elasticsearchOperations", "elasticsearchTemplate" })
public ElasticsearchOperations elasticsearchOperations(ElasticsearchConverter elasticsearchConverter, public ElasticsearchOperations elasticsearchOperations(ElasticsearchConverter elasticsearchConverter,
RestHighLevelClient elasticsearchClient) { RestHighLevelClient elasticsearchClient) {
return new ElasticsearchRestTemplate(elasticsearchClient, elasticsearchConverter);
ElasticsearchRestTemplate template = new ElasticsearchRestTemplate(elasticsearchClient, elasticsearchConverter);
template.setRefreshPolicy(refreshPolicy());
return template;
} }
} }

View File

@ -16,11 +16,11 @@
package org.springframework.data.elasticsearch.config; package org.springframework.data.elasticsearch.config;
import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient; import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations; import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchTemplate; import org.springframework.data.elasticsearch.core.ReactiveElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.RefreshPolicy;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@ -58,13 +58,13 @@ public abstract class AbstractReactiveElasticsearchConfiguration extends Elastic
} }
/** /**
* Set up the write {@link RefreshPolicy}. Default is set to {@link RefreshPolicy#IMMEDIATE}. * Set up the write {@link RefreshPolicy}. Default is set to null to use the cluster defaults..
* *
* @return {@literal null} to use the server defaults. * @return {@literal null} to use the server defaults.
*/ */
@Nullable @Nullable
protected RefreshPolicy refreshPolicy() { protected RefreshPolicy refreshPolicy() {
return RefreshPolicy.IMMEDIATE; return null;
} }
/** /**

View File

@ -28,10 +28,12 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.annotation.Persistent; import org.springframework.data.annotation.Persistent;
import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.core.RefreshPolicy;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions; import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter; import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext; import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -44,8 +46,8 @@ import org.springframework.util.StringUtils;
public class ElasticsearchConfigurationSupport { public class ElasticsearchConfigurationSupport {
@Bean @Bean
public ElasticsearchConverter elasticsearchEntityMapper( public ElasticsearchConverter elasticsearchEntityMapper(SimpleElasticsearchMappingContext elasticsearchMappingContext,
SimpleElasticsearchMappingContext elasticsearchMappingContext, ElasticsearchCustomConversions elasticsearchCustomConversions) { ElasticsearchCustomConversions elasticsearchCustomConversions) {
MappingElasticsearchConverter elasticsearchConverter = new MappingElasticsearchConverter( MappingElasticsearchConverter elasticsearchConverter = new MappingElasticsearchConverter(
elasticsearchMappingContext); elasticsearchMappingContext);
@ -61,7 +63,8 @@ public class ElasticsearchConfigurationSupport {
* @return never {@literal null}. * @return never {@literal null}.
*/ */
@Bean @Bean
public SimpleElasticsearchMappingContext elasticsearchMappingContext(ElasticsearchCustomConversions elasticsearchCustomConversions) { public SimpleElasticsearchMappingContext elasticsearchMappingContext(
ElasticsearchCustomConversions elasticsearchCustomConversions) {
SimpleElasticsearchMappingContext mappingContext = new SimpleElasticsearchMappingContext(); SimpleElasticsearchMappingContext mappingContext = new SimpleElasticsearchMappingContext();
mappingContext.setInitialEntitySet(getInitialEntitySet()); mappingContext.setInitialEntitySet(getInitialEntitySet());
@ -147,4 +150,14 @@ public class ElasticsearchConfigurationSupport {
return initialEntitySet; return initialEntitySet;
} }
/**
* Set up the write {@link RefreshPolicy}. Default is set to null to use the cluster defaults..
*
* @return {@literal null} to use the server defaults.
*/
@Nullable
protected RefreshPolicy refreshPolicy() {
return null;
}
} }

View File

@ -31,6 +31,8 @@ import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.search.MultiSearchRequest; import org.elasticsearch.action.search.MultiSearchRequest;
import org.elasticsearch.action.search.MultiSearchResponse; import org.elasticsearch.action.search.MultiSearchResponse;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.support.WriteRequestBuilder;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.MoreLikeThisQueryBuilder; import org.elasticsearch.index.query.MoreLikeThisQueryBuilder;
import org.elasticsearch.search.suggest.SuggestBuilder; import org.elasticsearch.search.suggest.SuggestBuilder;
@ -82,6 +84,7 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
@Nullable protected RequestFactory requestFactory; @Nullable protected RequestFactory requestFactory;
@Nullable private EntityOperations entityOperations; @Nullable private EntityOperations entityOperations;
@Nullable private EntityCallbacks entityCallbacks; @Nullable private EntityCallbacks entityCallbacks;
@Nullable private RefreshPolicy refreshPolicy;
// region Initialization // region Initialization
protected void initialize(ElasticsearchConverter elasticsearchConverter) { protected void initialize(ElasticsearchConverter elasticsearchConverter) {
@ -130,6 +133,15 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
this.entityCallbacks = entityCallbacks; this.entityCallbacks = entityCallbacks;
} }
public void setRefreshPolicy(@Nullable RefreshPolicy refreshPolicy) {
this.refreshPolicy = refreshPolicy;
}
@Nullable
public RefreshPolicy getRefreshPolicy() {
return refreshPolicy;
}
// endregion // endregion
// region DocumentOperations // region DocumentOperations
@ -308,6 +320,41 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
public abstract List<IndexedObjectInformation> doBulkOperation(List<?> queries, BulkOptions bulkOptions, public abstract List<IndexedObjectInformation> doBulkOperation(List<?> queries, BulkOptions bulkOptions,
IndexCoordinates index); IndexCoordinates index);
/**
* Pre process the write request before it is sent to the server, eg. by setting the
* {@link WriteRequest#setRefreshPolicy(String) refresh policy} if applicable.
*
* @param request must not be {@literal null}.
* @param <R>
* @return the processed {@link WriteRequest}.
*/
protected <R extends WriteRequest<R>> R prepareWriteRequest(R request) {
if (refreshPolicy == null) {
return request;
}
return request.setRefreshPolicy(refreshPolicy.toRequestRefreshPolicy());
}
/**
* Pre process the write request before it is sent to the server, eg. by setting the
* {@link WriteRequest#setRefreshPolicy(String) refresh policy} if applicable.
*
* @param requestBuilder must not be {@literal null}.
* @param <R>
* @return the processed {@link WriteRequest}.
*/
protected <R extends WriteRequestBuilder<R>> R prepareWriteRequestBuilder(R requestBuilder) {
if (refreshPolicy == null) {
return requestBuilder;
}
return requestBuilder.setRefreshPolicy(refreshPolicy.toRequestRefreshPolicy());
}
// endregion // endregion
// region SearchOperations // region SearchOperations
@ -609,6 +656,7 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
} }
private <T> IndexQuery getIndexQuery(T entity) { private <T> IndexQuery getIndexQuery(T entity) {
String id = getEntityId(entity); String id = getEntityId(entity);
if (id != null) { if (id != null) {
@ -618,7 +666,9 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
IndexQueryBuilder builder = new IndexQueryBuilder() // IndexQueryBuilder builder = new IndexQueryBuilder() //
.withId(id) // .withId(id) //
.withObject(entity); .withObject(entity);
SeqNoPrimaryTerm seqNoPrimaryTerm = getEntitySeqNoPrimaryTerm(entity); SeqNoPrimaryTerm seqNoPrimaryTerm = getEntitySeqNoPrimaryTerm(entity);
if (seqNoPrimaryTerm != null) { if (seqNoPrimaryTerm != null) {
builder.withSeqNoPrimaryTerm(seqNoPrimaryTerm); builder.withSeqNoPrimaryTerm(seqNoPrimaryTerm);
} else { } else {
@ -627,9 +677,11 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
} }
String routing = getEntityRouting(entity); String routing = getEntityRouting(entity);
if (routing != null) { if (routing != null) {
builder.withRouting(routing); builder.withRouting(routing);
} }
return builder.build(); return builder.build();
} }

View File

@ -139,7 +139,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
// region DocumentOperations // region DocumentOperations
public String doIndex(IndexQuery query, IndexCoordinates index) { public String doIndex(IndexQuery query, IndexCoordinates index) {
IndexRequest request = requestFactory.indexRequest(query, index); IndexRequest request = prepareWriteRequest(requestFactory.indexRequest(query, index));
IndexResponse indexResponse = execute(client -> client.index(request, RequestOptions.DEFAULT)); IndexResponse indexResponse = execute(client -> client.index(request, RequestOptions.DEFAULT));
// We should call this because we are not going through a mapper. // We should call this because we are not going through a mapper.
@ -197,7 +197,8 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
Assert.notNull(id, "id must not be null"); Assert.notNull(id, "id must not be null");
Assert.notNull(index, "index must not be null"); Assert.notNull(index, "index must not be null");
DeleteRequest request = requestFactory.deleteRequest(elasticsearchConverter.convertId(id), routing, index); DeleteRequest request = prepareWriteRequest(
requestFactory.deleteRequest(elasticsearchConverter.convertId(id), routing, index));
return execute(client -> client.delete(request, RequestOptions.DEFAULT).getId()); return execute(client -> client.delete(request, RequestOptions.DEFAULT).getId());
} }
@ -224,7 +225,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
public List<IndexedObjectInformation> doBulkOperation(List<?> queries, BulkOptions bulkOptions, public List<IndexedObjectInformation> doBulkOperation(List<?> queries, BulkOptions bulkOptions,
IndexCoordinates index) { IndexCoordinates index) {
BulkRequest bulkRequest = requestFactory.bulkRequest(queries, bulkOptions, index); BulkRequest bulkRequest = prepareWriteRequest(requestFactory.bulkRequest(queries, bulkOptions, index));
List<IndexedObjectInformation> indexedObjectInformationList = checkForBulkOperationFailure( List<IndexedObjectInformation> indexedObjectInformationList = checkForBulkOperationFailure(
execute(client -> client.bulk(bulkRequest, RequestOptions.DEFAULT))); execute(client -> client.bulk(bulkRequest, RequestOptions.DEFAULT)));
updateIndexedObjectsWithQueries(queries, indexedObjectInformationList); updateIndexedObjectsWithQueries(queries, indexedObjectInformationList);

View File

@ -147,6 +147,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
public String doIndex(IndexQuery query, IndexCoordinates index) { public String doIndex(IndexQuery query, IndexCoordinates index) {
IndexRequestBuilder indexRequestBuilder = requestFactory.indexRequestBuilder(client, query, index); IndexRequestBuilder indexRequestBuilder = requestFactory.indexRequestBuilder(client, query, index);
indexRequestBuilder = prepareWriteRequestBuilder(indexRequestBuilder);
ActionFuture<IndexResponse> future = indexRequestBuilder.execute(); ActionFuture<IndexResponse> future = indexRequestBuilder.execute();
IndexResponse response; IndexResponse response;
try { try {
@ -211,8 +212,8 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
Assert.notNull(id, "id must not be null"); Assert.notNull(id, "id must not be null");
Assert.notNull(index, "index must not be null"); Assert.notNull(index, "index must not be null");
DeleteRequestBuilder deleteRequestBuilder = requestFactory.deleteRequestBuilder(client, DeleteRequestBuilder deleteRequestBuilder = prepareWriteRequestBuilder(
elasticsearchConverter.convertId(id), routing, index); requestFactory.deleteRequestBuilder(client, elasticsearchConverter.convertId(id), routing, index));
return deleteRequestBuilder.execute().actionGet().getId(); return deleteRequestBuilder.execute().actionGet().getId();
} }
@ -242,9 +243,10 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
public List<IndexedObjectInformation> doBulkOperation(List<?> queries, BulkOptions bulkOptions, public List<IndexedObjectInformation> doBulkOperation(List<?> queries, BulkOptions bulkOptions,
IndexCoordinates index) { IndexCoordinates index) {
BulkRequestBuilder bulkRequest = requestFactory.bulkRequestBuilder(client, queries, bulkOptions, index); BulkRequestBuilder bulkRequestBuilder = requestFactory.bulkRequestBuilder(client, queries, bulkOptions, index);
bulkRequestBuilder = prepareWriteRequestBuilder(bulkRequestBuilder);
final List<IndexedObjectInformation> indexedObjectInformations = checkForBulkOperationFailure( final List<IndexedObjectInformation> indexedObjectInformations = checkForBulkOperationFailure(
bulkRequest.execute().actionGet()); bulkRequestBuilder.execute().actionGet());
updateIndexedObjectsWithQueries(queries, indexedObjectInformations); updateIndexedObjectsWithQueries(queries, indexedObjectInformations);
return indexedObjectInformations; return indexedObjectInformations;
} }

View File

@ -37,7 +37,6 @@ import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.WriteRequest; import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.index.get.GetResult; import org.elasticsearch.index.get.GetResult;
import org.elasticsearch.index.reindex.BulkByScrollResponse; import org.elasticsearch.index.reindex.BulkByScrollResponse;
@ -648,7 +647,7 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
return request; return request;
} }
return request.setRefreshPolicy(refreshPolicy); return request.setRefreshPolicy(refreshPolicy.toRequestRefreshPolicy());
} }
// endregion // endregion

View File

@ -0,0 +1,41 @@
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core;
import org.elasticsearch.action.support.WriteRequest;
/**
* Enum mirroring org.elasticsearch.action.support.WriteRequest.RefreshPolicy to keep Elasticsearch classes out of our
* API.
*
* @author Peter-Josef Meisch
* @since 4.2
*/
public enum RefreshPolicy {
NONE, IMMEDIATE, WAIT_UNTIL;
WriteRequest.RefreshPolicy toRequestRefreshPolicy() {
switch (this) {
case IMMEDIATE:
return WriteRequest.RefreshPolicy.IMMEDIATE;
case WAIT_UNTIL:
return WriteRequest.RefreshPolicy.WAIT_UNTIL;
case NONE:
default:
return WriteRequest.RefreshPolicy.NONE;
}
}
}

View File

@ -958,6 +958,7 @@ class RequestFactory {
throw new ElasticsearchException( throw new ElasticsearchException(
"object or source is null, failed to index the document [id: " + query.getId() + ']'); "object or source is null, failed to index the document [id: " + query.getId() + ']');
} }
if (query.getVersion() != null) { if (query.getVersion() != null) {
indexRequestBuilder.setVersion(query.getVersion()); indexRequestBuilder.setVersion(query.getVersion());
VersionType versionType = retrieveVersionTypeFromPersistentEntity(query.getObject().getClass()); VersionType versionType = retrieveVersionTypeFromPersistentEntity(query.getObject().getClass());
@ -967,9 +968,11 @@ class RequestFactory {
if (query.getSeqNo() != null) { if (query.getSeqNo() != null) {
indexRequestBuilder.setIfSeqNo(query.getSeqNo()); indexRequestBuilder.setIfSeqNo(query.getSeqNo());
} }
if (query.getPrimaryTerm() != null) { if (query.getPrimaryTerm() != null) {
indexRequestBuilder.setIfPrimaryTerm(query.getPrimaryTerm()); indexRequestBuilder.setIfPrimaryTerm(query.getPrimaryTerm());
} }
if (query.getRouting() != null) { if (query.getRouting() != null) {
indexRequestBuilder.setRouting(query.getRouting()); indexRequestBuilder.setRouting(query.getRouting());
} }

View File

@ -15,6 +15,8 @@
*/ */
package org.springframework.data.elasticsearch.core.query; package org.springframework.data.elasticsearch.core.query;
import java.time.Duration;
import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilder;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@ -24,7 +26,8 @@ import org.springframework.lang.Nullable;
* @author Rizwan Idrees * @author Rizwan Idrees
* @author Mohsin Husen * @author Mohsin Husen
* @author Peter-Josef Meisch * @author Peter-Josef Meisch
* @deprecated since 4.0, use {@link Query} implementations and set {@link Query#setScrollTimeInMillis(Long)} and {@link Query#getMaxResults()} * @deprecated since 4.0, use {@link Query} implementations and set {@link Query#setScrollTime(Duration)} and
* {@link Query#getMaxResults()}
*/ */
@Deprecated @Deprecated
public class DeleteQuery { public class DeleteQuery {

View File

@ -38,6 +38,22 @@ public class IndexQuery {
@Nullable private String routing; @Nullable private String routing;
@Nullable private OpType opType; @Nullable private OpType opType;
public IndexQuery() {}
public IndexQuery(@Nullable String id, @Nullable Object object, @Nullable Long version, @Nullable String source,
@Nullable String parentId, @Nullable Long seqNo, @Nullable Long primaryTerm, @Nullable String routing,
@Nullable OpType opType) {
this.id = id;
this.object = object;
this.version = version;
this.source = source;
this.parentId = parentId;
this.seqNo = seqNo;
this.primaryTerm = primaryTerm;
this.routing = routing;
this.opType = opType;
}
@Nullable @Nullable
public String getId() { public String getId() {
return id; return id;

View File

@ -15,6 +15,7 @@
*/ */
package org.springframework.data.elasticsearch.core.query; package org.springframework.data.elasticsearch.core.query;
import org.springframework.data.elasticsearch.core.RefreshPolicy;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
/** /**
@ -37,6 +38,9 @@ public class IndexQueryBuilder {
@Nullable private Long primaryTerm; @Nullable private Long primaryTerm;
@Nullable private String routing; @Nullable private String routing;
@Nullable private IndexQuery.OpType opType; @Nullable private IndexQuery.OpType opType;
@Nullable private RefreshPolicy refreshPolicy;
public IndexQueryBuilder() {}
public IndexQueryBuilder withId(String id) { public IndexQueryBuilder withId(String id) {
this.id = id; this.id = id;
@ -84,16 +88,6 @@ public class IndexQueryBuilder {
} }
public IndexQuery build() { public IndexQuery build() {
IndexQuery indexQuery = new IndexQuery(); return new IndexQuery(id, object, version, source, parentId, seqNo, primaryTerm, routing, opType);
indexQuery.setId(id);
indexQuery.setObject(object);
indexQuery.setParentId(parentId);
indexQuery.setSource(source);
indexQuery.setVersion(version);
indexQuery.setSeqNo(seqNo);
indexQuery.setPrimaryTerm(primaryTerm);
indexQuery.setRouting(routing);
indexQuery.setOpType(opType);
return indexQuery;
} }
} }

View File

@ -27,14 +27,15 @@ import org.elasticsearch.index.query.IdsQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilder;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations; import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.IndexOperations; import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.RefreshPolicy;
import org.springframework.data.elasticsearch.core.SearchHit; import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHitSupport; import org.springframework.data.elasticsearch.core.SearchHitSupport;
import org.springframework.data.elasticsearch.core.SearchHits; import org.springframework.data.elasticsearch.core.SearchHits;
@ -346,10 +347,24 @@ public class SimpleElasticsearchRepository<T, ID> implements ElasticsearchReposi
} }
@Override @Override
@Deprecated
public void refresh() { public void refresh() {
indexOperations.refresh(); indexOperations.refresh();
} }
private void doRefresh() {
RefreshPolicy refreshPolicy = null;
if (operations instanceof AbstractElasticsearchTemplate) {
refreshPolicy = ((AbstractElasticsearchTemplate) operations).getRefreshPolicy();
}
if (refreshPolicy == null) {
indexOperations.refresh();
}
}
// region helper functions
@Nullable @Nullable
protected ID extractIdFromBean(T entity) { protected ID extractIdFromBean(T entity) {
return entityInformation.getId(entity); return entityInformation.getId(entity);
@ -376,6 +391,7 @@ public class SimpleElasticsearchRepository<T, ID> implements ElasticsearchReposi
return new NativeSearchQueryBuilder().withIds(stringIds).build(); return new NativeSearchQueryBuilder().withIds(stringIds).build();
} }
// endregion
// region operations callback // region operations callback
@FunctionalInterface @FunctionalInterface
@ -392,7 +408,7 @@ public class SimpleElasticsearchRepository<T, ID> implements ElasticsearchReposi
@Nullable @Nullable
public <R> R executeAndRefresh(OperationsCallback<R> callback) { public <R> R executeAndRefresh(OperationsCallback<R> callback) {
R result = callback.doWithOperations(operations); R result = callback.doWithOperations(operations);
refresh(); doRefresh();
return result; return result;
} }
// endregion // endregion

View File

@ -16,10 +16,10 @@
package org.springframework.data.elasticsearch.repository.support; package org.springframework.data.elasticsearch.repository.support;
import org.elasticsearch.index.query.IdsQueryBuilder; import org.elasticsearch.index.query.IdsQueryBuilder;
import org.springframework.data.elasticsearch.core.RefreshPolicy;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
import org.reactivestreams.Publisher; import org.reactivestreams.Publisher;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -259,11 +259,10 @@ public class SimpleReactiveElasticsearchRepository<T, ID> implements ReactiveEla
refreshPolicy = ((ReactiveElasticsearchTemplate) operations).getRefreshPolicy(); refreshPolicy = ((ReactiveElasticsearchTemplate) operations).getRefreshPolicy();
} }
if (refreshPolicy == null || refreshPolicy == RefreshPolicy.NONE) { if (refreshPolicy == null) {
return indexOperations.refresh(); return indexOperations.refresh();
} }
return Mono.empty(); return Mono.empty();
} }
} }

View File

@ -37,7 +37,6 @@ import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.MultiGetRequest; import org.elasticsearch.action.get.MultiGetRequest;
import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.get.GetResult; import org.elasticsearch.index.get.GetResult;
@ -86,6 +85,11 @@ public class ReactiveElasticsearchClientIntegrationTests {
public ReactiveElasticsearchClient reactiveElasticsearchClient() { public ReactiveElasticsearchClient reactiveElasticsearchClient() {
return super.reactiveElasticsearchClient(); return super.reactiveElasticsearchClient();
} }
@Override
protected org.springframework.data.elasticsearch.core.RefreshPolicy refreshPolicy() {
return org.springframework.data.elasticsearch.core.RefreshPolicy.IMMEDIATE;
}
} }
static final String INDEX_I = "idx-1-reactive-client-tests"; static final String INDEX_I = "idx-1-reactive-client-tests";
@ -745,7 +749,6 @@ public class ReactiveElasticsearchClientIntegrationTests {
return new IndexRequest(ReactiveElasticsearchClientIntegrationTests.INDEX_I) // return new IndexRequest(ReactiveElasticsearchClientIntegrationTests.INDEX_I) //
.id(UUID.randomUUID().toString()) // .id(UUID.randomUUID().toString()) //
.source(ReactiveElasticsearchClientIntegrationTests.DOC_SOURCE) // .source(ReactiveElasticsearchClientIntegrationTests.DOC_SOURCE) //
.setRefreshPolicy(RefreshPolicy.IMMEDIATE) //
.create(true); .create(true);
} }

View File

@ -153,12 +153,9 @@ public class ReactiveElasticsearchTemplateIntegrationTests {
SampleEntity sampleEntity = randomEntity("foo bar"); SampleEntity sampleEntity = randomEntity("foo bar");
template.save(sampleEntity)// template.save(sampleEntity) //
.as(StepVerifier::create)// .then(indexOperations.refresh()) //
.expectNextCount(1)// .block();
.verifyComplete();
indexOperations.refresh();
template template
.search(new CriteriaQuery(Criteria.where("message").is(sampleEntity.getMessage())), SampleEntity.class, .search(new CriteriaQuery(Criteria.where("message").is(sampleEntity.getMessage())), SampleEntity.class,
@ -842,11 +839,8 @@ public class ReactiveElasticsearchTemplateIntegrationTests {
entity2.rate = 2; entity2.rate = 2;
template.saveAll(Mono.just(Arrays.asList(entity1, entity2)), IndexCoordinates.of(DEFAULT_INDEX)) // template.saveAll(Mono.just(Arrays.asList(entity1, entity2)), IndexCoordinates.of(DEFAULT_INDEX)) //
.as(StepVerifier::create) // .then(indexOperations.refresh()) //
.expectNext(entity1) // .block();
.expectNext(entity2) //
.verifyComplete();
indexOperations.refresh();
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).build(); NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).build();
template.search(searchQuery, SampleEntity.class, IndexCoordinates.of(DEFAULT_INDEX)) // template.search(searchQuery, SampleEntity.class, IndexCoordinates.of(DEFAULT_INDEX)) //

View File

@ -38,7 +38,6 @@ import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.main.MainResponse; import org.elasticsearch.action.main.MainResponse;
import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
import org.elasticsearch.cluster.ClusterName; import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.DeleteByQueryRequest; import org.elasticsearch.index.reindex.DeleteByQueryRequest;
@ -94,7 +93,7 @@ public class ReactiveElasticsearchTemplateUnitTests {
.as(StepVerifier::create) // .as(StepVerifier::create) //
.verifyComplete(); .verifyComplete();
assertThat(captor.getValue().getRefreshPolicy()).isEqualTo(RefreshPolicy.IMMEDIATE); assertThat(captor.getValue().getRefreshPolicy()).isEqualTo(RefreshPolicy.IMMEDIATE.toRequestRefreshPolicy());
} }
@Test // DATAES-504 @Test // DATAES-504
@ -109,7 +108,7 @@ public class ReactiveElasticsearchTemplateUnitTests {
.as(StepVerifier::create) // .as(StepVerifier::create) //
.verifyComplete(); .verifyComplete();
assertThat(captor.getValue().getRefreshPolicy()).isEqualTo(RefreshPolicy.WAIT_UNTIL); assertThat(captor.getValue().getRefreshPolicy()).isEqualTo(RefreshPolicy.WAIT_UNTIL.toRequestRefreshPolicy());
} }
@Test // DATAES-504, DATAES-518 @Test // DATAES-504, DATAES-518
@ -179,7 +178,7 @@ public class ReactiveElasticsearchTemplateUnitTests {
.as(StepVerifier::create) // .as(StepVerifier::create) //
.verifyComplete(); .verifyComplete();
assertThat(captor.getValue().getRefreshPolicy()).isEqualTo(RefreshPolicy.IMMEDIATE); assertThat(captor.getValue().getRefreshPolicy()).isEqualTo(RefreshPolicy.IMMEDIATE.toRequestRefreshPolicy());
} }
@Test // DATAES-504 @Test // DATAES-504
@ -194,7 +193,7 @@ public class ReactiveElasticsearchTemplateUnitTests {
.as(StepVerifier::create) // .as(StepVerifier::create) //
.verifyComplete(); .verifyComplete();
assertThat(captor.getValue().getRefreshPolicy()).isEqualTo(RefreshPolicy.WAIT_UNTIL); assertThat(captor.getValue().getRefreshPolicy()).isEqualTo(RefreshPolicy.WAIT_UNTIL.toRequestRefreshPolicy());
} }
@Test // DATAES-504 @Test // DATAES-504

View File

@ -27,6 +27,7 @@ import org.springframework.data.elasticsearch.client.RestClients;
import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration; import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations; import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.RefreshPolicy;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
/** /**
@ -84,4 +85,9 @@ public class ElasticsearchRestTemplateConfiguration extends AbstractElasticsearc
} }
}; };
} }
@Override
protected RefreshPolicy refreshPolicy() {
return RefreshPolicy.IMMEDIATE;
}
} }

View File

@ -27,6 +27,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.config.ElasticsearchConfigurationSupport; import org.springframework.data.elasticsearch.config.ElasticsearchConfigurationSupport;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.RefreshPolicy;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
/** /**
@ -52,6 +53,15 @@ public class ElasticsearchTemplateConfiguration extends ElasticsearchConfigurati
@Bean(name = { "elasticsearchOperations", "elasticsearchTemplate" }) @Bean(name = { "elasticsearchOperations", "elasticsearchTemplate" })
public ElasticsearchTemplate elasticsearchTemplate(Client elasticsearchClient, public ElasticsearchTemplate elasticsearchTemplate(Client elasticsearchClient,
ElasticsearchConverter elasticsearchConverter) { ElasticsearchConverter elasticsearchConverter) {
return new ElasticsearchTemplate(elasticsearchClient, elasticsearchConverter);
ElasticsearchTemplate template = new ElasticsearchTemplate(elasticsearchClient, elasticsearchConverter);
template.setRefreshPolicy(refreshPolicy());
return template;
}
@Override
protected RefreshPolicy refreshPolicy() {
return RefreshPolicy.IMMEDIATE;
} }
} }

View File

@ -23,6 +23,7 @@ import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient; import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
import org.springframework.data.elasticsearch.client.reactive.ReactiveRestClients; import org.springframework.data.elasticsearch.client.reactive.ReactiveRestClients;
import org.springframework.data.elasticsearch.config.AbstractReactiveElasticsearchConfiguration; import org.springframework.data.elasticsearch.config.AbstractReactiveElasticsearchConfiguration;
import org.springframework.data.elasticsearch.core.RefreshPolicy;
/** /**
* Configuration for Spring Data Elasticsearch Integration Tests using * Configuration for Spring Data Elasticsearch Integration Tests using
@ -52,4 +53,9 @@ public class ReactiveElasticsearchRestTemplateConfiguration extends AbstractReac
.withSocketTimeout(Duration.ofSeconds(20)) // .withSocketTimeout(Duration.ofSeconds(20)) //
.build()); .build());
} }
@Override
protected RefreshPolicy refreshPolicy() {
return RefreshPolicy.IMMEDIATE;
}
} }