Add new Elasticsearch client as an alternative to the existing REST client.

Original Pull Request #2160
Closes #1973

(cherry picked from commit c0b26a51f1299fdc20998cc54c82ffbc7c005dae)
This commit is contained in:
Peter-Josef Meisch 2022-05-12 07:32:39 +02:00
parent 0950dd6c7a
commit a86658c397
No known key found for this signature in database
GPG Key ID: DE108246970C7708
26 changed files with 329 additions and 138 deletions

View File

@ -31,6 +31,7 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.springframework.data.elasticsearch.core.convert.GeoConverters; import org.springframework.data.elasticsearch.core.convert.GeoConverters;
@ -67,9 +68,13 @@ class CriteriaFilterProcessor {
for (Criteria chainedCriteria : criteria.getCriteriaChain()) { for (Criteria chainedCriteria : criteria.getCriteriaChain()) {
if (chainedCriteria.isOr()) { if (chainedCriteria.isOr()) {
// todo #1973 BoolQuery.Builder boolQueryBuilder = QueryBuilders.bool();
queriesForEntries(chainedCriteria).forEach(boolQueryBuilder::should);
filterQueries.add(new Query(boolQueryBuilder.build()));
} else if (chainedCriteria.isNegating()) { } else if (chainedCriteria.isNegating()) {
// todo #1973 Collection<? extends Query> negatingFilters = buildNegatingFilter(criteria.getField().getName(),
criteria.getFilterCriteriaEntries());
filterQueries.addAll(negatingFilters);
} else { } else {
filterQueries.addAll(queriesForEntries(chainedCriteria)); filterQueries.addAll(queriesForEntries(chainedCriteria));
} }
@ -85,11 +90,28 @@ class CriteriaFilterProcessor {
BoolQuery.Builder boolQueryBuilder = QueryBuilders.bool(); BoolQuery.Builder boolQueryBuilder = QueryBuilders.bool();
filterQueries.forEach(boolQueryBuilder::must); filterQueries.forEach(boolQueryBuilder::must);
BoolQuery boolQuery = boolQueryBuilder.build(); BoolQuery boolQuery = boolQueryBuilder.build();
return Optional.of(boolQuery._toQuery()); return Optional.of(new Query(boolQuery));
} }
} }
} }
private static Collection<? extends Query> buildNegatingFilter(String fieldName,
Set<Criteria.CriteriaEntry> filterCriteriaEntries) {
List<Query> negationFilters = new ArrayList<>();
filterCriteriaEntries.forEach(criteriaEntry -> {
Optional<Query> query = queryFor(criteriaEntry.getKey(), criteriaEntry.getValue(), fieldName);
if (query.isPresent()) {
BoolQuery negatingFilter = QueryBuilders.bool().mustNot(query.get()).build();
negationFilters.add(new Query(negatingFilter));
}
});
return negationFilters;
}
private static Collection<? extends Query> queriesForEntries(Criteria criteria) { private static Collection<? extends Query> queriesForEntries(Criteria criteria) {
Assert.notNull(criteria.getField(), "criteria must have a field"); Assert.notNull(criteria.getField(), "criteria must have a field");

View File

@ -80,8 +80,7 @@ final class DocumentAdapters {
Explanation explanation = from(hit.explanation()); Explanation explanation = from(hit.explanation());
// todo #1973 matchedQueries List<String> matchedQueries = hit.matchedQueries();
List<String> matchedQueries = null;
Function<Map<String, JsonData>, EntityAsMap> fromFields = fields -> { Function<Map<String, JsonData>, EntityAsMap> fromFields = fields -> {
StringBuilder sb = new StringBuilder("{"); StringBuilder sb = new StringBuilder("{");

View File

@ -106,7 +106,6 @@ public class ElasticsearchExceptionTranslator implements PersistenceExceptionTra
} }
private boolean isSeqNoConflict(Throwable exception) { private boolean isSeqNoConflict(Throwable exception) {
// todo #1973 check if this works
Integer status = null; Integer status = null;
String message = null; String message = null;

View File

@ -34,6 +34,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.elasticsearch.BulkFailureException; import org.springframework.data.elasticsearch.BulkFailureException;
import org.springframework.data.elasticsearch.client.UnsupportedBackendOperation; import org.springframework.data.elasticsearch.client.UnsupportedBackendOperation;
import org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate; import org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate;
@ -68,6 +70,8 @@ import org.springframework.util.Assert;
*/ */
public class ElasticsearchTemplate extends AbstractElasticsearchTemplate { public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
private static final Log LOGGER = LogFactory.getLog(ElasticsearchTemplate.class);
private final ElasticsearchClient client; private final ElasticsearchClient client;
private final RequestConverter requestConverter; private final RequestConverter requestConverter;
private final ResponseConverter responseConverter; private final ResponseConverter responseConverter;
@ -249,7 +253,6 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
client -> client.reindex(reindexRequestES)); client -> client.reindex(reindexRequestES));
if (reindexResponse.task() == null) { if (reindexResponse.task() == null) {
// todo #1973 check behaviour and create issue in ES if necessary
throw new UnsupportedBackendOperation("ElasticsearchClient did not return a task id on submit request"); throw new UnsupportedBackendOperation("ElasticsearchClient did not return a task id on submit request");
} }
@ -447,9 +450,6 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
MultiSearchQueryParameter queryParameter = queryIterator.next(); MultiSearchQueryParameter queryParameter = queryIterator.next();
MultiSearchResponseItem<EntityAsMap> responseItem = responseIterator.next(); MultiSearchResponseItem<EntityAsMap> responseItem = responseIterator.next();
// if responseItem kind is Result then responseItem.value is a MultiSearchItem which is derived from
// SearchResponse
if (responseItem.isResult()) { if (responseItem.isResult()) {
Class clazz = queryParameter.clazz; Class clazz = queryParameter.clazz;
@ -463,7 +463,10 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
searchHitsList.add(searchHits); searchHitsList.add(searchHits);
} else { } else {
// todo #1973 add failure if (LOGGER.isWarnEnabled()) {
LOGGER
.warn(String.format("multisearch responsecontains failure: {}", responseItem.failure().error().reason()));
}
} }
} }

View File

@ -87,10 +87,6 @@ class HighlightQueryBuilder {
builder.boundaryScannerLocale(parameters.getBoundaryScannerLocale()); builder.boundaryScannerLocale(parameters.getBoundaryScannerLocale());
} }
if (parameters.getForceSource()) { // default is false
// todo #1973 parameter missing in new client
}
if (StringUtils.hasLength(parameters.getFragmenter())) { if (StringUtils.hasLength(parameters.getFragmenter())) {
builder.fragmenter(highlighterFragmenter(parameters.getFragmenter())); builder.fragmenter(highlighterFragmenter(parameters.getFragmenter()));
} }
@ -111,10 +107,6 @@ class HighlightQueryBuilder {
builder.order(highlighterOrder(parameters.getOrder())); builder.order(highlighterOrder(parameters.getOrder()));
} }
if (parameters.getPhraseLimit() > -1) {
// todo #1973 parameter missing in new client
}
if (parameters.getPreTags().length > 0) { if (parameters.getPreTags().length > 0) {
builder.preTags(Arrays.asList(parameters.getPreTags())); builder.preTags(Arrays.asList(parameters.getPreTags()));
} }

