Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f3035dab5 | |||
| a5c4867684 | |||
| 572cc7ffea | |||
| 4e7bcac5f5 | |||
| 4628908e84 | |||
| 922f4b1760 | |||
| 4614c62bb5 | |||
| 063020f8b3 | |||
| 0c98c419c9 | |||
| 3f085b2675 | |||
| 42aeb48b43 | |||
| 449910b4f7 | |||
| 2e99f5b2e0 | |||
| 9b9136d852 | |||
| a266d7c46a | |||
| c045a8ae29 | |||
| 11c87a1251 | |||
| c9e9bf757e |
+2
-2
@@ -1,3 +1,3 @@
|
||||
#Mon Jul 03 09:48:29 CEST 2023
|
||||
#Mon Aug 14 07:55:32 EDT 2023
|
||||
wrapperUrl=https\://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
|
||||
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip
|
||||
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.4/apache-maven-3.9.4-bin.zip
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Java versions
|
||||
java.main.tag=17.0.7_7-jdk-focal
|
||||
java.main.tag=17.0.8_7-jdk-focal
|
||||
java.next.tag=20-jdk-jammy
|
||||
|
||||
# Docker container images - standard
|
||||
@@ -7,12 +7,12 @@ docker.java.main.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/ecli
|
||||
docker.java.next.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.next.tag}
|
||||
|
||||
# Supported versions of MongoDB
|
||||
docker.mongodb.4.4.version=4.4.22
|
||||
docker.mongodb.5.0.version=5.0.18
|
||||
docker.mongodb.6.0.version=6.0.7
|
||||
docker.mongodb.4.4.version=4.4.23
|
||||
docker.mongodb.5.0.version=5.0.19
|
||||
docker.mongodb.6.0.version=6.0.8
|
||||
|
||||
# Supported versions of Redis
|
||||
docker.redis.6.version=6.2.12
|
||||
docker.redis.6.version=6.2.13
|
||||
|
||||
# Supported versions of Cassandra
|
||||
docker.cassandra.3.version=3.11.15
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>5.1.2</version>
|
||||
<version>5.1.4</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<version>3.1.4</version>
|
||||
</parent>
|
||||
|
||||
<name>Spring Data Elasticsearch</name>
|
||||
@@ -18,10 +18,10 @@
|
||||
<url>https://github.com/spring-projects/spring-data-elasticsearch</url>
|
||||
|
||||
<properties>
|
||||
<springdata.commons>3.1.2</springdata.commons>
|
||||
<springdata.commons>3.1.4</springdata.commons>
|
||||
|
||||
<!-- version of the RestHighLevelClient -->
|
||||
<elasticsearch-rhlc>7.17.11</elasticsearch-rhlc>
|
||||
<elasticsearch-rhlc>7.17.13</elasticsearch-rhlc>
|
||||
<!-- version of the new ElasticsearchClient -->
|
||||
<elasticsearch-java>8.7.1</elasticsearch-java>
|
||||
|
||||
|
||||
+3
-7
@@ -19,7 +19,6 @@ import static org.springframework.data.elasticsearch.client.elc.TypeUtils.*;
|
||||
import static org.springframework.util.CollectionUtils.*;
|
||||
|
||||
import co.elastic.clients.elasticsearch._types.Conflicts;
|
||||
import co.elastic.clients.elasticsearch._types.FieldValue;
|
||||
import co.elastic.clients.elasticsearch._types.InlineScript;
|
||||
import co.elastic.clients.elasticsearch._types.OpType;
|
||||
import co.elastic.clients.elasticsearch._types.SortOptions;
|
||||
@@ -63,7 +62,6 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
@@ -1001,7 +999,7 @@ class RequestConverter {
|
||||
.docAsUpsert(query.getDocAsUpsert()) //
|
||||
.ifSeqNo(query.getIfSeqNo() != null ? Long.valueOf(query.getIfSeqNo()) : null) //
|
||||
.ifPrimaryTerm(query.getIfPrimaryTerm() != null ? Long.valueOf(query.getIfPrimaryTerm()) : null) //
|
||||
.refresh(refresh(refreshPolicy)) //
|
||||
.refresh(query.getRefreshPolicy() != null ? refresh(query.getRefreshPolicy()) : refresh(refreshPolicy)) //
|
||||
.retryOnConflict(query.getRetryOnConflict()) //
|
||||
;
|
||||
|
||||
@@ -1221,8 +1219,7 @@ class RequestConverter {
|
||||
}
|
||||
|
||||
if (!isEmpty(query.getSearchAfter())) {
|
||||
bb.searchAfter(query.getSearchAfter().stream().map(it -> FieldValue.of(it.toString()))
|
||||
.collect(Collectors.toList()));
|
||||
bb.searchAfter(query.getSearchAfter().stream().map(TypeUtils::toFieldValue).toList());
|
||||
}
|
||||
|
||||
query.getRescorerQueries().forEach(rescorerQuery -> bb.rescore(getRescore(rescorerQuery)));
|
||||
@@ -1376,8 +1373,7 @@ class RequestConverter {
|
||||
}
|
||||
|
||||
if (!isEmpty(query.getSearchAfter())) {
|
||||
builder.searchAfter(
|
||||
query.getSearchAfter().stream().map(it -> FieldValue.of(it.toString())).collect(Collectors.toList()));
|
||||
builder.searchAfter(query.getSearchAfter().stream().map(TypeUtils::toFieldValue).toList());
|
||||
}
|
||||
|
||||
query.getRescorerQueries().forEach(rescorerQuery -> builder.rescore(getRescore(rescorerQuery)));
|
||||
|
||||
+2
-1
@@ -219,7 +219,8 @@ class SearchDocumentResponseBuilder {
|
||||
var phraseSuggestOptions = phraseSuggest.options();
|
||||
List<PhraseSuggestion.Entry.Option> options = new ArrayList<>();
|
||||
phraseSuggestOptions.forEach(optionES -> options
|
||||
.add(new PhraseSuggestion.Entry.Option(optionES.text(), optionES.highlighted(), null, null)));
|
||||
.add(new PhraseSuggestion.Entry.Option(optionES.text(), optionES.highlighted(), optionES.score(),
|
||||
optionES.collateMatch())));
|
||||
entries.add(new PhraseSuggestion.Entry(phraseSuggest.text(), phraseSuggest.offset(), phraseSuggest.length(),
|
||||
options, null));
|
||||
});
|
||||
|
||||
@@ -18,8 +18,15 @@ package org.springframework.data.elasticsearch.client.elc;
|
||||
import co.elastic.clients.elasticsearch._types.*;
|
||||
import co.elastic.clients.elasticsearch._types.mapping.FieldType;
|
||||
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
|
||||
import co.elastic.clients.elasticsearch.core.search.*;
|
||||
import co.elastic.clients.elasticsearch.core.search.BoundaryScanner;
|
||||
import co.elastic.clients.elasticsearch.core.search.HighlighterEncoder;
|
||||
import co.elastic.clients.elasticsearch.core.search.HighlighterFragmenter;
|
||||
import co.elastic.clients.elasticsearch.core.search.HighlighterOrder;
|
||||
import co.elastic.clients.elasticsearch.core.search.HighlighterTagsSchema;
|
||||
import co.elastic.clients.elasticsearch.core.search.HighlighterType;
|
||||
import co.elastic.clients.elasticsearch.core.search.ScoreMode;
|
||||
import co.elastic.clients.elasticsearch.indices.IndexSettings;
|
||||
import co.elastic.clients.json.JsonData;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.time.Duration;
|
||||
@@ -31,8 +38,13 @@ import java.util.stream.Collectors;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.elasticsearch.core.RefreshPolicy;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.data.elasticsearch.core.query.*;
|
||||
import org.springframework.data.elasticsearch.core.query.GeoDistanceOrder;
|
||||
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.IndicesOptions;
|
||||
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.UpdateResponse;
|
||||
import org.springframework.data.elasticsearch.core.reindex.ReindexRequest;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
@@ -156,6 +168,40 @@ final class TypeUtils {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static FieldValue toFieldValue(@Nullable Object fieldValue) {
|
||||
|
||||
if (fieldValue == null) {
|
||||
return FieldValue.NULL;
|
||||
}
|
||||
|
||||
if (fieldValue instanceof Boolean b) {
|
||||
return b ? FieldValue.TRUE : FieldValue.FALSE;
|
||||
}
|
||||
|
||||
if (fieldValue instanceof String s) {
|
||||
return FieldValue.of(s);
|
||||
}
|
||||
|
||||
if (fieldValue instanceof Long l) {
|
||||
return FieldValue.of(l);
|
||||
}
|
||||
|
||||
if (fieldValue instanceof Integer i) {
|
||||
return FieldValue.of((long) i);
|
||||
}
|
||||
|
||||
if (fieldValue instanceof Double d) {
|
||||
return FieldValue.of(d);
|
||||
}
|
||||
|
||||
if (fieldValue instanceof Float f) {
|
||||
return FieldValue.of((double) f);
|
||||
}
|
||||
|
||||
return FieldValue.of(JsonData.of(fieldValue));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static GeoDistanceType geoDistanceType(GeoDistanceOrder.DistanceType distanceType) {
|
||||
|
||||
|
||||
+1
-1
@@ -919,7 +919,7 @@ public class MappingElasticsearchConverter
|
||||
|
||||
Class<?> elementType = element == null ? null : element.getClass();
|
||||
|
||||
if (elementType == null || conversions.isSimpleType(elementType)) {
|
||||
if (elementType == null || isSimpleType(elementType)) {
|
||||
collection.add(getPotentiallyConvertedSimpleWrite(element,
|
||||
componentType != null ? componentType.getType() : Object.class));
|
||||
} else if (element instanceof Collection || elementType.isArray()) {
|
||||
|
||||
@@ -332,6 +332,8 @@ public final class MappingParameters {
|
||||
|
||||
if (!Similarity.Default.equals(similarity)) {
|
||||
objectNode.put(FIELD_PARAM_SIMILARITY, similarity);
|
||||
// similarity must have index explicitly set, otherwise Elasticsearch returns an error
|
||||
objectNode.put(FIELD_PARAM_INDEX, index);
|
||||
}
|
||||
|
||||
if (termVector != TermVector.none) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Data Elasticsearch 5.1.2 (2023.0.2)
|
||||
Spring Data Elasticsearch 5.1.4 (2023.0.4)
|
||||
Copyright (c) [2013-2022] Pivotal Software, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
@@ -15,3 +15,5 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2023 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.client.elc;
|
||||
|
||||
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
|
||||
import co.elastic.clients.elasticsearch.core.search.Suggestion;
|
||||
import co.elastic.clients.elasticsearch.core.search.TotalHitsRelation;
|
||||
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
import org.json.JSONException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
* Tests for the factory class to create {@link SearchDocumentResponse} instances.
|
||||
*
|
||||
* @author Sébastien Comeau
|
||||
* @since 5.2
|
||||
*/
|
||||
class SearchDocumentResponseBuilderUnitTests {
|
||||
|
||||
private JacksonJsonpMapper jsonpMapper = new JacksonJsonpMapper();
|
||||
|
||||
@Test // #2681
|
||||
void shouldGetPhraseSuggestion() throws JSONException {
|
||||
// arrange
|
||||
final var hitsMetadata = new HitsMetadata.Builder<EntityAsMap>()
|
||||
.total(total -> total
|
||||
.value(0)
|
||||
.relation(TotalHitsRelation.Eq))
|
||||
.hits(new ArrayList<>())
|
||||
.build();
|
||||
|
||||
final var suggestionTest = new Suggestion.Builder<EntityAsMap>()
|
||||
.phrase(phrase -> phrase
|
||||
.text("National")
|
||||
.offset(0)
|
||||
.length(8)
|
||||
.options(option -> option
|
||||
.text("nations")
|
||||
.highlighted("highlighted-nations")
|
||||
.score(0.11480146)
|
||||
.collateMatch(false))
|
||||
.options(option -> option
|
||||
.text("national")
|
||||
.highlighted("highlighted-national")
|
||||
.score(0.08063514)
|
||||
.collateMatch(false)))
|
||||
.build();
|
||||
|
||||
final var sortProperties = ImmutableMap.<String, List<Suggestion<EntityAsMap>>> builder()
|
||||
.put("suggestionTest", ImmutableList.of(suggestionTest))
|
||||
.build();
|
||||
|
||||
// act
|
||||
final var actual = SearchDocumentResponseBuilder.from(hitsMetadata, null, null, null, sortProperties, null,
|
||||
jsonpMapper);
|
||||
|
||||
// assert
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
|
||||
softly.assertThat(actual).isNotNull();
|
||||
softly.assertThat(actual.getSuggest()).isNotNull();
|
||||
softly.assertThat(actual.getSuggest().getSuggestions()).isNotNull().hasSize(1);
|
||||
|
||||
final var actualSuggestion = actual.getSuggest().getSuggestions().get(0);
|
||||
softly.assertThat(actualSuggestion.getName()).isEqualTo("suggestionTest");
|
||||
softly.assertThat(actualSuggestion.getEntries()).isNotNull().hasSize(1);
|
||||
|
||||
final var actualEntry = actualSuggestion.getEntries().get(0);
|
||||
softly.assertThat(actualEntry).isNotNull();
|
||||
softly.assertThat(actualEntry.getText()).isEqualTo("National");
|
||||
softly.assertThat(actualEntry.getOffset()).isEqualTo(0);
|
||||
softly.assertThat(actualEntry.getLength()).isEqualTo(8);
|
||||
softly.assertThat(actualEntry.getOptions()).isNotNull().hasSize(2);
|
||||
|
||||
final var actualOption1 = actualEntry.getOptions().get(0);
|
||||
softly.assertThat(actualOption1.getText()).isEqualTo("nations");
|
||||
softly.assertThat(actualOption1.getHighlighted()).isEqualTo("highlighted-nations");
|
||||
softly.assertThat(actualOption1.getScore()).isEqualTo(0.11480146);
|
||||
softly.assertThat(actualOption1.getCollateMatch()).isEqualTo(false);
|
||||
|
||||
final var actualOption2 = actualEntry.getOptions().get(1);
|
||||
softly.assertThat(actualOption2.getText()).isEqualTo("national");
|
||||
softly.assertThat(actualOption2.getHighlighted()).isEqualTo("highlighted-national");
|
||||
softly.assertThat(actualOption2.getScore()).isEqualTo(0.08063514);
|
||||
softly.assertThat(actualOption2.getCollateMatch()).isEqualTo(false);
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
}
|
||||
+56
-6
@@ -909,6 +909,55 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
assertEquals(expected, document.toJson(), false);
|
||||
}
|
||||
|
||||
@Test // #2627
|
||||
@DisplayName("should write Map containing collection containing map")
|
||||
void shouldWriteMapContainingCollectionContainingMap() throws JSONException {
|
||||
|
||||
class EntityWithMapCollectionMap {
|
||||
Map<String, Object> map;
|
||||
}
|
||||
class InnerEntity {
|
||||
String prop1;
|
||||
|
||||
String prop2;
|
||||
|
||||
public InnerEntity() {}
|
||||
|
||||
public InnerEntity(String prop1, String prop2) {
|
||||
this.prop1 = prop1;
|
||||
this.prop2 = prop2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var entity = new EntityWithMapCollectionMap();
|
||||
entity.map = Collections.singletonMap("collection",
|
||||
Collections.singletonList(Collections.singletonMap("destination", new InnerEntity("prop1", "prop2"))));
|
||||
|
||||
var expected = """
|
||||
{
|
||||
"_class": "org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverterUnitTests$1EntityWithMapCollectionMap",
|
||||
"map": {
|
||||
"collection": [
|
||||
{
|
||||
"destination": {
|
||||
"_class": "org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverterUnitTests$1InnerEntity",
|
||||
"prop1": "prop1",
|
||||
"prop2": "prop2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
Document document = Document.create();
|
||||
|
||||
mappingElasticsearchConverter.write(entity, document);
|
||||
|
||||
assertEquals(expected, document.toJson(), false);
|
||||
}
|
||||
|
||||
@Nested
|
||||
class RangeTests {
|
||||
|
||||
@@ -1953,12 +2002,12 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
|
||||
@Language("JSON")
|
||||
var expected = """
|
||||
{
|
||||
"_class": "org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverterUnitTests$FieldNameDotsEntity",
|
||||
"id": "42",
|
||||
"dotted.field": "dotted field"
|
||||
}
|
||||
""";
|
||||
{
|
||||
"_class": "org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverterUnitTests$FieldNameDotsEntity",
|
||||
"id": "42",
|
||||
"dotted.field": "dotted field"
|
||||
}
|
||||
""";
|
||||
var entity = new FieldNameDotsEntity();
|
||||
entity.setId("42");
|
||||
entity.setDottedField("dotted field");
|
||||
@@ -3192,6 +3241,7 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
this.mapToNotWriteWhenEmpty = mapToNotWriteWhenEmpty;
|
||||
}
|
||||
}
|
||||
|
||||
static class FieldNameDotsEntity {
|
||||
@Id
|
||||
@Nullable private String id;
|
||||
|
||||
+15
@@ -287,6 +287,12 @@ public abstract class MappingBuilderIntegrationTests extends MappingContextBaseT
|
||||
indexOps.createWithMapping();
|
||||
}
|
||||
|
||||
@Test // #2659
|
||||
@DisplayName("should write correct mapping for dense vector property")
|
||||
void shouldWriteCorrectMappingForDenseVectorProperty() {
|
||||
operations.indexOps(SimilarityEntity.class).createWithMapping();
|
||||
}
|
||||
|
||||
// region Entities
|
||||
@Document(indexName = "#{@indexNameProvider.indexName()}")
|
||||
static class Book {
|
||||
@@ -916,5 +922,14 @@ public abstract class MappingBuilderIntegrationTests extends MappingContextBaseT
|
||||
@Nullable
|
||||
@Field(name = "dotted.field", type = Text) private String dottedField;
|
||||
}
|
||||
|
||||
@Document(indexName = "#{@indexNameProvider.indexName()}")
|
||||
static class SimilarityEntity {
|
||||
@Nullable
|
||||
@Id private String id;
|
||||
|
||||
@Field(type = FieldType.Dense_Vector, dims = 42, similarity = "cosine") private double[] denseVector;
|
||||
}
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
||||
+81
-14
@@ -62,7 +62,7 @@ public abstract class SearchAfterIntegrationTests {
|
||||
@Test
|
||||
@Order(java.lang.Integer.MAX_VALUE)
|
||||
void cleanup() {
|
||||
operations.indexOps(IndexCoordinates.of(indexNameProvider.getPrefix() + "*")).delete();
|
||||
operations.indexOps(IndexCoordinates.of(indexNameProvider.getPrefix() + '*')).delete();
|
||||
}
|
||||
|
||||
@Test // #1143
|
||||
@@ -85,11 +85,11 @@ public abstract class SearchAfterIntegrationTests {
|
||||
query.setSearchAfter(searchAfter);
|
||||
SearchHits<Entity> searchHits = operations.search(query, Entity.class);
|
||||
|
||||
if (searchHits.getSearchHits().size() == 0) {
|
||||
if (searchHits.getSearchHits().isEmpty()) {
|
||||
break;
|
||||
}
|
||||
foundEntities.addAll(searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList()));
|
||||
searchAfter = searchHits.getSearchHit((int) (searchHits.getSearchHits().size() - 1)).getSortValues();
|
||||
foundEntities.addAll(searchHits.stream().map(SearchHit::getContent).toList());
|
||||
searchAfter = searchHits.getSearchHit(searchHits.getSearchHits().size() - 1).getSortValues();
|
||||
|
||||
if (++loop > 10) {
|
||||
fail("loop not terminating");
|
||||
@@ -99,16 +99,69 @@ public abstract class SearchAfterIntegrationTests {
|
||||
assertThat(foundEntities).containsExactlyElementsOf(entities);
|
||||
}
|
||||
|
||||
@Test // #2678
|
||||
@DisplayName("should be able to handle different search after type values including null")
|
||||
void shouldBeAbleToHandleDifferentSearchAfterTypeValuesIncludingNull() {
|
||||
|
||||
List<Entity> entities = IntStream.rangeClosed(1, 10)
|
||||
.mapToObj(i -> {
|
||||
var message = (i % 2 == 0) ? null : "message " + i;
|
||||
var value = (i % 3 == 0) ? null : (long) i;
|
||||
return new Entity((long) i, message, value);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
operations.save(entities);
|
||||
|
||||
Query query = Query.findAll();
|
||||
query.setPageable(PageRequest.of(0, 3));
|
||||
query.addSort(Sort.by(Sort.Direction.ASC, "id"));
|
||||
query.addSort(Sort.by(Sort.Direction.ASC, "keyword"));
|
||||
query.addSort(Sort.by(Sort.Direction.ASC, "value"));
|
||||
|
||||
List<Object> searchAfter = null;
|
||||
List<Entity> foundEntities = new ArrayList<>();
|
||||
|
||||
int loop = 0;
|
||||
do {
|
||||
query.setSearchAfter(searchAfter);
|
||||
SearchHits<Entity> searchHits = operations.search(query, Entity.class);
|
||||
|
||||
if (searchHits.getSearchHits().isEmpty()) {
|
||||
break;
|
||||
}
|
||||
foundEntities.addAll(searchHits.stream().map(SearchHit::getContent).toList());
|
||||
searchAfter = searchHits.getSearchHit(searchHits.getSearchHits().size() - 1).getSortValues();
|
||||
|
||||
if (++loop > 10) {
|
||||
fail("loop not terminating");
|
||||
}
|
||||
} while (true);
|
||||
|
||||
assertThat(foundEntities).containsExactlyElementsOf(entities);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Document(indexName = "#{@indexNameProvider.indexName()}")
|
||||
private static class Entity {
|
||||
@Nullable
|
||||
@Id private Long id;
|
||||
@Nullable
|
||||
@Field(type = FieldType.Text) private String message;
|
||||
@Field(type = FieldType.Keyword) private String keyword;
|
||||
|
||||
public Entity(@Nullable Long id, @Nullable String message) {
|
||||
@Nullable
|
||||
@Field(type = FieldType.Long) private Long value;
|
||||
|
||||
public Entity() {}
|
||||
|
||||
public Entity(@Nullable Long id, @Nullable String keyword) {
|
||||
this.id = id;
|
||||
this.message = message;
|
||||
this.keyword = keyword;
|
||||
}
|
||||
|
||||
public Entity(@Nullable Long id, @Nullable String keyword, @Nullable Long value) {
|
||||
this.id = id;
|
||||
this.keyword = keyword;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -121,30 +174,44 @@ public abstract class SearchAfterIntegrationTests {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getMessage() {
|
||||
return message;
|
||||
public String getKeyword() {
|
||||
return keyword;
|
||||
}
|
||||
|
||||
public void setMessage(@Nullable String message) {
|
||||
this.message = message;
|
||||
public void setKeyword(@Nullable String keyword) {
|
||||
this.keyword = keyword;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Long getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(@Nullable Long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (!(o instanceof Entity entity))
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
|
||||
Entity entity = (Entity) o;
|
||||
|
||||
if (!Objects.equals(id, entity.id))
|
||||
return false;
|
||||
return Objects.equals(message, entity.message);
|
||||
if (!Objects.equals(keyword, entity.keyword))
|
||||
return false;
|
||||
return Objects.equals(value, entity.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = id != null ? id.hashCode() : 0;
|
||||
result = 31 * result + (message != null ? message.hashCode() : 0);
|
||||
result = 31 * result + (keyword != null ? keyword.hashCode() : 0);
|
||||
result = 31 * result + (value != null ? value.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user