1
0
mirror of synced 2026-05-24 13:13:17 +00:00

Compare commits

...

16 Commits

Author SHA1 Message Date
Mark Paluch 033b3fbf55 Release version 5.1.7 (2023.0.7).
See #2770
2023-12-15 13:15:05 +01:00
Mark Paluch b9c8c2ef7e Prepare 5.1.7 (2023.0.7).
See #2770
2023-12-15 13:14:52 +01:00
Mark Paluch 37c78e4289 Update CI properties.
See #2770
2023-12-14 08:50:13 +01:00
Mark Paluch 0122f61ec0 Upgrade to Maven Wrapper 3.9.6.
See #2800
2023-12-14 08:37:40 +01:00
Peter-Josef Meisch b775357524 Fix type of returned sort values.
Original Pull Request #2786
Closes #2777

(cherry picked from commit 3833975a1a)
(cherry picked from commit 0fb98eda39)
2023-11-30 21:09:49 +01:00
Mark Paluch c9fe8a29b9 Introduce property for Jenkins user and Artifactory server details.
Closes #2781
2023-11-27 11:18:52 +01:00
Mark Paluch c444bbd65f After release cleanups.
See #2736
2023-11-17 13:41:01 +01:00
Mark Paluch 9c1b001da1 Prepare next development iteration.
See #2736
2023-11-17 13:40:59 +01:00
Mark Paluch ea234c7b68 Release version 5.1.6 (2023.0.6).
See #2736
2023-11-17 13:38:04 +01:00
Mark Paluch 42af6e375c Prepare 5.1.6 (2023.0.6).
See #2736
2023-11-17 13:37:52 +01:00
Peter-Josef Meisch 5dfd05992f Upgrade dependency of deprecated Elasticsearch client to 7.17.15.
Origina Pull Request #2769
Closes #2765
2023-11-15 21:38:17 +01:00
Peter-Josef Meisch 64cf9566d9 Use routing info on delete operations.
Original Pull Request #2755
Closes #2754

(cherry picked from commit 9abcacb2e9)
2023-11-06 22:17:04 +01:00
Peter-Josef Meisch 2c857178f4 Fix reactive native sort.
Original Pull Request #2746
Closes #2745