View File

@ -17,6 +17,7 @@ package org.springframework.data.elasticsearch.client.elc;
import co.elastic.clients.elasticsearch._types.FieldValue; import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.LatLonGeoLocation; import co.elastic.clients.elasticsearch._types.LatLonGeoLocation;
import co.elastic.clients.elasticsearch._types.query_dsl.IdsQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchAllQuery; import co.elastic.clients.elasticsearch._types.query_dsl.MatchAllQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchQuery; import co.elastic.clients.elasticsearch._types.query_dsl.MatchQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Operator; import co.elastic.clients.elasticsearch._types.query_dsl.Operator;
@ -29,6 +30,7 @@ import co.elastic.clients.util.ObjectBuilder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Base64; import java.util.Base64;
import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import org.springframework.data.elasticsearch.core.geo.GeoPoint; import org.springframework.data.elasticsearch.core.geo.GeoPoint;
@ -45,6 +47,21 @@ public final class QueryBuilders {
private QueryBuilders() {} private QueryBuilders() {}
public static IdsQuery idsQuery(List<String> ids) {
Assert.notNull(ids, "ids must not be null");
return IdsQuery.of(i -> i.values(ids));
}
public static Query idsQueryAsQuery(List<String> ids) {
Assert.notNull(ids, "ids must not be null");
Function<Query.Builder, ObjectBuilder<Query>> builder = b -> b.ids(idsQuery(ids));
return builder.apply(new Query.Builder()).build();
}
public static MatchQuery matchQuery(String fieldName, String query, @Nullable Operator operator, public static MatchQuery matchQuery(String fieldName, String query, @Nullable Operator operator,
@Nullable Float boost) { @Nullable Float boost) {

View File

@ -177,8 +177,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
return Mono.from(execute( // return Mono.from(execute( //
(ClientCallback<Publisher<co.elastic.clients.elasticsearch.core.ReindexResponse>>) client -> client (ClientCallback<Publisher<co.elastic.clients.elasticsearch.core.ReindexResponse>>) client -> client
.reindex(reindexRequestES))) .reindex(reindexRequestES)))
.flatMap(response -> (response.task() == null) ? Mono.error( // todo #1973 check behaviour and create issue in .flatMap(response -> (response.task() == null) ? Mono.error(
// ES if necessary
new UnsupportedBackendOperation("ElasticsearchClient did not return a task id on submit request")) new UnsupportedBackendOperation("ElasticsearchClient did not return a task id on submit request"))
: Mono.just(response.task())); : Mono.just(response.task()));
} }
@ -499,7 +498,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
@Override @Override
public Query idsQuery(List<String> ids) { public Query idsQuery(List<String> ids) {
throw new UnsupportedOperationException("not implemented"); return NativeQuery.builder().withQuery(QueryBuilders.idsQueryAsQuery(ids)).build();
} }
/** /**

View File

@ -58,6 +58,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
@ -192,7 +193,7 @@ class RequestConverter {
if (filterQuery != null) { if (filterQuery != null) {
elasticsearchConverter.updateQuery(filterQuery, parameters.getFilterQueryClass()); elasticsearchConverter.updateQuery(filterQuery, parameters.getFilterQueryClass());
co.elastic.clients.elasticsearch._types.query_dsl.Query esQuery = getFilter(filterQuery); co.elastic.clients.elasticsearch._types.query_dsl.Query esQuery = getQuery(filterQuery, null);
if (esQuery != null) { if (esQuery != null) {
addActionBuilder.filter(esQuery); addActionBuilder.filter(esQuery);
@ -239,7 +240,8 @@ class RequestConverter {
PutMappingRequest.Builder builder = new PutMappingRequest.Builder(); PutMappingRequest.Builder builder = new PutMappingRequest.Builder();
builder.index(Arrays.asList(indexCoordinates.getIndexNames())); builder.index(Arrays.asList(indexCoordinates.getIndexNames()));
addPropertiesToMapping(builder, mapping); addPropertiesToMapping(builder, mapping);
// TODO #1973 what else to add
// TODO #2155 what else to add
return builder.build(); return builder.build();
} }
@ -374,7 +376,7 @@ class RequestConverter {
Query filterQuery = parameters.getFilterQuery(); Query filterQuery = parameters.getFilterQuery();
if (filterQuery != null) { if (filterQuery != null) {
co.elastic.clients.elasticsearch._types.query_dsl.Query esQuery = getFilter(filterQuery); co.elastic.clients.elasticsearch._types.query_dsl.Query esQuery = getQuery(filterQuery, null);
if (esQuery != null) { if (esQuery != null) {
aliasBuilder.filter(esQuery); aliasBuilder.filter(esQuery);
@ -475,7 +477,7 @@ class RequestConverter {
} }
} }
builder.refresh(refresh(refreshPolicy)); builder.refresh(TypeUtils.refresh(refreshPolicy));
return builder.build(); return builder.build();
} }
@ -644,9 +646,9 @@ class RequestConverter {
builder.timeout(tb -> tb.time(Long.valueOf(bulkOptions.getTimeout().toMillis()).toString() + "ms")); builder.timeout(tb -> tb.time(Long.valueOf(bulkOptions.getTimeout().toMillis()).toString() + "ms"));
} }
builder.refresh(refresh(refreshPolicy)); builder.refresh(TypeUtils.refresh(refreshPolicy));
if (bulkOptions.getRefreshPolicy() != null) { if (bulkOptions.getRefreshPolicy() != null) {
builder.refresh(refresh(bulkOptions.getRefreshPolicy())); builder.refresh(TypeUtils.refresh(bulkOptions.getRefreshPolicy()));
} }
if (bulkOptions.getWaitForActiveShards() != null) { if (bulkOptions.getWaitForActiveShards() != null) {
@ -791,13 +793,13 @@ class RequestConverter {
ReindexRequest.Dest dest = reindexRequest.getDest(); ReindexRequest.Dest dest = reindexRequest.getDest();
return d // return d //
.index(dest.getIndex().getIndexName()) // .index(dest.getIndex().getIndexName()) //
.versionType(versionType(dest.getVersionType())) // .versionType(TypeUtils.versionType(dest.getVersionType())) //
.opType(opType(dest.getOpType())); .opType(TypeUtils.opType(dest.getOpType()));
} // } //
); );
if (reindexRequest.getConflicts() != null) { if (reindexRequest.getConflicts() != null) {
builder.conflicts(conflicts(reindexRequest.getConflicts())); builder.conflicts(TypeUtils.conflicts(reindexRequest.getConflicts()));
} }
ReindexRequest.Script script = reindexRequest.getScript(); ReindexRequest.Script script = reindexRequest.getScript();
@ -810,7 +812,7 @@ class RequestConverter {
if (reindexRequest.getWaitForActiveShards() != null) { if (reindexRequest.getWaitForActiveShards() != null) {
builder.waitForActiveShards(wfas -> wfas // builder.waitForActiveShards(wfas -> wfas //
.count(waitForActiveShardsCount(reindexRequest.getWaitForActiveShards()))); .count(TypeUtils.waitForActiveShardsCount(reindexRequest.getWaitForActiveShards())));
} }
builder // builder //
@ -835,7 +837,7 @@ class RequestConverter {
if (routing != null) { if (routing != null) {
r.routing(routing); r.routing(routing);
} }
r.refresh(refresh(refreshPolicy)); r.refresh(TypeUtils.refresh(refreshPolicy));
return r; return r;
}); });
} }
@ -908,7 +910,7 @@ class RequestConverter {
.docAsUpsert(query.getDocAsUpsert()) // .docAsUpsert(query.getDocAsUpsert()) //
.ifSeqNo(query.getIfSeqNo() != null ? Long.valueOf(query.getIfSeqNo()) : null) // .ifSeqNo(query.getIfSeqNo() != null ? Long.valueOf(query.getIfSeqNo()) : null) //
.ifPrimaryTerm(query.getIfPrimaryTerm() != null ? Long.valueOf(query.getIfPrimaryTerm()) : null) // .ifPrimaryTerm(query.getIfPrimaryTerm() != null ? Long.valueOf(query.getIfPrimaryTerm()) : null) //
.refresh(refresh(refreshPolicy)) // .refresh(TypeUtils.refresh(refreshPolicy)) //
.retryOnConflict(query.getRetryOnConflict()) // .retryOnConflict(query.getRetryOnConflict()) //
; ;
@ -993,7 +995,7 @@ class RequestConverter {
} }
if (updateQuery.getWaitForActiveShards() != null) { if (updateQuery.getWaitForActiveShards() != null) {
ub.waitForActiveShards(w -> w.count(waitForActiveShardsCount(updateQuery.getWaitForActiveShards()))); ub.waitForActiveShards(w -> w.count(TypeUtils.waitForActiveShardsCount(updateQuery.getWaitForActiveShards())));
} }
return ub; return ub;
@ -1048,12 +1050,12 @@ class RequestConverter {
mrb.searches(sb -> sb // mrb.searches(sb -> sb //
.header(h -> h // .header(h -> h //
.index(param.index.getIndexName()) // .index(param.index.getIndexName()) //
// todo #1973 add remaining flags for header // todo #2156 add remaining flags for header
) // ) //
.body(bb -> bb // .body(bb -> bb //
.query(getQuery(param.query, param.clazz))// .query(getQuery(param.query, param.clazz))//
// #1973 seq_no_primary_term and version not available in client ES issue 161 // todo #2138 seq_no_primary_term and version not available in client ES issue 161
// todo #1973 add remaining flags for body // todo #2156 add remaining flags for body
) // ) //
); );
}); });
@ -1101,7 +1103,7 @@ class RequestConverter {
} }
if (query.getIndicesOptions() != null) { if (query.getIndicesOptions() != null) {
// todo #1973 indices options // new Elasticsearch client does not support the old Indices options, need to be adapted
} }
if (query.isLimiting()) { if (query.isLimiting()) {
@ -1116,7 +1118,7 @@ class RequestConverter {
builder.preference(query.getPreference()); builder.preference(query.getPreference());
} }
// todo #1973 searchType builder.searchType(searchType(query.getSearchType()));
if (query.getSort() != null) { if (query.getSort() != null) {
List<SortOptions> sortOptions = getSortOptions(query.getSort(), persistentEntity); List<SortOptions> sortOptions = getSortOptions(query.getSort(), persistentEntity);
@ -1144,7 +1146,7 @@ class RequestConverter {
builder.routing(query.getRoute()); builder.routing(query.getRoute());
} }
// todo #1973 timeout builder.timeout(timeStringMs(query.getTimeout()));
if (query.getExplain()) { if (query.getExplain()) {
builder.explain(true); builder.explain(true);
@ -1158,7 +1160,7 @@ class RequestConverter {
builder.rescore(getRescore(rescorerQuery)); builder.rescore(getRescore(rescorerQuery));
}); });
// todo #1973 request cache builder.requestCache(query.getRequestCache());
if (!query.getRuntimeFields().isEmpty()) { if (!query.getRuntimeFields().isEmpty()) {
@ -1183,6 +1185,15 @@ class RequestConverter {
// limit the number of documents in a batch // limit the number of documents in a batch
builder.size(500); builder.size(500);
} }
if (!isEmpty(query.getIndicesBoost())) {
Map<String, Double> boosts = new LinkedHashMap<>();
query.getIndicesBoost().forEach(indexBoost -> {
boosts.put(indexBoost.getIndexName(), (double) indexBoost.getBoost());
});
// noinspection unchecked
builder.indicesBoost(boosts);
}
} }
private Rescore getRescore(RescorerQuery rescorerQuery) { private Rescore getRescore(RescorerQuery rescorerQuery) {
@ -1190,7 +1201,7 @@ class RequestConverter {
return Rescore.of(r -> r // return Rescore.of(r -> r //
.query(rq -> rq // .query(rq -> rq //
.query(getQuery(rescorerQuery.getQuery(), null)) // .query(getQuery(rescorerQuery.getQuery(), null)) //
.scoreMode(scoreMode(rescorerQuery.getScoreMode())) // .scoreMode(TypeUtils.scoreMode(rescorerQuery.getScoreMode())) //
.queryWeight(rescorerQuery.getQueryWeight() != null ? Double.valueOf(rescorerQuery.getQueryWeight()) : 1.0) // .queryWeight(rescorerQuery.getQueryWeight() != null ? Double.valueOf(rescorerQuery.getQueryWeight()) : 1.0) //
.rescoreQueryWeight( .rescoreQueryWeight(
rescorerQuery.getRescoreQueryWeight() != null ? Double.valueOf(rescorerQuery.getRescoreQueryWeight()) rescorerQuery.getRescoreQueryWeight() != null ? Double.valueOf(rescorerQuery.getRescoreQueryWeight())
@ -1242,8 +1253,9 @@ class RequestConverter {
.geoDistance(gd -> gd // .geoDistance(gd -> gd //
.field(fieldName) // .field(fieldName) //
.location(loc -> loc.latlon(QueryBuilders.latLon(geoDistanceOrder.getGeoPoint())))// .location(loc -> loc.latlon(QueryBuilders.latLon(geoDistanceOrder.getGeoPoint())))//
.distanceType(geoDistanceType(geoDistanceOrder.getDistanceType())).mode(sortMode(finalMode)) // .distanceType(TypeUtils.geoDistanceType(geoDistanceOrder.getDistanceType()))
.unit(distanceUnit(geoDistanceOrder.getUnit())) // .mode(TypeUtils.sortMode(finalMode)) //
.unit(TypeUtils.distanceUnit(geoDistanceOrder.getUnit())) //
.ignoreUnmapped(geoDistanceOrder.getIgnoreUnmapped()))); .ignoreUnmapped(geoDistanceOrder.getIgnoreUnmapped())));
} else { } else {
String missing = (order.getNullHandling() == Sort.NullHandling.NULLS_FIRST) ? "_first" String missing = (order.getNullHandling() == Sort.NullHandling.NULLS_FIRST) ? "_first"
@ -1253,10 +1265,10 @@ class RequestConverter {
.field(f -> { .field(f -> {
f.field(fieldName) // f.field(fieldName) //
.order(sortOrder) // .order(sortOrder) //
.mode(sortMode(finalMode)); .mode(TypeUtils.sortMode(finalMode));
if (finalUnmappedType != null) { if (finalUnmappedType != null) {
FieldType fieldType = fieldType(finalUnmappedType); FieldType fieldType = TypeUtils.fieldType(finalUnmappedType);
if (fieldType != null) { if (fieldType != null) {
f.unmappedType(fieldType); f.unmappedType(fieldType);
@ -1284,13 +1296,11 @@ class RequestConverter {
.collapse(query.getFieldCollapse()) // .collapse(query.getFieldCollapse()) //
; ;
// todo #1973 indices boost
if (!isEmpty(query.getAggregations())) { if (!isEmpty(query.getAggregations())) {
builder.aggregations(query.getAggregations()); builder.aggregations(query.getAggregations());
} }
// todo #1973 searchExt // todo #2150 searchExt, currently not supported by the new client
} }
@Nullable @Nullable
@ -1463,12 +1473,6 @@ class RequestConverter {
return versionType != null ? versionType : VersionType.External; return versionType != null ? versionType : VersionType.External;
} }
private co.elastic.clients.elasticsearch._types.query_dsl.Query getFilter(Query filterQuery) {
// TODO #1973 add filter query
throw new UnsupportedOperationException("not implemented");
}
@Nullable @Nullable
private SourceConfig getSourceConfig(Query query) { private SourceConfig getSourceConfig(Query query) {

View File

@ -116,7 +116,7 @@ class SearchDocumentResponseBuilder {
ElasticsearchAggregations aggregationsContainer = aggregations != null ? new ElasticsearchAggregations(aggregations) ElasticsearchAggregations aggregationsContainer = aggregations != null ? new ElasticsearchAggregations(aggregations)
: null; : null;
// todo #1973 // todo #2154
Suggest suggest = null; Suggest suggest = null;
return new SearchDocumentResponse(totalHits, totalHitsRelation, maxScore, scrollId, searchDocuments, return new SearchDocumentResponse(totalHits, totalHitsRelation, maxScore, scrollId, searchDocuments,

View File

@ -15,15 +15,7 @@
*/ */
package org.springframework.data.elasticsearch.client.elc; package org.springframework.data.elasticsearch.client.elc;
import co.elastic.clients.elasticsearch._types.Conflicts; import co.elastic.clients.elasticsearch._types.*;
import co.elastic.clients.elasticsearch._types.DistanceUnit;
import co.elastic.clients.elasticsearch._types.GeoDistanceType;
import co.elastic.clients.elasticsearch._types.OpType;
import co.elastic.clients.elasticsearch._types.Refresh;
import co.elastic.clients.elasticsearch._types.Result;
import co.elastic.clients.elasticsearch._types.SortMode;
import co.elastic.clients.elasticsearch._types.Time;
import co.elastic.clients.elasticsearch._types.VersionType;
import co.elastic.clients.elasticsearch._types.mapping.FieldType; import co.elastic.clients.elasticsearch._types.mapping.FieldType;
import co.elastic.clients.elasticsearch.core.search.BoundaryScanner; import co.elastic.clients.elasticsearch.core.search.BoundaryScanner;
import co.elastic.clients.elasticsearch.core.search.BuiltinHighlighterType; import co.elastic.clients.elasticsearch.core.search.BuiltinHighlighterType;
@ -40,6 +32,7 @@ import org.springframework.data.elasticsearch.core.RefreshPolicy;
import org.springframework.data.elasticsearch.core.query.GeoDistanceOrder; import org.springframework.data.elasticsearch.core.query.GeoDistanceOrder;
import org.springframework.data.elasticsearch.core.query.IndexQuery; import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.Order; import org.springframework.data.elasticsearch.core.query.Order;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.query.RescorerQuery; import org.springframework.data.elasticsearch.core.query.RescorerQuery;
import org.springframework.data.elasticsearch.core.query.UpdateResponse; import org.springframework.data.elasticsearch.core.query.UpdateResponse;
import org.springframework.data.elasticsearch.core.reindex.ReindexRequest; import org.springframework.data.elasticsearch.core.reindex.ReindexRequest;
@ -298,6 +291,23 @@ final class TypeUtils {
return null; return null;
} }
@Nullable
static SearchType searchType(@Nullable Query.SearchType searchType) {
if (searchType == null) {
return null;
}
switch (searchType) {
case QUERY_THEN_FETCH:
return SearchType.QueryThenFetch;
case DFS_QUERY_THEN_FETCH:
return SearchType.DfsQueryThenFetch;
}
return null;
}
@Nullable @Nullable
static SortMode sortMode(Order.Mode mode) { static SortMode sortMode(Order.Mode mode) {
@ -325,6 +335,16 @@ final class TypeUtils {
return Time.of(t -> t.time(duration.toMillis() + "ms")); return Time.of(t -> t.time(duration.toMillis() + "ms"));
} }
@Nullable
static String timeStringMs(@Nullable Duration duration) {
if (duration == null) {
return null;
}
return duration.toMillis() + "ms";
}
@Nullable @Nullable
static VersionType versionType( static VersionType versionType(
@Nullable org.springframework.data.elasticsearch.annotations.Document.VersionType versionType) { @Nullable org.springframework.data.elasticsearch.annotations.Document.VersionType versionType) {

View File

@ -277,8 +277,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
*/ */
protected Mono<GetResult> doGet(GetRequest request) { protected Mono<GetResult> doGet(GetRequest request) {
return Mono.from(execute(client -> client.get(request))) // return Mono.from(execute(client -> client.get(request)));
.onErrorResume(NoSuchIndexException.class, it -> Mono.empty());
} }
protected Mono<String> doDeleteById(String id, @Nullable String routing, IndexCoordinates index) { protected Mono<String> doDeleteById(String id, @Nullable String routing, IndexCoordinates index) {
@ -633,8 +632,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
QUERY_LOGGER.debug(String.format("Executing doCount: %s", request)); QUERY_LOGGER.debug(String.format("Executing doCount: %s", request));
} }
return Mono.from(execute(client -> client.count(request))) // return Mono.from(execute(client -> client.count(request)));
.onErrorResume(NoSuchIndexException.class, it -> Mono.just(0L));
} }
/** /**

View File

@ -22,7 +22,8 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* class that holds explanations returned from an Elasticsearch search. * class that holds explanations returned from an Elasticsearch search. Note: the new Elasticsearch client does not
* return the match property in search hits anymore, probably because a returned hit always is a match.
* *
* @author Peter-Josef Meisch * @author Peter-Josef Meisch
*/ */

View File

@ -71,6 +71,7 @@ public class BaseQuery implements Query {
@Nullable protected Boolean requestCache; @Nullable protected Boolean requestCache;
protected List<IdWithRouting> idsWithRouting = Collections.emptyList(); protected List<IdWithRouting> idsWithRouting = Collections.emptyList();
protected final List<RuntimeField> runtimeFields = new ArrayList<>(); protected final List<RuntimeField> runtimeFields = new ArrayList<>();
@Nullable protected List<IndexBoost> indicesBoost;
public BaseQuery() {} public BaseQuery() {}
@ -88,7 +89,7 @@ public class BaseQuery implements Query {
this.fields = builder.getFields(); this.fields = builder.getFields();
this.highlightQuery = builder.highlightQuery; this.highlightQuery = builder.highlightQuery;
this.route = builder.getRoute(); this.route = builder.getRoute();
// #1973 add the other fields to the builder this.indicesBoost = builder.getIndicesBoost();
} }
@Override @Override
@ -433,4 +434,10 @@ public class BaseQuery implements Query {
public List<RuntimeField> getRuntimeFields() { public List<RuntimeField> getRuntimeFields() {
return runtimeFields; return runtimeFields;
} }
@Override
@Nullable
public List<IndexBoost> getIndicesBoost() {
return indicesBoost;
}
} }

View File

@ -46,6 +46,7 @@ public abstract class BaseQueryBuilder<Q extends BaseQuery, SELF extends BaseQue
private List<String> fields = new ArrayList<>(); private List<String> fields = new ArrayList<>();
@Nullable protected HighlightQuery highlightQuery; @Nullable protected HighlightQuery highlightQuery;
@Nullable private String route; @Nullable private String route;
@Nullable private List<IndexBoost> indicesBoost;
@Nullable @Nullable
public Pageable getPageable() { public Pageable getPageable() {
@ -104,6 +105,11 @@ public abstract class BaseQueryBuilder<Q extends BaseQuery, SELF extends BaseQue
return route; return route;
} }
@Nullable
public List<IndexBoost> getIndicesBoost() {
return indicesBoost;
}
public SELF withPageable(Pageable pageable) { public SELF withPageable(Pageable pageable) {
this.pageable = pageable; this.pageable = pageable;
return self(); return self();
@ -178,6 +184,16 @@ public abstract class BaseQueryBuilder<Q extends BaseQuery, SELF extends BaseQue
return self(); return self();
} }
public SELF withIndicesBoost(List<IndexBoost> indicesBoost) {
this.indicesBoost = indicesBoost;
return self();
}
public SELF withIndicesBoost(IndexBoost... indicesBoost) {
this.indicesBoost = Arrays.asList(indicesBoost);
return self();
}
public abstract Q build(); public abstract Q build();
private SELF self() { private SELF self() {

View File

@ -55,7 +55,6 @@ public class NativeSearchQuery extends BaseQuery {
@Nullable private List<PipelineAggregationBuilder> pipelineAggregations; @Nullable private List<PipelineAggregationBuilder> pipelineAggregations;
@Nullable private HighlightBuilder highlightBuilder; @Nullable private HighlightBuilder highlightBuilder;
@Nullable private HighlightBuilder.Field[] highlightFields; @Nullable private HighlightBuilder.Field[] highlightFields;
@Nullable private List<IndexBoost> indicesBoost;
@Nullable private SearchTemplateRequestBuilder searchTemplate; @Nullable private SearchTemplateRequestBuilder searchTemplate;
@Nullable private SuggestBuilder suggestBuilder; @Nullable private SuggestBuilder suggestBuilder;
@Nullable private List<SearchExtBuilder> searchExtBuilders; @Nullable private List<SearchExtBuilder> searchExtBuilders;
@ -182,11 +181,6 @@ public class NativeSearchQuery extends BaseQuery {
this.pipelineAggregations = pipelineAggregationBuilders; this.pipelineAggregations = pipelineAggregationBuilders;
} }
@Nullable
public List<IndexBoost> getIndicesBoost() {
return indicesBoost;
}
public void setIndicesBoost(List<IndexBoost> indicesBoost) { public void setIndicesBoost(List<IndexBoost> indicesBoost) {
this.indicesBoost = indicesBoost; this.indicesBoost = indicesBoost;
} }

View File

@ -63,7 +63,6 @@ public class NativeSearchQueryBuilder extends BaseQueryBuilder<NativeSearchQuery
@Nullable private List<HighlightBuilder.Field> highlightFields = new ArrayList<>(); @Nullable private List<HighlightBuilder.Field> highlightFields = new ArrayList<>();
@Nullable protected List<String> storedFields; @Nullable protected List<String> storedFields;
@Nullable private CollapseBuilder collapseBuilder; @Nullable private CollapseBuilder collapseBuilder;
@Nullable private List<IndexBoost> indicesBoost = new ArrayList<>();
@Nullable private SearchTemplateRequestBuilder searchTemplateBuilder; @Nullable private SearchTemplateRequestBuilder searchTemplateBuilder;
@Nullable private SearchType searchType; @Nullable private SearchType searchType;
@Nullable private Boolean trackTotalHits; @Nullable private Boolean trackTotalHits;
@ -194,19 +193,6 @@ public class NativeSearchQueryBuilder extends BaseQueryBuilder<NativeSearchQuery
return this; return this;
} }
public NativeSearchQueryBuilder withIndicesBoost(Collection<IndexBoost> indicesBoost) {
this.indicesBoost.addAll(indicesBoost);
return this;
}
/**
* @since 4.3
*/
public NativeSearchQueryBuilder withIndicesBoost(IndexBoost... indicesBoost) {
Collections.addAll(this.indicesBoost, indicesBoost);
return this;
}
public NativeSearchQueryBuilder withSearchTemplate(SearchTemplateRequestBuilder searchTemplateBuilder) { public NativeSearchQueryBuilder withSearchTemplate(SearchTemplateRequestBuilder searchTemplateBuilder) {
this.searchTemplateBuilder = searchTemplateBuilder; this.searchTemplateBuilder = searchTemplateBuilder;
return this; return this;
@ -290,10 +276,6 @@ public class NativeSearchQueryBuilder extends BaseQueryBuilder<NativeSearchQuery
nativeSearchQuery.setStoredFields(storedFields); nativeSearchQuery.setStoredFields(storedFields);
} }
if (indicesBoost != null) {
nativeSearchQuery.setIndicesBoost(indicesBoost);
}
if (searchTemplateBuilder != null) { if (searchTemplateBuilder != null) {
nativeSearchQuery.setSearchTemplate(searchTemplateBuilder); nativeSearchQuery.setSearchTemplate(searchTemplateBuilder);
} }