(cherry picked from commit 73fe0869e6)
2023-10-23 21:50:50 +02:00
Peter-Josef Meisch f087d5aac3 Fix field parameters in search request creation.
Original Pull Request #2739
Closes #2727
2023-10-14 11:17:09 +02:00
John Blum fbcb76f8ad After release cleanups.
See #2699
2023-10-13 08:09:35 -07:00
John Blum ba06741c93 Prepare next development iteration.
See #2699
2023-10-13 08:09:33 -07:00
16 changed files with 210 additions and 45 deletions
+2 -2
View File
@@ -1,3 +1,3 @@
#Wed Oct 04 18:22:43 PDT 2023
#Thu Dec 14 08:37:40 CET 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.5/apache-maven-3.9.5-bin.zip
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip
Vendored
+9 -10
View File
@@ -38,8 +38,8 @@ pipeline {
steps {
script {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.docker']) {
sh 'PROFILE=none ci/verify.sh'
sh "ci/clean.sh"
sh "PROFILE=none JENKINS_USER_NAME=${p['jenkins.user.name']} ci/verify.sh"
sh "JENKINS_USER_NAME=${p['jenkins.user.name']} ci/clean.sh"
}
}
}
@@ -65,8 +65,8 @@ pipeline {
steps {
script {
docker.image(p['docker.java.next.image']).inside(p['docker.java.inside.docker']) {
sh 'PROFILE=none ci/verify.sh'
sh "ci/clean.sh"
sh "PROFILE=none JENKINS_USER_NAME=${p['jenkins.user.name']} ci/verify.sh"
sh "JENKINS_USER_NAME=${p['jenkins.user.name']} ci/clean.sh"
}
}
}
@@ -86,22 +86,21 @@ pipeline {
label 'data'
}
options { timeout(time: 20, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
}
steps {
script {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.basic']) {
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml -Pci,artifactory -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch-non-root ' +
'-Dartifactory.server=https://repo.spring.io ' +
sh 'MAVEN_OPTS="-Duser.name=' + "${p['jenkins.user.name']}" + ' -Duser.home=/tmp/jenkins-home" ' +
"./mvnw -s settings.xml -Pci,artifactory -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch-non-root " +
"-Dartifactory.server=${p['artifactory.url']} " +
"-Dartifactory.username=${ARTIFACTORY_USR} " +
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
"-Dartifactory.staging-repository=libs-snapshot-local " +
"-Dartifactory.staging-repository=${p['artifactory.repository.snapshot']} " +
"-Dartifactory.build-name=spring-data-elasticsearch " +
"-Dartifactory.build-number=${BUILD_NUMBER} " +
'-Dmaven.test.skip=true clean deploy -U -B'
"-Dmaven.test.skip=true clean deploy -U -B"
}
}
}
+3 -1
View File
@@ -2,5 +2,7 @@
set -euo pipefail
MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" \
export JENKINS_USER=${JENKINS_USER_NAME}
MAVEN_OPTS="-Duser.name=${JENKINS_USER} -Duser.home=/tmp/jenkins-home" \
./mvnw -s settings.xml clean -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch
+4 -1
View File
@@ -1,5 +1,5 @@
# Java versions
java.main.tag=17.0.8_7-jdk-focal
java.main.tag=17.0.9_9-jdk-focal
java.next.tag=20-jdk-jammy
# Docker container images - standard
@@ -25,3 +25,6 @@ docker.java.inside.docker=-u root -v /var/run/docker.sock:/var/run/docker.sock -
docker.registry=
docker.credentials=hub.docker.com-springbuildmaster
artifactory.credentials=02bd1690-b54f-4c9f-819d-a77cb7a9822c
artifactory.url=https://repo.spring.io
artifactory.repository.snapshot=libs-snapshot-local
jenkins.user.name=spring-builds+jenkins
+4 -2
View File
@@ -5,6 +5,8 @@ set -euo pipefail
mkdir -p /tmp/jenkins-home/.m2/spring-data-elasticsearch
chown -R 1001:1001 .
MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" \
export JENKINS_USER=${JENKINS_USER_NAME}
MAVEN_OPTS="-Duser.name=${JENKINS_USER} -Duser.home=/tmp/jenkins-home" \
./mvnw -s settings.xml \
-P${PROFILE} clean dependency:list verify -Dsort -U -B -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch
-P${PROFILE} clean dependency:list verify -Dsort -U -B -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch
+4 -4
View File
@@ -5,12 +5,12 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>5.1.5</version>
<version>5.1.7</version>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>3.1.5</version>
<version>3.1.7</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.5</springdata.commons>
<springdata.commons>3.1.7</springdata.commons>
<!-- version of the RestHighLevelClient -->
<elasticsearch-rhlc>7.17.14</elasticsearch-rhlc>
<elasticsearch-rhlc>7.17.15</elasticsearch-rhlc>
<!-- version of the new ElasticsearchClient -->
<elasticsearch-java>8.7.1</elasticsearch-java>
@@ -138,7 +138,7 @@ final class DocumentAdapters {
document.setPrimaryTerm(hit.primaryTerm() != null && hit.primaryTerm() > 0 ? hit.primaryTerm() : 0);
float score = hit.score() != null ? hit.score().floatValue() : Float.NaN;
return new SearchDocumentAdapter(document, score, hit.sort().stream().map(TypeUtils::toString).toArray(),
return new SearchDocumentAdapter(document, score, hit.sort().stream().map(TypeUtils::toObject).toArray(),
documentFields, highlightFields, innerHits, nestedMetaData, explanation, matchedQueries, hit.routing());
}
@@ -1186,10 +1186,9 @@ class RequestConverter {
}
if (!isEmpty(query.getFields())) {
bb.fields(fb -> {
query.getFields().forEach(fb::field);
return fb;
});
var fieldAndFormats = query.getFields().stream()
.map(field -> FieldAndFormat.of(b -> b.field(field))).toList();
bb.fields(fieldAndFormats);
}
if (!isEmpty(query.getStoredFields())) {
@@ -1321,10 +1320,9 @@ class RequestConverter {
}
if (!isEmpty(query.getFields())) {
builder.fields(fb -> {
query.getFields().forEach(fb::field);
return fb;
});
var fieldAndFormats = query.getFields().stream()
.map(field -> FieldAndFormat.of(b -> b.field(field))).toList();
builder.fields(fieldAndFormats);
}
if (!isEmpty(query.getStoredFields())) {
@@ -1343,14 +1341,6 @@ class RequestConverter {
builder.minScore((double) query.getMinScore());
}
if (query.getSort() != null) {
List<SortOptions> sortOptions = getSortOptions(query.getSort(), persistentEntity);
if (!sortOptions.isEmpty()) {
builder.sort(sortOptions);
}
}
addHighlight(query, builder);
query.getScriptedFields().forEach(scriptedField -> builder.scriptFields(scriptedField.getFieldName(),
@@ -1359,6 +1349,15 @@ class RequestConverter {
if (query instanceof NativeQuery) {
prepareNativeSearch((NativeQuery) query, builder);
}
// query.getSort() must be checked after prepareNativeSearch as this already might hav a sort set that must have
// higher priority
if (query.getSort() != null) {
List<SortOptions> sortOptions = getSortOptions(query.getSort(), persistentEntity);
if (!sortOptions.isEmpty()) {
builder.sort(sortOptions);
}
}
if (query.getTrackTotalHits() != null) {
// logic from the RHLC, choose between -1 and Integer.MAX_VALUE
@@ -748,6 +748,12 @@ abstract public class AbstractReactiveElasticsearchTemplate
public abstract Mono<String> getClusterVersion();
@Nullable
public String getEntityRouting(Object entity) {
return entityOperations.forEntity(entity, converter.getConversionService(), routingResolver)
.getRouting();
}
/**
* Value class to capture client independent information from a response to an index request.
*/
@@ -117,6 +117,17 @@ public interface ReactiveElasticsearchOperations
ReactiveClusterOperations cluster();
// region routing
/**
* gets the routing for an entity.
*
* @param entity the entity
* @return the routing, may be null if not set.
* @since 5.2
*/
@Nullable
String getEntityRouting(Object entity);
// region customizations
/**
* Returns a copy of this instance with the same configuration, but that uses a different {@link RoutingResolver} to
* obtain routing information.
@@ -39,6 +39,7 @@ import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.BaseQuery;
import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.routing.RoutingResolver;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.data.util.StreamUtils;
import org.springframework.data.util.Streamable;
@@ -223,7 +224,7 @@ public class SimpleElasticsearchRepository<T, ID> implements ElasticsearchReposi
Assert.notNull(id, "Cannot delete entity with id 'null'.");
doDelete(id, getIndexCoordinates());
doDelete(id, null, getIndexCoordinates());
}
@Override
@@ -231,7 +232,7 @@ public class SimpleElasticsearchRepository<T, ID> implements ElasticsearchReposi
Assert.notNull(entity, "Cannot delete 'null' entity.");
doDelete(extractIdFromBean(entity), getIndexCoordinates());
doDelete(extractIdFromBean(entity), operations.getEntityRouting(entity), getIndexCoordinates());
}
@Override
@@ -271,10 +272,14 @@ public class SimpleElasticsearchRepository<T, ID> implements ElasticsearchReposi
deleteAllById(ids);
}
private void doDelete(@Nullable ID id, IndexCoordinates indexCoordinates) {
private void doDelete(@Nullable ID id, @Nullable String routing, IndexCoordinates indexCoordinates) {
if (id != null) {
executeAndRefresh(operations -> operations.delete(stringIdRepresentation(id), indexCoordinates));
executeAndRefresh(operations -> {
var ops = routing != null ? operations.withRouting(RoutingResolver.just(routing)) : operations;
// noinspection DataFlowIssue
return ops.delete(stringIdRepresentation(id), indexCoordinates);
});
}
}
@@ -31,6 +31,7 @@ import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersiste
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.BaseQuery;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.routing.RoutingResolver;
import org.springframework.data.elasticsearch.repository.ReactiveElasticsearchRepository;
import org.springframework.util.Assert;
@@ -196,7 +197,10 @@ public class SimpleReactiveElasticsearchRepository<T, ID> implements ReactiveEla
public Mono<Void> delete(T entity) {
Assert.notNull(entity, "Entity must not be null!");
return operations.delete(entity, entityInformation.getIndexCoordinates()) //
var routing = operations.getEntityRouting(entity);
var ops = routing != null ? operations.withRouting(RoutingResolver.just(routing)) : operations;
return ops.delete(entity, entityInformation.getIndexCoordinates()) //
.then(doRefresh());
}
+3 -1
View File
@@ -1,4 +1,4 @@
Spring Data Elasticsearch 5.1.5 (2023.0.5)
Spring Data Elasticsearch 5.1.7 (2023.0.7)
Copyright (c) [2013-2022] Pivotal Software, Inc.
This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -18,3 +18,5 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
@@ -18,6 +18,7 @@ package org.springframework.data.elasticsearch.core;
import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.elasticsearch.client.elc.Queries.*;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch._types.aggregations.Buckets;
import co.elastic.clients.elasticsearch._types.aggregations.StringTermsAggregate;
@@ -27,9 +28,12 @@ import co.elastic.clients.elasticsearch.core.search.FieldCollapse;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.client.elc.Aggregation;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchAggregation;
import org.springframework.data.elasticsearch.client.elc.NativeQuery;
@@ -48,6 +52,51 @@ import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration(classes = ReactiveElasticsearchELCIntegrationTests.Config.class)
public class ReactiveElasticsearchELCIntegrationTests extends ReactiveElasticsearchIntegrationTests {
@Test // #2745
@DisplayName("should use sort defined in native unbounded query")
void shouldUseSortDefinedInNativeUnboundedQuery() {
var entity1 = randomEntity(null);
entity1.setRate(7);
var entity2 = randomEntity(null);
entity2.setRate(5);
var entity3 = randomEntity(null);
entity3.setRate(11);
operations.saveAll(List.of(entity1, entity2, entity3), SampleEntity.class).blockLast();
var query = NativeQuery.builder()
.withQuery(qb -> qb
.matchAll(m -> m))
.withSort(sob -> sob
.field(f -> f
.field("rate")
.order(SortOrder.Asc)))
.withPageable(Pageable.unpaged())
.build();
var rates = operations.search(query, SampleEntity.class)
.map(SearchHit::getContent)
.map(SampleEntity::getRate)
.collectList().block();
assertThat(rates).containsExactly(5, 7, 11);
query = NativeQuery.builder()
.withQuery(qb -> qb
.matchAll(m -> m))
.withSort(sob -> sob
.field(f -> f
.field("rate")
.order(SortOrder.Desc)))
.withPageable(Pageable.unpaged())
.build();
rates = operations.search(query, SampleEntity.class)
.map(SearchHit::getContent)
.map(SampleEntity::getRate)
.collectList().block();
assertThat(rates).containsExactly(11, 7, 5);
}
@Configuration
@Import({ ReactiveElasticsearchTemplateConfiguration.class })
static class Config {
@@ -99,7 +99,7 @@ import org.springframework.util.StringUtils;
@SpringIntegrationTest
public abstract class ReactiveElasticsearchIntegrationTests {
@Autowired private ReactiveElasticsearchOperations operations;
@Autowired protected ReactiveElasticsearchOperations operations;
@Autowired private IndexNameProvider indexNameProvider;
// region Setup
@@ -1205,7 +1205,7 @@ public abstract class ReactiveElasticsearchIntegrationTests {
// endregion
// region Helper functions
private SampleEntity randomEntity(String message) {
protected SampleEntity randomEntity(@Nullable String message) {
SampleEntity entity = new SampleEntity();
entity.setId(UUID.randomUUID().toString());
@@ -31,6 +31,7 @@ import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.Mapping;
import org.springframework.data.elasticsearch.annotations.ScriptedField;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
@@ -95,6 +96,88 @@ public abstract class RuntimeFieldsIntegrationTests {
assertThat(searchHits.getSearchHit(0).getId()).isEqualTo("1");
}
@Test // #2727
@DisplayName("should return runtime fields values")
void shouldReturnRuntimeFieldsValues() {
var entity = new SAREntity();
entity.setId("42");
entity.setValue(3);
operations.save(entity);
var runtimeField1 = getRuntimeField("scriptedValue1", 2);
var runtimeField2 = getRuntimeField("scriptedValue2", 3);
var query = CriteriaQuery.builder(Criteria.where("value").is(3)).build();
query.addRuntimeField(runtimeField1);
query.addRuntimeField(runtimeField2);
query.addSourceFilter(new FetchSourceFilterBuilder().withIncludes("*").build());
query.addFields("scriptedValue1", "scriptedValue2");
var searchHits = operations.search(query, SAREntity.class);
assertThat(searchHits.getTotalHits()).isEqualTo(1);
var foundEntity = searchHits.getSearchHit(0).getContent();
assertThat(foundEntity.value).isEqualTo(3);
assertThat(foundEntity.getScriptedValue1()).isEqualTo(6);
assertThat(foundEntity.getScriptedValue2()).isEqualTo(9);
}
@Document(indexName = "#{@indexNameProvider.indexName()}-sar")
public static class SAREntity {
@Nullable private String id;
@Field(type = FieldType.Integer)
@Nullable Integer value;
@ScriptedField
@Nullable Integer scriptedValue1;
@ScriptedField
@Nullable Integer scriptedValue2;
// getter and setter omitted
@Nullable
public String getId() {
return id;
}
public void setId(@Nullable String id) {
this.id = id;
}
@Nullable
public Integer getValue() {
return value;
}
public void setValue(@Nullable Integer value) {
this.value = value;
}
@Nullable
public Integer getScriptedValue1() {
return scriptedValue1;
}
public void setScriptedValue1(@Nullable Integer scriptedValue1) {
this.scriptedValue1 = scriptedValue1;
}
@Nullable
public Integer getScriptedValue2() {
return scriptedValue2;
}
public void setScriptedValue2(@Nullable Integer scriptedValue2) {
this.scriptedValue2 = scriptedValue2;
}
}
private static RuntimeField getRuntimeField(String fieldName, int factor) {
return new RuntimeField(
fieldName,
"long",
String.format("emit(doc['value'].size() > 0 ? doc['value'].value * %d : 0)", factor));
}
@Test // #2431
@DisplayName("should return value from runtime field defined in mapping")
void shouldReturnValueFromRuntimeFieldDefinedInMapping() {