View File

@ -433,6 +433,12 @@ public interface Query {
*/ */
List<RuntimeField> getRuntimeFields(); List<RuntimeField> getRuntimeFields();
/**
* @since 4.4
*/
@Nullable
List<IndexBoost> getIndicesBoost();
/** /**
* @since 4.3 * @since 4.3
*/ */

View File

@ -1,2 +1,2 @@
version.spring-data-elasticsearch=${project.version} version.spring-data-elasticsearch=${project.version}
version.elasticsearch-client=${elasticsearch} version.elasticsearch-client=${elasticsearch-rhlc}

View File

@ -16,7 +16,7 @@
package org.springframework.data.elasticsearch; package org.springframework.data.elasticsearch;
/** /**
* TODO #1973 remove when the new Elasticsearch client is fully working * TODO remove when the new Elasticsearch client is fully working
* *
* @author Peter-Josef Meisch * @author Peter-Josef Meisch
*/ */

View File

@ -20,12 +20,15 @@ import co.elastic.clients.json.JsonData;
import co.elastic.clients.json.JsonpMapper; import co.elastic.clients.json.JsonpMapper;
import co.elastic.clients.json.jackson.JacksonJsonpMapper; import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.assertj.core.api.SoftAssertions; import org.assertj.core.api.SoftAssertions;
import org.assertj.core.data.Offset;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.data.elasticsearch.core.document.Explanation;
import org.springframework.data.elasticsearch.core.document.SearchDocument; import org.springframework.data.elasticsearch.core.document.SearchDocument;
/** /**
@ -106,4 +109,53 @@ class DocumentAdaptersUnitTests {
softly.assertAll(); softly.assertAll();
} }
@Test // #725 #1973
@DisplayName("should adapt returned explanations")
void shouldAdaptReturnedExplanations() {
Hit<EntityAsMap> searchHit = new Hit.Builder<EntityAsMap>() //
.index("index") //
.id("42") //
.explanation(eb -> eb //
.value(3.14f) //
.description("explanation 3.14") //
.details(edb -> edb.description("explanation noMatch").value(0f)))
.build();
SearchDocument searchDocument = DocumentAdapters.from(searchHit, jsonpMapper);
SoftAssertions softly = new SoftAssertions();
Explanation explanation = searchDocument.getExplanation();
softly.assertThat(explanation).isNotNull();
softly.assertThat(explanation.isMatch()).isTrue();
softly.assertThat(explanation.getValue()).isCloseTo(3.14, Offset.offset(0.001));
softly.assertThat(explanation.getDescription()).isEqualTo("explanation 3.14");
List<Explanation> details = explanation.getDetails();
softly.assertThat(details)
.containsExactly(new Explanation(null, 0.0, "explanation noMatch", Collections.emptyList()));
softly.assertAll();
}
@Test // DATAES-979 #1973
@DisplayName("should adapt returned matched queries")
void shouldAdaptReturnedMatchedQueries() {
Hit<EntityAsMap> searchHit = new Hit.Builder<EntityAsMap>() //
.index("index") //
.id("42") //
.matchedQueries("query1", "query2") //
.build();
SearchDocument searchDocument = DocumentAdapters.from(searchHit, jsonpMapper);
SoftAssertions softly = new SoftAssertions();
List<String> matchedQueries = searchDocument.getMatchedQueries();
softly.assertThat(matchedQueries).isNotNull();
softly.assertThat(matchedQueries).hasSize(2);
softly.assertThat(matchedQueries).isEqualTo(Arrays.asList("query1", "query2"));
softly.assertAll();
}
} }

View File

@ -1617,7 +1617,7 @@ public abstract class ElasticsearchIntegrationTests implements NewElasticsearchC
} }
@DisabledIf(value = "newElasticsearchClient", @DisabledIf(value = "newElasticsearchClient",
disabledReason = "todo #1973 can't check response, open ES issue 161 that does not allow seqno") disabledReason = "todo #2138 can't check response, open ES issue 161 that does not allow seqno")
// and version to be set in the request // and version to be set in the request
@Test // DATAES-487 @Test // DATAES-487
public void shouldReturnSameEntityForMultiSearch() { public void shouldReturnSameEntityForMultiSearch() {
@ -1642,7 +1642,7 @@ public abstract class ElasticsearchIntegrationTests implements NewElasticsearchC
} }
@DisabledIf(value = "newElasticsearchClient", @DisabledIf(value = "newElasticsearchClient",
disabledReason = "todo #1973 can't check response, open ES issue 161 that does not allow seqno") disabledReason = "todo #2138 can't check response, open ES issue 161 that does not allow seqno")
// and version to be set in the request // and version to be set in the request
@Test // DATAES-487 @Test // DATAES-487
public void shouldReturnDifferentEntityForMultiSearch() { public void shouldReturnDifferentEntityForMultiSearch() {
@ -3070,7 +3070,7 @@ public abstract class ElasticsearchIntegrationTests implements NewElasticsearchC
} }
@DisabledIf(value = "newElasticsearchClient", @DisabledIf(value = "newElasticsearchClient",
disabledReason = "todo #1973 can't check response, open ES issue 161 that does not allow seqno") disabledReason = "todo #2138 can't check response, open ES issue 161 that does not allow seqno")
// and version to be set in the request // and version to be set in the request
@Test // DATAES-799 @Test // DATAES-799
void multiSearchShouldReturnSeqNoPrimaryTerm() { void multiSearchShouldReturnSeqNoPrimaryTerm() {

View File

@ -116,7 +116,7 @@ public abstract class CompletionIntegrationTests implements NewElasticsearchClie
operations.bulkIndex(indexQueries, AnnotatedCompletionEntity.class); operations.bulkIndex(indexQueries, AnnotatedCompletionEntity.class);
} }
@DisabledIf(value = "newElasticsearchClient", disabledReason="todo #1973, ES issue 150") @DisabledIf(value = "newElasticsearchClient", disabledReason = "todo #2139, ES issue 150")
@Test @Test
public void shouldFindSuggestionsForGivenCriteriaQueryUsingCompletionEntity() { public void shouldFindSuggestionsForGivenCriteriaQueryUsingCompletionEntity() {
@ -148,7 +148,7 @@ public abstract class CompletionIntegrationTests implements NewElasticsearchClie
operations.get("1", CompletionEntity.class); operations.get("1", CompletionEntity.class);
} }
@DisabledIf(value = "newElasticsearchClient", disabledReason="todo #1973, ES issue 150") @DisabledIf(value = "newElasticsearchClient", disabledReason = "todo #2139, ES issue 150")
@Test @Test
public void shouldFindSuggestionsForGivenCriteriaQueryUsingAnnotatedCompletionEntity() { public void shouldFindSuggestionsForGivenCriteriaQueryUsingAnnotatedCompletionEntity() {
@ -172,7 +172,7 @@ public abstract class CompletionIntegrationTests implements NewElasticsearchClie
assertThat(options.get(1).getText()).isIn("Marchand", "Mohsin"); assertThat(options.get(1).getText()).isIn("Marchand", "Mohsin");
} }
@DisabledIf(value = "newElasticsearchClient", disabledReason="todo #1973, ES issue 150") @DisabledIf(value = "newElasticsearchClient", disabledReason = "todo #2139, ES 1issue 150")
@Test @Test
public void shouldFindSuggestionsWithWeightsForGivenCriteriaQueryUsingAnnotatedCompletionEntity() { public void shouldFindSuggestionsWithWeightsForGivenCriteriaQueryUsingAnnotatedCompletionEntity() {

View File

@ -67,7 +67,7 @@ public abstract class ReactiveSuggestIntegrationTests implements NewElasticsearc
operations.indexOps(IndexCoordinates.of(indexNameProvider.getPrefix() + "*")).delete().block(); operations.indexOps(IndexCoordinates.of(indexNameProvider.getPrefix() + "*")).delete().block();
} }
@DisabledIf(value = "newElasticsearchClient", disabledReason="todo #1973, ES issue 150") @DisabledIf(value = "newElasticsearchClient", disabledReason = "todo #2139, ES issue 150")
@Test // #1302 @Test // #1302
@DisplayName("should find suggestions for given prefix completion") @DisplayName("should find suggestions for given prefix completion")
void shouldFindSuggestionsForGivenPrefixCompletion() { void shouldFindSuggestionsForGivenPrefixCompletion() {

View File

@ -0,0 +1,44 @@
/*
* Copyright 2022 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.repository.support;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchTemplateConfiguration;
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
import org.springframework.data.elasticsearch.utils.IndexNameProvider;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Peter-Josef Meisch
* @since 4.4
*/
@ContextConfiguration(classes = { SimpleReactiveElasticsearchRepositoryELCIntegrationTests.Config.class })
public class SimpleReactiveElasticsearchRepositoryELCIntegrationTests
extends SimpleReactiveElasticsearchRepositoryIntegrationTests {
@Configuration
@Import({ ReactiveElasticsearchTemplateConfiguration.class })
@EnableReactiveElasticsearchRepositories(considerNestedRepositories = true)
static class Config {
@Bean
IndexNameProvider indexNameProvider() {
return new IndexNameProvider("simple-reactive-repository");
}
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2022 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.repository.support;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
import org.springframework.data.elasticsearch.utils.IndexNameProvider;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Peter-Josef Meisch
*/
@ContextConfiguration(classes = { SimpleReactiveElasticsearchRepositoryERHLCIntegrationTests.Config.class })
public class SimpleReactiveElasticsearchRepositoryERHLCIntegrationTests
extends SimpleReactiveElasticsearchRepositoryIntegrationTests {
@Configuration
@Import({ ReactiveElasticsearchRestTemplateConfiguration.class })
@EnableReactiveElasticsearchRepositories(considerNestedRepositories = true)
static class Config {
@Bean
IndexNameProvider indexNameProvider() {
return new IndexNameProvider("simple-reactive-repository-es7");
}
}
}

View File

@ -16,81 +16,68 @@
package org.springframework.data.elasticsearch.repository.support; package org.springframework.data.elasticsearch.repository.support;
import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.elasticsearch.annotations.FieldType.*;
import static org.springframework.data.elasticsearch.core.query.Query.*; import static org.springframework.data.elasticsearch.core.query.Query.*;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import reactor.test.StepVerifier; import reactor.test.StepVerifier;
import java.lang.Boolean;
import java.lang.Long;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.reactivestreams.Publisher; import org.reactivestreams.Publisher;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Version; import org.springframework.data.annotation.Version;
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.domain.Sort.Order; import org.springframework.data.domain.Sort.Order;
import org.springframework.data.elasticsearch.RestStatusException; import org.springframework.data.elasticsearch.NoSuchIndexException;
import org.springframework.data.elasticsearch.annotations.CountQuery; import org.springframework.data.elasticsearch.annotations.CountQuery;
import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.Highlight; import org.springframework.data.elasticsearch.annotations.Highlight;
import org.springframework.data.elasticsearch.annotations.HighlightField; import org.springframework.data.elasticsearch.annotations.HighlightField;
import org.springframework.data.elasticsearch.annotations.Query; import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations; import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit; import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest; import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories; import org.springframework.data.elasticsearch.utils.IndexNameProvider;
import org.springframework.data.repository.reactive.ReactiveCrudRepository; import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.test.context.ContextConfiguration;
/** /**
* @author Christoph Strobl * @author Christoph Strobl
* @author Peter-Josef Meisch * @author Peter-Josef Meisch
* @author Jens Schauder * @author Jens Schauder
*/ */
// todo #1973 test for both clients
@SpringIntegrationTest @SpringIntegrationTest
@ContextConfiguration(classes = { SimpleReactiveElasticsearchRepositoryTests.Config.class }) abstract class SimpleReactiveElasticsearchRepositoryIntegrationTests {
class SimpleReactiveElasticsearchRepositoryTests {
@Configuration
@Import({ ReactiveElasticsearchRestTemplateConfiguration.class })
@EnableReactiveElasticsearchRepositories(considerNestedRepositories = true)
static class Config {}
static final String INDEX = "test-index-sample-simple-reactive";
@Autowired ReactiveElasticsearchOperations operations; @Autowired ReactiveElasticsearchOperations operations;
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Autowired ReactiveSampleEntityRepository repository; @Autowired ReactiveSampleEntityRepository repository;
@Autowired private IndexNameProvider indexNameProvider;
@BeforeEach @BeforeEach
void setUp() { void before() {
operations.indexOps(IndexCoordinates.of(INDEX)).delete().block(); indexNameProvider.increment();
operations.indexOps(SampleEntity.class).createWithMapping().block();
} }
@AfterEach @Test
void after() { @org.junit.jupiter.api.Order(Integer.MAX_VALUE)
operations.indexOps(IndexCoordinates.of(INDEX)).delete().block(); public void cleanup() {
operations.indexOps(IndexCoordinates.of(indexNameProvider.getPrefix() + "*")).delete().block();
} }
@Test // DATAES-519 @Test // DATAES-519
@ -104,7 +91,7 @@ class SimpleReactiveElasticsearchRepositoryTests {
} }
private Mono<Boolean> documentWithIdExistsInIndex(String id) { private Mono<Boolean> documentWithIdExistsInIndex(String id) {
return operations.exists(id, IndexCoordinates.of(INDEX)); return operations.exists(id, IndexCoordinates.of(indexNameProvider.indexName()));
} }
@Test // DATAES-519 @Test // DATAES-519
@ -122,9 +109,12 @@ class SimpleReactiveElasticsearchRepositoryTests {
@Test // DATAES-519, DATAES-767, DATAES-822 @Test // DATAES-519, DATAES-767, DATAES-822
void findByIdShouldErrorIfIndexDoesNotExist() { void findByIdShouldErrorIfIndexDoesNotExist() {
operations.indexOps(SampleEntity.class).delete().block();
repository.findById("id-two") // repository.findById("id-two") //
.as(StepVerifier::create) // .as(StepVerifier::create) //
.expectError(RestStatusException.class); .expectError(NoSuchIndexException.class) //
.verify();
} }
@Test // DATAES-519 @Test // DATAES-519
@ -268,9 +258,12 @@ class SimpleReactiveElasticsearchRepositoryTests {
@Test // DATAES-519, DATAES-767, DATAES-822 @Test // DATAES-519, DATAES-767, DATAES-822
void countShouldErrorWhenIndexDoesNotExist() { void countShouldErrorWhenIndexDoesNotExist() {
operations.indexOps(SampleEntity.class).delete().block();
repository.count() // repository.count() //
.as(StepVerifier::create) // .as(StepVerifier::create) //
.expectError(RestStatusException.class); .expectError(NoSuchIndexException.class) //
.verify();
} }
@Test // DATAES-519 @Test // DATAES-519
@ -596,7 +589,7 @@ class SimpleReactiveElasticsearchRepositoryTests {
} }
Mono<Void> bulkIndex(SampleEntity... entities) { Mono<Void> bulkIndex(SampleEntity... entities) {
return operations.saveAll(Arrays.asList(entities), IndexCoordinates.of(INDEX)).then(); return operations.saveAll(Arrays.asList(entities), IndexCoordinates.of(indexNameProvider.indexName())).then();
} }
interface ReactiveSampleEntityRepository extends ReactiveCrudRepository<SampleEntity, String> { interface ReactiveSampleEntityRepository extends ReactiveCrudRepository<SampleEntity, String> {
@ -636,14 +629,14 @@ class SimpleReactiveElasticsearchRepositoryTests {
Mono<Long> retrieveCountByText(String message); Mono<Long> retrieveCountByText(String message);
} }
@Document(indexName = INDEX) @Document(indexName = "#{@indexNameProvider.indexName()}")
static class SampleEntity { static class SampleEntity {
@Nullable @Nullable
@Id private String id; @Id private String id;
@Nullable @Nullable
@Field(type = Text, store = true, fielddata = true) private String type; @Field(type = FieldType.Text, store = true, fielddata = true) private String type;
@Nullable @Nullable
@Field(type = Text, store = true, fielddata = true) private String message; @Field(type = FieldType.Text, store = true, fielddata = true) private String message;
@Nullable private int rate; @Nullable private int rate;
@Nullable private boolean available; @Nullable private boolean available;
@Nullable @Nullable