Compare commits

...

65 Commits
main ... 5.1.7

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 3833975a1ad76ef9c90b1260b090ff1eb9af523c)
(cherry picked from commit 0fb98eda39532ba1091a27a6acffe732c27d846f)
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 9abcacb2e9dfcebc9629d563072bdb85632630a9)
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 73fe0869e67db5aa45302658db14a930aa8cf32f)
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
John Blum
a228629c7d
Release version 5.1.5 (2023.0.5).
See #2699
2023-10-13 08:01:15 -07:00
John Blum
6fd688f3a2
Prepare 5.1.5 (2023.0.5).
See #2699
2023-10-13 08:00:48 -07:00
Peter-Josef Meisch
7d85f0bdd8
Upgrade to Elasticsearch 7.17.14.
Original Pull Request #2732
2023-10-13 08:37:45 +02:00
John Blum
c7534fa8b9
Upgrade to Maven Wrapper 3.9.5.
See #2715
2023-10-04 18:22:43 -07:00
John Blum
fe9e0b5d0c
Update CI properties.
See #2699
2023-10-04 17:46:55 -07:00
Peter-Josef Meisch
d26d01bab1 Fix converting of Range<?> in Lists.
Original Pull Request #2707
Closes #2706

(cherry picked from commit 3330d65edf37d3f07d50ed229002ce7a6b9b0b64)
2023-09-23 12:53:19 +02:00
Mark Paluch
026be264fe
After release cleanups.
See #2674
2023-09-15 10:55:36 +02:00
Mark Paluch
fd1ba5869d
Prepare next development iteration.
See #2674
2023-09-15 10:55:34 +02:00
Mark Paluch
7f3035dab5
Release version 5.1.4 (2023.0.4).
See #2674
2023-09-15 10:52:26 +02:00
Mark Paluch
a5c4867684
Prepare 5.1.4 (2023.0.4).
See #2674
2023-09-15 10:52:12 +02:00
Peter-Josef Meisch
572cc7ffea
Fix refresh policy in UpdateQuery.
Original Pull Request #2696
Closes #2692

(cherry picked from commit 2d0aee08ce00d84dd874b0d46da731b688f1ce61)
2023-09-13 21:49:19 +02:00
Peter-Josef Meisch
4e7bcac5f5
Upgrade deprecated client to Elasticsearch-7.17.13.
Original Pull Request #2694
Closes #2688
2023-09-13 19:38:50 +02:00
Peter-Josef Meisch
4628908e84
Polishing.
(cherry picked from commit a82952b12435d069c2fb6904528b6f71ece40c78)
2023-09-03 15:44:09 +02:00
Sébastien Comeau
922f4b1760
Fix: missing PhraseSuggestion.Entry.Option's score and collateMatch values.
Original Pull Request #2680
Closes #2681

(cherry picked from commit 7c466395c42e3802be03879f2ac2055170b4692e)
2023-09-03 15:44:08 +02:00
Peter-Josef Meisch
4614c62bb5
Fix search_after field values (#2679)
Closes #2678

(cherry picked from commit 9adc4d2b368fc600e58ac5d15c02cdc78c0dd743)
2023-08-28 20:27:21 +02:00
Mark Paluch
063020f8b3
After release cleanups.
See #2631
2023-08-18 14:07:36 +02:00
Mark Paluch
0c98c419c9
Prepare next development iteration.
See #2631
2023-08-18 14:07:34 +02:00
Mark Paluch
3f085b2675
Release version 5.1.3 (2023.0.3).
See #2631
2023-08-18 14:04:04 +02:00
Mark Paluch
42aeb48b43
Prepare 5.1.3 (2023.0.3).
See #2631
2023-08-18 14:03:49 +02:00
Julia Lee
449910b4f7
Update CI properties.
See #2631
2023-08-14 11:29:43 -04:00
Julia Lee
2e99f5b2e0
Upgrade to Maven Wrapper 3.9.4.
See #2669
2023-08-14 07:55:32 -04:00
Peter-Josef Meisch
9b9136d852 Fix similarity field mapping.
Original Pull Request #2666
Closes #2659

(cherry picked from commit 8c5ff92cd2ec2177452dc0aa1b9307bdfcfa4e75)
2023-08-13 21:40:31 +02:00
Peter-Josef Meisch
a266d7c46a
Upgrade deprecated dependency to Elasticsearch 7.17.12.
Original Pull Request #2655
#Closes #2651
2023-07-30 19:51:01 +02:00
Peter-Josef Meisch
c045a8ae29
Fix MappingElasticsearchConverter.
Original Pull Request #2637
Closes #2627

(cherry picked from commit d9bb9911f91f2da8723e579fb3962ecf13a5a651)
2023-07-18 22:51:45 +02:00
Mark Paluch
11c87a1251
After release cleanups.
See #2595
2023-07-14 13:57:59 +02:00
Mark Paluch
c9e9bf757e
Prepare next development iteration.
See #2595
2023-07-14 13:57:58 +02:00
Mark Paluch
db8d89aeff
Release version 5.1.2 (2023.0.2).
See #2595
2023-07-14 13:54:08 +02:00
Mark Paluch
0ed14e7caa
Prepare 5.1.2 (2023.0.2).
See #2595
2023-07-14 13:52:55 +02:00
Peter-Josef Meisch
d0658affc3
Upgrade to Elasticsearch 7.17.11.
Original Pull Request #2625
Closes #2622
2023-07-12 20:05:40 +02:00
Mark Paluch
7c10128cec
Update CI properties.
See #2595
2023-07-03 09:49:00 +02:00
Mark Paluch
6e3535d68d
Upgrade to Maven Wrapper 3.9.3.
See #2614
2023-07-03 09:48:29 +02:00
Peter-Josef Meisch
121b47e1be
Fix IndicesBoost error.
Original Pull Request #2606
Closes #2598

(cherry picked from commit d9fd722bb6af81068fb9b723b77c60efddbf06d3)
2023-06-27 22:28:16 +02:00
Greg L. Turnquist
3abe6d9c1b
Stop posting build status on internal Slack.
See #2603
2023-06-26 13:38:20 -05:00
seunghyun.cheong
d43b44ba9c
Adding GeoDistanceOrder's direction in request.
Original Pull Request #2602
Closes #2601

(cherry picked from commit 8a164b103937d6911f388ecd106996578119a599)

Polishing

(cherry picked from commit b7570ffa957254d114e161cf73e173135fb3ee54)

add implementation for old client
2023-06-24 11:16:14 +02:00
John Blum
a715d2836d
After release cleanups.
See #2548
2023-06-16 08:13:31 -07:00
John Blum
a69b95867a
Prepare next development iteration.
See #2548
2023-06-16 08:13:28 -07:00
John Blum
d424195c8b
Release version 5.1.1 (2023.0.1).
See #2548
2023-06-16 08:05:37 -07:00
John Blum
44d1614a20
Prepare 5.1.1 (2023.0.1).
See #2548
2023-06-16 08:05:07 -07:00
Mark Paluch
7b6823cc31
Upgrade to Maven Wrapper 3.9.2.
See #2588
2023-06-13 08:54:05 +02:00
Mark Paluch
2e43c7800b
Reformat pom.xml.
See #2585
2023-06-06 10:57:04 +02:00
Mark Paluch
59968e8118
Use snapshot and milestone repositories instead of libs-snapshot and libs-milestone.
Closes #2585
2023-06-06 10:56:48 +02:00
Peter-Josef Meisch
a5934442bf
Fix reactive save of Flux.
Original Pull Request #2581
Closes #2576

(cherry picked from commit d6b55406142abe2f72d2da29f7180621d0380b08)
2023-06-02 17:39:16 +02:00
Peter-Josef Meisch
89afa819f3
Polishing
(cherry picked from commit 6edd3cf1fe98d11ddd4b42102b01b84e8a2c0e0f)
2023-05-17 20:23:23 +02:00
Pierre Mazieres @Semarchy
5561a5b1ae
"BaseQuery" class : the "build" method does not apply to the "runtimeFields" field.
Original Pull Request #2568
Closes #2567

(cherry picked from commit 7b527c44511d0e45e0246ae2ee758cd522685aeb)
2023-05-17 20:23:23 +02:00
Peter-Josef Meisch
23a5071ee5
Upgrade to Elasticsearch 8.7.1.
Closes #2541

(cherry picked from commit af924c2cbcab1ab25f80ab4c446356e7ebde3339)
2023-05-12 22:35:53 +02:00
Peter-Josef Meisch
d1324a26db
Documentation misses link to migration page 5.0 -> 5.1.
Original Pull Request #2554
Closes #2553
2023-05-12 18:59:21 +02:00
Mark Paluch
34e3e8f5da
Update Jenkins triggers after GA release.
See #2532
2023-05-12 14:47:15 +02:00
Christoph Strobl
1571b9b4e2
After release cleanups.
See #2532
2023-05-12 14:19:11 +02:00
Christoph Strobl
78e7dd2764
Prepare next development iteration.
See #2532
2023-05-12 14:19:10 +02:00
37 changed files with 1233 additions and 648 deletions

View File

@ -1,3 +1,3 @@
#Thu Apr 06 16:16:37 CEST 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 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.1/apache-maven-3.9.1-bin.zip distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip

25
Jenkinsfile vendored
View File

@ -9,7 +9,7 @@ pipeline {
triggers { triggers {
pollSCM 'H/10 * * * *' pollSCM 'H/10 * * * *'
upstream(upstreamProjects: "spring-data-commons/main", threshold: hudson.model.Result.SUCCESS) upstream(upstreamProjects: "spring-data-commons/3.1.x", threshold: hudson.model.Result.SUCCESS)
} }
options { options {
@ -38,8 +38,8 @@ pipeline {
steps { steps {
script { script {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.docker']) { docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.docker']) {
sh 'PROFILE=none ci/verify.sh' sh "PROFILE=none JENKINS_USER_NAME=${p['jenkins.user.name']} ci/verify.sh"
sh "ci/clean.sh" sh "JENKINS_USER_NAME=${p['jenkins.user.name']} ci/clean.sh"
} }
} }
} }
@ -65,8 +65,8 @@ pipeline {
steps { steps {
script { script {
docker.image(p['docker.java.next.image']).inside(p['docker.java.inside.docker']) { docker.image(p['docker.java.next.image']).inside(p['docker.java.inside.docker']) {
sh 'PROFILE=none ci/verify.sh' sh "PROFILE=none JENKINS_USER_NAME=${p['jenkins.user.name']} ci/verify.sh"
sh "ci/clean.sh" sh "JENKINS_USER_NAME=${p['jenkins.user.name']} ci/clean.sh"
} }
} }
} }
@ -86,22 +86,21 @@ pipeline {
label 'data' label 'data'
} }
options { timeout(time: 20, unit: 'MINUTES') } options { timeout(time: 20, unit: 'MINUTES') }
environment { environment {
ARTIFACTORY = credentials("${p['artifactory.credentials']}") ARTIFACTORY = credentials("${p['artifactory.credentials']}")
} }
steps { steps {
script { script {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.basic']) { 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 ' + sh 'MAVEN_OPTS="-Duser.name=' + "${p['jenkins.user.name']}" + ' -Duser.home=/tmp/jenkins-home" ' +
'-Dartifactory.server=https://repo.spring.io ' + "./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.username=${ARTIFACTORY_USR} " +
"-Dartifactory.password=${ARTIFACTORY_PSW} " + "-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-name=spring-data-elasticsearch " +
"-Dartifactory.build-number=${BUILD_NUMBER} " + "-Dartifactory.build-number=${BUILD_NUMBER} " +
'-Dmaven.test.skip=true clean deploy -U -B' "-Dmaven.test.skip=true clean deploy -U -B"
} }
} }
} }
@ -111,10 +110,6 @@ pipeline {
post { post {
changed { changed {
script { script {
slackSend(
color: (currentBuild.currentResult == 'SUCCESS') ? 'good' : 'danger',
channel: '#spring-data-dev',
message: "${currentBuild.fullDisplayName} - `${currentBuild.currentResult}`\n${env.BUILD_URL}")
emailext( emailext(
subject: "[${currentBuild.fullDisplayName}] ${currentBuild.currentResult}", subject: "[${currentBuild.fullDisplayName}] ${currentBuild.currentResult}",
mimeType: 'text/html', mimeType: 'text/html',

View File

@ -137,9 +137,9 @@ To use the Release candidate versions of the upcoming major version, use our Mav
</dependency> </dependency>
<repository> <repository>
<id>spring-libs-snapshot</id> <id>spring-snapshot</id>
<name>Spring Snapshot Repository</name> <name>Spring Snapshot Repository</name>
<url>https://repo.spring.io/libs-milestone</url> <url>https://repo.spring.io/milestone</url>
</repository> </repository>
---- ----
@ -154,9 +154,9 @@ If you'd rather like the latest snapshots of the upcoming major version, use our
</dependency> </dependency>
<repository> <repository>
<id>spring-libs-snapshot</id> <id>spring-snapshot</id>
<name>Spring Snapshot Repository</name> <name>Spring Snapshot Repository</name>
<url>https://repo.spring.io/libs-snapshot</url> <url>https://repo.spring.io/snapshot</url>
</repository> </repository>
---- ----

View File

@ -2,5 +2,7 @@
set -euo pipefail 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 ./mvnw -s settings.xml clean -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch

View File

@ -1,5 +1,5 @@
# Java versions # Java versions
java.main.tag=17.0.6_10-jdk-focal java.main.tag=17.0.9_9-jdk-focal
java.next.tag=20-jdk-jammy java.next.tag=20-jdk-jammy
# Docker container images - standard # Docker container images - standard
@ -7,15 +7,15 @@ 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} docker.java.next.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.next.tag}
# Supported versions of MongoDB # Supported versions of MongoDB
docker.mongodb.4.4.version=4.4.18 docker.mongodb.4.4.version=4.4.25
docker.mongodb.5.0.version=5.0.14 docker.mongodb.5.0.version=5.0.21
docker.mongodb.6.0.version=6.0.4 docker.mongodb.6.0.version=6.0.10
# Supported versions of Redis # Supported versions of Redis
docker.redis.6.version=6.2.10 docker.redis.6.version=6.2.13
# Supported versions of Cassandra # Supported versions of Cassandra
docker.cassandra.3.version=3.11.14 docker.cassandra.3.version=3.11.16
# Docker environment settings # Docker environment settings
docker.java.inside.basic=-v $HOME:/tmp/jenkins-home docker.java.inside.basic=-v $HOME:/tmp/jenkins-home
@ -25,3 +25,6 @@ docker.java.inside.docker=-u root -v /var/run/docker.sock:/var/run/docker.sock -
docker.registry= docker.registry=
docker.credentials=hub.docker.com-springbuildmaster docker.credentials=hub.docker.com-springbuildmaster
artifactory.credentials=02bd1690-b54f-4c9f-819d-a77cb7a9822c 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

View File

@ -5,6 +5,8 @@ set -euo pipefail
mkdir -p /tmp/jenkins-home/.m2/spring-data-elasticsearch mkdir -p /tmp/jenkins-home/.m2/spring-data-elasticsearch
chown -R 1001:1001 . 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 \ ./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

913
pom.xml
View File

@ -1,486 +1,471 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.data</groupId> <groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId> <artifactId>spring-data-elasticsearch</artifactId>
<version>5.1.0</version> <version>5.1.7</version>
<parent> <parent>
<groupId>org.springframework.data.build</groupId> <groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId> <artifactId>spring-data-parent</artifactId>
<version>3.1.0</version> <version>3.1.7</version>
</parent> </parent>
<name>Spring Data Elasticsearch</name> <name>Spring Data Elasticsearch</name>
<description>Spring Data Implementation for Elasticsearch</description> <description>Spring Data Implementation for Elasticsearch</description>
<url>https://github.com/spring-projects/spring-data-elasticsearch</url>
<properties>
<springdata.commons>3.1.7</springdata.commons>
<!-- version of the RestHighLevelClient -->
<elasticsearch-rhlc>7.17.15</elasticsearch-rhlc>
<!-- version of the new ElasticsearchClient -->
<elasticsearch-java>8.7.1</elasticsearch-java>
<log4j>2.18.0</log4j>
<!-- netty dependency can be removed once the WebClient code is gone -->
<netty>4.1.90.Final</netty>
<blockhound-junit>1.0.8.RELEASE</blockhound-junit>
<hoverfly>0.14.4</hoverfly>
<jsonassert>1.5.1</jsonassert>
<testcontainers>1.18.0</testcontainers>
<wiremock>2.35.0</wiremock>
<java-module-name>spring.data.elasticsearch</java-module-name>
<!--
properties defining the maven phase for the tests and integration tests
set to "none" to disable the corresponding test execution (-Dmvn.unit-test.goal=none)
default execution for unit-test: "test", for the integration tests: "integration-test"
-->
<mvn.unit-test.goal>test</mvn.unit-test.goal>
<mvn.integration-test-elasticsearch.goal>integration-test</mvn.integration-test-elasticsearch.goal>
</properties>
<developers>
<developer>
<id>biomedcentral</id>
<name>BioMed Central Development Team</name>
<timezone>+0</timezone>
</developer>
<developer>
<id>cstrobl</id>
<name>Christoph Strobl</name>
<email>cstrobl at pivotal.io</email>
<organization>Pivotal</organization>
<organizationUrl>https://www.pivotal.io</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>+1</timezone>
</developer>
<developer>
<id>mpaluch</id>
<name>Mark Paluch</name>
<email>mpaluch at pivotal.io</email>
<organization>Pivotal</organization>
<organizationUrl>https://www.pivotal.io</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>+1</timezone>
</developer>
</developers>
<scm>
<url>https://github.com/spring-projects/spring-data-elasticsearch</url> <url>https://github.com/spring-projects/spring-data-elasticsearch</url>
<connection>scm:git:git://github.com/spring-projects/spring-data-elasticsearch.git</connection>
<developerConnection>scm:git:ssh://git@github.com/spring-projects/spring-data-elasticsearch.git
</developerConnection>
</scm>
<properties> <ciManagement>
<springdata.commons>3.1.0</springdata.commons> <system>Bamboo</system>
<url>https://build.spring.io/browse/SPRINGDATAES</url>
</ciManagement>
<!-- version of the RestHighLevelClient --> <issueManagement>
<elasticsearch-rhlc>7.17.9</elasticsearch-rhlc> <system>GitHub</system>
<!-- version of the new ElasticsearchClient --> <url>https://github.com/spring-projects/spring-data-elasticsearch/issues</url>
<elasticsearch-java>8.7.0</elasticsearch-java> </issueManagement>
<log4j>2.18.0</log4j>
<!-- netty dependency can be removed once the WebClient code is gone -->
<netty>4.1.90.Final</netty>
<blockhound-junit>1.0.8.RELEASE</blockhound-junit>
<hoverfly>0.14.4</hoverfly>
<jsonassert>1.5.1</jsonassert>
<testcontainers>1.18.0</testcontainers>
<wiremock>2.35.0</wiremock>
<java-module-name>spring.data.elasticsearch</java-module-name>
<!--
properties defining the maven phase for the tests and integration tests
set to "none" to disable the corresponding test execution (-Dmvn.unit-test.goal=none)
default execution for unit-test: "test", for the integration tests: "integration-test"
-->
<mvn.unit-test.goal>test</mvn.unit-test.goal>
<mvn.integration-test-elasticsearch.goal>integration-test</mvn.integration-test-elasticsearch.goal>
</properties>
<developers>
<developer>
<id>biomedcentral</id>
<name>BioMed Central Development Team</name>
<timezone>+0</timezone>
</developer>
<developer>
<id>cstrobl</id>
<name>Christoph Strobl</name>
<email>cstrobl at pivotal.io</email>
<organization>Pivotal</organization>
<organizationUrl>https://www.pivotal.io</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>+1</timezone>
</developer>
<developer>
<id>mpaluch</id>
<name>Mark Paluch</name>
<email>mpaluch at pivotal.io</email>
<organization>Pivotal</organization>
<organizationUrl>https://www.pivotal.io</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>+1</timezone>
</developer>
</developers>
<scm>
<url>https://github.com/spring-projects/spring-data-elasticsearch</url>
<connection>scm:git:git://github.com/spring-projects/spring-data-elasticsearch.git</connection>
<developerConnection>scm:git:ssh://git@github.com/spring-projects/spring-data-elasticsearch.git
</developerConnection>
</scm>
<ciManagement>
<system>Bamboo</system>
<url>https://build.spring.io/browse/SPRINGDATAES</url>
</ciManagement>
<issueManagement>
<system>GitHub</system>
<url>https://github.com/spring-projects/spring-data-elasticsearch/issues</url>
</issueManagement>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-bom</artifactId>
<version>${netty}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencyManagement>
<dependencies> <dependencies>
<dependency>
<!-- Spring --> <groupId>io.netty</groupId>
<dependency> <artifactId>netty-bom</artifactId>
<groupId>org.springframework</groupId> <version>${netty}</version>
<artifactId>spring-context</artifactId> <type>pom</type>
</dependency> <scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<!-- SPRING DATA -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>${springdata.commons}</version>
</dependency>
<!-- Reactive Infrastructure -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty-http</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<!-- optional Elasticsearch RestHighLevelClient, deprecated in SDE 5.0 -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>${elasticsearch-rhlc}</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- new Elasticsearch client, needs the low-level rest client and json api -->
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>${elasticsearch-java}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId> <!-- is Apache 2-->
<version>${elasticsearch-java}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Jackson JSON Mapper -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- CDI -->
<dependency>
<groupId>javax.interceptor</groupId>
<artifactId>javax.interceptor-api</artifactId>
<version>1.2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>${jakarta-annotation-api}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.openwebbeans</groupId>
<artifactId>openwebbeans-se</artifactId>
<classifier>jakarta</classifier>
<version>${webbeans}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.openwebbeans</groupId>
<artifactId>openwebbeans-spi</artifactId>
<classifier>jakarta</classifier>
<version>${webbeans}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.openwebbeans</groupId>
<artifactId>openwebbeans-impl</artifactId>
<classifier>jakarta</classifier>
<version>${webbeans}</version>
<scope>test</scope>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>${slf4j}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>${log4j}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor.tools</groupId>
<artifactId>blockhound-junit-platform</artifactId>
<version>${blockhound-junit}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<version>${jsonassert}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8</artifactId>
<version>${wiremock}</version>
<scope>test</scope>
<exclusions>
<!-- these exclusions are needed because of Elasticsearch JarHell-->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
<exclusion>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.specto</groupId>
<artifactId>hoverfly-java-junit5</artifactId>
<version>${hoverfly}</version>
<scope>test</scope>
</dependency>
<!-- Upgrade xbean to 4.5 to prevent incompatibilities due to ASM versions -->
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-asm5-shaded</artifactId>
<version>4.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>elasticsearch</artifactId>
<version>${testcontainers}</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</dependencyManagement>
<build> <dependencies>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/versions.properties</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<excludes>
<exclude>**/versions.properties</exclude>
</excludes>
</resource>
</resources>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<!-- SPRING DATA -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>${springdata.commons}</version>
</dependency>
<!-- Reactive Infrastructure -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty-http</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<!-- optional Elasticsearch RestHighLevelClient, deprecated in SDE 5.0 -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>${elasticsearch-rhlc}</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- new Elasticsearch client, needs the low-level rest client and json api -->
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>${elasticsearch-java}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId> <!-- is Apache 2-->
<version>${elasticsearch-java}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Jackson JSON Mapper -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- CDI -->
<dependency>
<groupId>javax.interceptor</groupId>
<artifactId>javax.interceptor-api</artifactId>
<version>1.2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>${jakarta-annotation-api}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.openwebbeans</groupId>
<artifactId>openwebbeans-se</artifactId>
<classifier>jakarta</classifier>
<version>${webbeans}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.openwebbeans</groupId>
<artifactId>openwebbeans-spi</artifactId>
<classifier>jakarta</classifier>
<version>${webbeans}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.openwebbeans</groupId>
<artifactId>openwebbeans-impl</artifactId>
<classifier>jakarta</classifier>
<version>${webbeans}</version>
<scope>test</scope>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>${slf4j}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>${log4j}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor.tools</groupId>
<artifactId>blockhound-junit-platform</artifactId>
<version>${blockhound-junit}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<version>${jsonassert}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8</artifactId>
<version>${wiremock}</version>
<scope>test</scope>
<exclusions>
<!-- these exclusions are needed because of Elasticsearch JarHell-->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
<exclusion>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.specto</groupId>
<artifactId>hoverfly-java-junit5</artifactId>
<version>${hoverfly}</version>
<scope>test</scope>
</dependency>
<!-- Upgrade xbean to 4.5 to prevent incompatibilities due to ASM versions -->
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-asm5-shaded</artifactId>
<version>4.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>elasticsearch</artifactId>
<version>${testcontainers}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/versions.properties</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<excludes>
<exclude>**/versions.properties</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<useSystemClassLoader>true</useSystemClassLoader>
<useFile>false</useFile>
<includes>
<include>**/*Tests.java</include>
<include>**/*Test.java</include>
</includes>
<systemPropertyVariables>
<es.set.netty.runtime.available.processors>false</es.set.netty.runtime.available.processors>
</systemPropertyVariables>
</configuration>
<executions>
<!-- the default-test execution runs only the unit tests -->
<execution>
<id>default-test</id>
<phase>${mvn.unit-test.goal}</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<excludedGroups>integration-test</excludedGroups>
</configuration>
</execution>
<!-- execution to run the integration tests against Elasticsearch -->
<execution>
<id>integration-test-elasticsearch</id>
<phase>${mvn.integration-test-elasticsearch.goal}</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<groups>integration-test</groups>
<systemPropertyVariables>
<sde.integration-test.environment>elasticsearch</sde.integration-test.environment>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>ci</id>
<build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-checkstyle-plugin</artifactId>
<configuration> <configuration>
<useSystemClassLoader>true</useSystemClassLoader> <checkstyleRules>
<useFile>false</useFile> <module name="Checker">
<includes>
<include>**/*Tests.java</include> <!-- Configure checker to use UTF-8 encoding -->
<include>**/*Test.java</include> <property name="charset" value="UTF-8"/>
</includes>
<systemPropertyVariables> <module name="io.spring.nohttp.checkstyle.check.NoHttpCheck"/>
<es.set.netty.runtime.available.processors>false</es.set.netty.runtime.available.processors> </module>
</systemPropertyVariables> </checkstyleRules>
</configuration> <includes>**/*</includes>
<executions> <excludes>
<!-- the default-test execution runs only the unit tests --> .git/**/*,target/**/*,**/target/**/*,.idea/**/*,**/spring.schemas,**/*.svg,mvnw,mvnw.cmd,**/*.policy
<execution> </excludes>
<id>default-test</id> <sourceDirectories>./</sourceDirectories>
<phase>${mvn.unit-test.goal}</phase> </configuration>
<goals> </plugin>
<goal>test</goal>
</goals>
<configuration>
<excludedGroups>integration-test</excludedGroups>
</configuration>
</execution>
<!-- execution to run the integration tests against Elasticsearch -->
<execution>
<id>integration-test-elasticsearch</id>
<phase>${mvn.integration-test-elasticsearch.goal}</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<groups>integration-test</groups>
<systemPropertyVariables>
<sde.integration-test.environment>elasticsearch</sde.integration-test.environment>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
</plugin>
</plugins> </plugins>
</build> </build>
</profile>
<profiles> <profile>
<profile> <id>jdk13+</id>
<id>ci</id> <!-- on jDK13+, Blockhound needs this JVM flag set -->
<build> <activation>
<plugins> <jdk>[13,)</jdk>
<plugin> </activation>
<groupId>org.apache.maven.plugins</groupId> <build>
<artifactId>maven-checkstyle-plugin</artifactId> <plugins>
<configuration> <plugin>
<checkstyleRules> <groupId>org.apache.maven.plugins</groupId>
<module name="Checker"> <artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-XX:+AllowRedefinitionToAddDeleteMethods</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<!-- Configure checker to use UTF-8 encoding --> <repositories>
<property name="charset" value="UTF-8"/>
<module name="io.spring.nohttp.checkstyle.check.NoHttpCheck"/>
</module>
</checkstyleRules>
<includes>**/*</includes>
<excludes>
.git/**/*,target/**/*,**/target/**/*,.idea/**/*,**/spring.schemas,**/*.svg,mvnw,mvnw.cmd,**/*.policy
</excludes>
<sourceDirectories>./</sourceDirectories>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile> </repositories>
<id>jdk13+</id>
<!-- on jDK13+, Blockhound needs this JVM flag set -->
<activation>
<jdk>[13,)</jdk>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-XX:+AllowRedefinitionToAddDeleteMethods</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<repositories>
<repository>
<id>spring-libs-release</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
<repository>
<id>local-maven-repo</id>
<url>file:///${project.basedir}/src/test/resources/local-maven-repo</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-plugins-release</id>
<url>https://repo.spring.io/plugins-release</url>
</pluginRepository>
</pluginRepositories>
</project> </project>

View File

@ -17,9 +17,9 @@ include::reference/elasticsearch-new.adoc[leveloffset=+1]
* Version Control - https://github.com/spring-projects/spring-data-elasticsearch * Version Control - https://github.com/spring-projects/spring-data-elasticsearch
* API Documentation - https://docs.spring.io/spring-data/elasticsearch/docs/current/api/ * API Documentation - https://docs.spring.io/spring-data/elasticsearch/docs/current/api/
* Bugtracker - https://github.com/spring-projects/spring-data-elasticsearch/issues * Bugtracker - https://github.com/spring-projects/spring-data-elasticsearch/issues
* Release repository - https://repo.spring.io/libs-release * Release repository - https://repo1.maven.org/maven2/
* Milestone repository - https://repo.spring.io/libs-milestone * Milestone repository - https://repo.spring.io/milestone/
* Snapshot repository - https://repo.spring.io/libs-snapshot * Snapshot repository - https://repo.spring.io/snapshot/
[[preface.requirements]] [[preface.requirements]]
== Requirements == Requirements
@ -37,7 +37,7 @@ built and tested.
[cols="^,^,^,^,^",options="header"] [cols="^,^,^,^,^",options="header"]
|=== |===
| Spring Data Release Train | Spring Data Elasticsearch | Elasticsearch | Spring Framework | Spring Boot | Spring Data Release Train | Spring Data Elasticsearch | Elasticsearch | Spring Framework | Spring Boot
| 2023.0 (Ullmann) | 5.1.x | 8.7.0 | 6.0.x | 3.1.x | 2023.0 (Ullmann) | 5.1.x | 8.7.1 | 6.0.x | 3.1.x
| 2022.0 (Turing) | 5.0.x | 8.5.3 | 6.0.x | 3.0.x | 2022.0 (Turing) | 5.0.x | 8.5.3 | 6.0.x | 3.0.x
| 2021.2 (Raj) | 4.4.xfootnote:oom[Out of maintenance] | 7.17.3 | 5.3.x | 2.7.x | 2021.2 (Raj) | 4.4.xfootnote:oom[Out of maintenance] | 7.17.3 | 5.3.x | 2.7.x
| 2021.1 (Q) | 4.3.xfootnote:oom[] | 7.15.2 | 5.3.x | 2.6.x | 2021.1 (Q) | 4.3.xfootnote:oom[] | 7.15.2 | 5.3.x | 2.6.x

View File

@ -15,4 +15,6 @@ include::elasticsearch-migration-guide-4.3-4.4.adoc[]
include::elasticsearch-migration-guide-4.4-5.0.adoc[] include::elasticsearch-migration-guide-4.4-5.0.adoc[]
include::elasticsearch-migration-guide-5.0-5.1.adoc[]
:leveloffset: -1 :leveloffset: -1

View File

@ -138,7 +138,7 @@ final class DocumentAdapters {
document.setPrimaryTerm(hit.primaryTerm() != null && hit.primaryTerm() > 0 ? hit.primaryTerm() : 0); document.setPrimaryTerm(hit.primaryTerm() != null && hit.primaryTerm() > 0 ? hit.primaryTerm() : 0);
float score = hit.score() != null ? hit.score().floatValue() : Float.NaN; 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()); documentFields, highlightFields, innerHits, nestedMetaData, explanation, matchedQueries, hit.routing());
} }

View File

@ -16,18 +16,24 @@
package org.springframework.data.elasticsearch.client.elc; package org.springframework.data.elasticsearch.client.elc;
import static org.springframework.data.elasticsearch.client.elc.TypeUtils.*; import static org.springframework.data.elasticsearch.client.elc.TypeUtils.*;
import static org.springframework.util.CollectionUtils.isEmpty; import static org.springframework.util.CollectionUtils.*;
import co.elastic.clients.elasticsearch._types.*; import co.elastic.clients.elasticsearch._types.Conflicts;
import co.elastic.clients.elasticsearch._types.InlineScript;
import co.elastic.clients.elasticsearch._types.OpType;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.VersionType;
import co.elastic.clients.elasticsearch._types.WaitForActiveShardOptions;
import co.elastic.clients.elasticsearch._types.mapping.FieldType; import co.elastic.clients.elasticsearch._types.mapping.FieldType;
import co.elastic.clients.elasticsearch._types.mapping.RuntimeField; import co.elastic.clients.elasticsearch._types.mapping.RuntimeField;
import co.elastic.clients.elasticsearch._types.mapping.RuntimeFieldType; import co.elastic.clients.elasticsearch._types.mapping.RuntimeFieldType;
import co.elastic.clients.elasticsearch._types.query_dsl.FieldAndFormat; import co.elastic.clients.elasticsearch._types.query_dsl.FieldAndFormat;
import co.elastic.clients.elasticsearch._types.query_dsl.Like; import co.elastic.clients.elasticsearch._types.query_dsl.Like;
import co.elastic.clients.elasticsearch.cluster.*;
import co.elastic.clients.elasticsearch.cluster.DeleteComponentTemplateRequest; import co.elastic.clients.elasticsearch.cluster.DeleteComponentTemplateRequest;
import co.elastic.clients.elasticsearch.cluster.ExistsComponentTemplateRequest; import co.elastic.clients.elasticsearch.cluster.ExistsComponentTemplateRequest;
import co.elastic.clients.elasticsearch.cluster.GetComponentTemplateRequest; import co.elastic.clients.elasticsearch.cluster.GetComponentTemplateRequest;
import co.elastic.clients.elasticsearch.cluster.HealthRequest;
import co.elastic.clients.elasticsearch.cluster.PutComponentTemplateRequest; import co.elastic.clients.elasticsearch.cluster.PutComponentTemplateRequest;
import co.elastic.clients.elasticsearch.core.*; import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation; import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
@ -52,7 +58,12 @@ import java.io.ByteArrayInputStream;
import java.io.StringReader; import java.io.StringReader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.Duration; import java.time.Duration;
import java.util.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -988,7 +999,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(query.getRefreshPolicy() != null ? refresh(query.getRefreshPolicy()) : refresh(refreshPolicy)) //
.retryOnConflict(query.getRetryOnConflict()) // .retryOnConflict(query.getRetryOnConflict()) //
; ;
@ -1175,10 +1186,9 @@ class RequestConverter {
} }
if (!isEmpty(query.getFields())) { if (!isEmpty(query.getFields())) {
bb.fields(fb -> { var fieldAndFormats = query.getFields().stream()
query.getFields().forEach(fb::field); .map(field -> FieldAndFormat.of(b -> b.field(field))).toList();
return fb; bb.fields(fieldAndFormats);
});
} }
if (!isEmpty(query.getStoredFields())) { if (!isEmpty(query.getStoredFields())) {
@ -1208,8 +1218,7 @@ class RequestConverter {
} }
if (!isEmpty(query.getSearchAfter())) { if (!isEmpty(query.getSearchAfter())) {
bb.searchAfter(query.getSearchAfter().stream().map(it -> FieldValue.of(it.toString())) bb.searchAfter(query.getSearchAfter().stream().map(TypeUtils::toFieldValue).toList());
.collect(Collectors.toList()));
} }
query.getRescorerQueries().forEach(rescorerQuery -> bb.rescore(getRescore(rescorerQuery))); query.getRescorerQueries().forEach(rescorerQuery -> bb.rescore(getRescore(rescorerQuery)));
@ -1233,11 +1242,9 @@ class RequestConverter {
} }
if (!isEmpty(query.getIndicesBoost())) { if (!isEmpty(query.getIndicesBoost())) {
Map<String, Double> boosts = new LinkedHashMap<>(); bb.indicesBoost(query.getIndicesBoost().stream()
query.getIndicesBoost() .map(indexBoost -> Map.of(indexBoost.getIndexName(), Double.valueOf(indexBoost.getBoost())))
.forEach(indexBoost -> boosts.put(indexBoost.getIndexName(), (double) indexBoost.getBoost())); .collect(Collectors.toList()));
// noinspection unchecked
bb.indicesBoost(boosts);
} }
query.getScriptedFields().forEach(scriptedField -> bb.scriptFields(scriptedField.getFieldName(), query.getScriptedFields().forEach(scriptedField -> bb.scriptFields(scriptedField.getFieldName(),
@ -1313,10 +1320,9 @@ class RequestConverter {
} }
if (!isEmpty(query.getFields())) { if (!isEmpty(query.getFields())) {
builder.fields(fb -> { var fieldAndFormats = query.getFields().stream()
query.getFields().forEach(fb::field); .map(field -> FieldAndFormat.of(b -> b.field(field))).toList();
return fb; builder.fields(fieldAndFormats);
});
} }
if (!isEmpty(query.getStoredFields())) { if (!isEmpty(query.getStoredFields())) {
@ -1335,14 +1341,6 @@ class RequestConverter {
builder.minScore((double) query.getMinScore()); 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); addHighlight(query, builder);
query.getScriptedFields().forEach(scriptedField -> builder.scriptFields(scriptedField.getFieldName(), query.getScriptedFields().forEach(scriptedField -> builder.scriptFields(scriptedField.getFieldName(),
@ -1351,6 +1349,15 @@ class RequestConverter {
if (query instanceof NativeQuery) { if (query instanceof NativeQuery) {
prepareNativeSearch((NativeQuery) query, builder); 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) { if (query.getTrackTotalHits() != null) {
// logic from the RHLC, choose between -1 and Integer.MAX_VALUE // logic from the RHLC, choose between -1 and Integer.MAX_VALUE
@ -1365,8 +1372,7 @@ class RequestConverter {
} }
if (!isEmpty(query.getSearchAfter())) { if (!isEmpty(query.getSearchAfter())) {
builder.searchAfter( builder.searchAfter(query.getSearchAfter().stream().map(TypeUtils::toFieldValue).toList());
query.getSearchAfter().stream().map(it -> FieldValue.of(it.toString())).collect(Collectors.toList()));
} }
query.getRescorerQueries().forEach(rescorerQuery -> builder.rescore(getRescore(rescorerQuery))); query.getRescorerQueries().forEach(rescorerQuery -> builder.rescore(getRescore(rescorerQuery)));
@ -1399,11 +1405,9 @@ class RequestConverter {
} }
if (!isEmpty(query.getIndicesBoost())) { if (!isEmpty(query.getIndicesBoost())) {
Map<String, Double> boosts = new LinkedHashMap<>(); builder.indicesBoost(query.getIndicesBoost().stream()
query.getIndicesBoost() .map(indexBoost -> Map.of(indexBoost.getIndexName(), Double.valueOf(indexBoost.getBoost())))
.forEach(indexBoost -> boosts.put(indexBoost.getIndexName(), (double) indexBoost.getBoost())); .collect(Collectors.toList()));
// noinspection unchecked
builder.indicesBoost(boosts);
} }
if (!isEmpty(query.getDocValueFields())) { if (!isEmpty(query.getDocValueFields())) {
@ -1477,8 +1481,9 @@ class RequestConverter {
return SortOptions.of(so -> so // return SortOptions.of(so -> so //
.geoDistance(gd -> gd // .geoDistance(gd -> gd //
.field(fieldName) // .field(fieldName) //
.location(loc -> loc.latlon(Queries.latLon(geoDistanceOrder.getGeoPoint())))// .location(loc -> loc.latlon(Queries.latLon(geoDistanceOrder.getGeoPoint()))) //
.distanceType(geoDistanceType(geoDistanceOrder.getDistanceType())).mode(sortMode(finalMode)) // .distanceType(geoDistanceType(geoDistanceOrder.getDistanceType())).mode(sortMode(finalMode)) //
.order(sortOrder(geoDistanceOrder.getDirection())) //
.unit(distanceUnit(geoDistanceOrder.getUnit())) // .unit(distanceUnit(geoDistanceOrder.getUnit())) //
.ignoreUnmapped(geoDistanceOrder.getIgnoreUnmapped()))); .ignoreUnmapped(geoDistanceOrder.getIgnoreUnmapped())));
} else { } else {
@ -1537,8 +1542,11 @@ class RequestConverter {
builder // builder //
.suggest(query.getSuggester()) // .suggest(query.getSuggester()) //
.collapse(query.getFieldCollapse()) // .collapse(query.getFieldCollapse()) //
.sort(query.getSortOptions()) // .sort(query.getSortOptions());
.knn(query.getKnnQuery());
if (query.getKnnQuery() != null) {
builder.knn(query.getKnnQuery());
}
if (!isEmpty(query.getAggregations())) { if (!isEmpty(query.getAggregations())) {
builder.aggregations(query.getAggregations()); builder.aggregations(query.getAggregations());

View File

@ -219,7 +219,8 @@ class SearchDocumentResponseBuilder {
var phraseSuggestOptions = phraseSuggest.options(); var phraseSuggestOptions = phraseSuggest.options();
List<PhraseSuggestion.Entry.Option> options = new ArrayList<>(); List<PhraseSuggestion.Entry.Option> options = new ArrayList<>();
phraseSuggestOptions.forEach(optionES -> options 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(), entries.add(new PhraseSuggestion.Entry(phraseSuggest.text(), phraseSuggest.offset(), phraseSuggest.length(),
options, null)); options, null));
}); });

View File

@ -18,8 +18,15 @@ package org.springframework.data.elasticsearch.client.elc;
import co.elastic.clients.elasticsearch._types.*; import co.elastic.clients.elasticsearch._types.*;
import co.elastic.clients.elasticsearch._types.mapping.FieldType; import co.elastic.clients.elasticsearch._types.mapping.FieldType;
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping; 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.elasticsearch.indices.IndexSettings;
import co.elastic.clients.json.JsonData;
import java.io.StringReader; import java.io.StringReader;
import java.time.Duration; import java.time.Duration;
@ -28,10 +35,16 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.RefreshPolicy; import org.springframework.data.elasticsearch.core.RefreshPolicy;
import org.springframework.data.elasticsearch.core.document.Document; 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.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.data.elasticsearch.core.reindex.ReindexRequest;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@ -155,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 @Nullable
static GeoDistanceType geoDistanceType(GeoDistanceOrder.DistanceType distanceType) { static GeoDistanceType geoDistanceType(GeoDistanceOrder.DistanceType distanceType) {
@ -165,6 +212,20 @@ final class TypeUtils {
} }
@Nullable
static SortOrder sortOrder(@Nullable Sort.Direction direction) {
if (direction == null) {
return null;
}
return switch (direction) {
case ASC -> SortOrder.Asc;
case DESC -> SortOrder.Desc;
};
}
@Nullable @Nullable
static HighlighterFragmenter highlighterFragmenter(@Nullable String value) { static HighlighterFragmenter highlighterFragmenter(@Nullable String value) {

View File

@ -348,8 +348,8 @@ class RequestFactory {
for (String aliasName : parametersAliases) { for (String aliasName : parametersAliases) {
Alias alias = new Alias(aliasName); Alias alias = new Alias(aliasName);
//noinspection DuplicatedCode // noinspection DuplicatedCode
if (parameters.getRouting() != null) { if (parameters.getRouting() != null) {
alias.routing(parameters.getRouting()); alias.routing(parameters.getRouting());
} }
@ -526,7 +526,8 @@ class RequestFactory {
// endregion // endregion
// region delete // region delete
public DeleteByQueryRequest deleteByQueryRequest(Query query, @Nullable String routing, Class<?> clazz, IndexCoordinates index) { public DeleteByQueryRequest deleteByQueryRequest(Query query, @Nullable String routing, Class<?> clazz,
IndexCoordinates index) {
SearchRequest searchRequest = searchRequest(query, routing, clazz, index); SearchRequest searchRequest = searchRequest(query, routing, clazz, index);
DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(index.getIndexNames()) // DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(index.getIndexNames()) //
.setQuery(searchRequest.source().query()) // .setQuery(searchRequest.source().query()) //
@ -754,10 +755,11 @@ class RequestFactory {
return searchRequest; return searchRequest;
} }
public SearchRequest searchRequest(Query query, @Nullable String routing, @Nullable Class<?> clazz, IndexCoordinates index) { public SearchRequest searchRequest(Query query, @Nullable String routing, @Nullable Class<?> clazz,
IndexCoordinates index) {
elasticsearchConverter.updateQuery(query, clazz); elasticsearchConverter.updateQuery(query, clazz);
SearchRequest searchRequest = prepareSearchRequest(query, routing,clazz, index); SearchRequest searchRequest = prepareSearchRequest(query, routing, clazz, index);
QueryBuilder elasticsearchQuery = getQuery(query); QueryBuilder elasticsearchQuery = getQuery(query);
QueryBuilder elasticsearchFilter = getFilter(query); QueryBuilder elasticsearchFilter = getFilter(query);
@ -771,7 +773,8 @@ class RequestFactory {
} }
private SearchRequest prepareSearchRequest(Query query, @Nullable String routing, @Nullable Class<?> clazz, IndexCoordinates indexCoordinates) { private SearchRequest prepareSearchRequest(Query query, @Nullable String routing, @Nullable Class<?> clazz,
IndexCoordinates indexCoordinates) {
String[] indexNames = indexCoordinates.getIndexNames(); String[] indexNames = indexCoordinates.getIndexNames();
Assert.notNull(indexNames, "No index defined for Query"); Assert.notNull(indexNames, "No index defined for Query");
@ -968,6 +971,8 @@ class RequestFactory {
sort.ignoreUnmapped(geoDistanceOrder.getIgnoreUnmapped()); sort.ignoreUnmapped(geoDistanceOrder.getIgnoreUnmapped());
} }
sort.order(order.isAscending() ? SortOrder.ASC : SortOrder.DESC);
return sort; return sort;
} else { } else {
FieldSortBuilder sort = SortBuilders // FieldSortBuilder sort = SortBuilders //

View File

@ -225,42 +225,42 @@ abstract public class AbstractReactiveElasticsearchTemplate
return Flux.defer(() -> { return Flux.defer(() -> {
Sinks.Many<T> sink = Sinks.many().unicast().onBackpressureBuffer(); Sinks.Many<T> sink = Sinks.many().unicast().onBackpressureBuffer();
entities // entities.window(bulkSize) //
.bufferTimeout(bulkSize, Duration.ofMillis(200)) // .concatMap(flux -> flux.collectList()) //
.subscribe(new Subscriber<List<T>>() { .subscribe(new Subscriber<List<T>>() {
private Subscription subscription; private Subscription subscription;
private AtomicBoolean upstreamComplete = new AtomicBoolean(false); private AtomicBoolean upstreamComplete = new AtomicBoolean(false);
@Override @Override
public void onSubscribe(Subscription subscription) { public void onSubscribe(Subscription subscription) {
this.subscription = subscription; this.subscription = subscription;
subscription.request(1); subscription.request(1);
} }
@Override @Override
public void onNext(List<T> entityList) { public void onNext(List<T> entityList) {
saveAll(entityList, index) // saveAll(entityList, index) //
.map(sink::tryEmitNext) // .map(sink::tryEmitNext) //
.doOnComplete(() -> { .doOnComplete(() -> {
if (!upstreamComplete.get()) { if (!upstreamComplete.get()) {
subscription.request(1); subscription.request(1);
} else { } else {
sink.tryEmitComplete(); sink.tryEmitComplete();
} }
}).subscribe(); }).subscribe();
} }
@Override @Override
public void onError(Throwable throwable) { public void onError(Throwable throwable) {
subscription.cancel(); subscription.cancel();
sink.tryEmitError(throwable); sink.tryEmitError(throwable);
} }
@Override @Override
public void onComplete() { public void onComplete() {
upstreamComplete.set(true); upstreamComplete.set(true);
} }
}); });
return sink.asFlux(); return sink.asFlux();
}); });
@ -748,6 +748,12 @@ abstract public class AbstractReactiveElasticsearchTemplate
public abstract Mono<String> getClusterVersion(); 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. * Value class to capture client independent information from a response to an index request.
*/ */

View File

@ -117,6 +117,17 @@ public interface ReactiveElasticsearchOperations
ReactiveClusterOperations cluster(); ReactiveClusterOperations cluster();
// region routing // 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 * Returns a copy of this instance with the same configuration, but that uses a different {@link RoutingResolver} to
* obtain routing information. * obtain routing information.

View File

@ -32,9 +32,19 @@ public abstract class AbstractRangePropertyValueConverter<T> extends AbstractPro
protected static final String LTE_FIELD = "lte"; protected static final String LTE_FIELD = "lte";
protected static final String GT_FIELD = "gt"; protected static final String GT_FIELD = "gt";
protected static final String GTE_FIELD = "gte"; protected static final String GTE_FIELD = "gte";
private final Class<?> genericType;
public AbstractRangePropertyValueConverter(PersistentProperty<?> property) { /**
* @param property the property this convertrer belongs to
* @param genericType the generic type of the Range
*/
public AbstractRangePropertyValueConverter(PersistentProperty<?> property, Class<?> genericType) {
super(property); super(property);
this.genericType = genericType;
}
public Class<?> getGenericType() {
return genericType;
} }
@Override @Override
@ -117,10 +127,6 @@ public abstract class AbstractRangePropertyValueConverter<T> extends AbstractPro
protected abstract String format(T value); protected abstract String format(T value);
protected Class<?> getGenericType() {
return getProperty().getTypeInformation().getTypeArguments().get(0).getType();
}
protected abstract T parse(String value); protected abstract T parse(String value);
} }

View File

@ -33,9 +33,9 @@ public class DateRangePropertyValueConverter extends AbstractRangePropertyValueC
private final List<ElasticsearchDateConverter> dateConverters; private final List<ElasticsearchDateConverter> dateConverters;
public DateRangePropertyValueConverter(PersistentProperty<?> property, public DateRangePropertyValueConverter(PersistentProperty<?> property,
List<ElasticsearchDateConverter> dateConverters) { Class<?> genericType, List<ElasticsearchDateConverter> dateConverters) {
super(property); super(property, genericType);
this.dateConverters = dateConverters; this.dateConverters = dateConverters;
} }

View File

@ -919,7 +919,7 @@ public class MappingElasticsearchConverter
Class<?> elementType = element == null ? null : element.getClass(); Class<?> elementType = element == null ? null : element.getClass();
if (elementType == null || conversions.isSimpleType(elementType)) { if (elementType == null || isSimpleType(elementType)) {
collection.add(getPotentiallyConvertedSimpleWrite(element, collection.add(getPotentiallyConvertedSimpleWrite(element,
componentType != null ? componentType.getType() : Object.class)); componentType != null ? componentType.getType() : Object.class));
} else if (element instanceof Collection || elementType.isArray()) { } else if (element instanceof Collection || elementType.isArray()) {

View File

@ -23,8 +23,12 @@ import org.springframework.data.mapping.PersistentProperty;
*/ */
public class NumberRangePropertyValueConverter extends AbstractRangePropertyValueConverter<Number> { public class NumberRangePropertyValueConverter extends AbstractRangePropertyValueConverter<Number> {
public NumberRangePropertyValueConverter(PersistentProperty<?> property) { /**
super(property); * @param property the property this convertrer belongs to
* @param genericType the generic type of the Range
*/
public NumberRangePropertyValueConverter(PersistentProperty<?> property, Class<?> genericType) {
super(property, genericType);
} }
@Override @Override

View File

@ -34,9 +34,9 @@ public class TemporalRangePropertyValueConverter extends AbstractRangePropertyVa
private final List<ElasticsearchDateConverter> dateConverters; private final List<ElasticsearchDateConverter> dateConverters;
public TemporalRangePropertyValueConverter(PersistentProperty<?> property, public TemporalRangePropertyValueConverter(PersistentProperty<?> property,
List<ElasticsearchDateConverter> dateConverters) { Class<?> genericType, List<ElasticsearchDateConverter> dateConverters) {
super(property); super(property, genericType);
Assert.notEmpty(dateConverters, "dateConverters must not be empty."); Assert.notEmpty(dateConverters, "dateConverters must not be empty.");
this.dateConverters = dateConverters; this.dateConverters = dateConverters;

View File

@ -332,6 +332,8 @@ public final class MappingParameters {
if (!Similarity.Default.equals(similarity)) { if (!Similarity.Default.equals(similarity)) {
objectNode.put(FIELD_PARAM_SIMILARITY, 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) { if (termVector != TermVector.none) {

View File

@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.function.Supplier;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -56,6 +57,7 @@ import org.springframework.data.mapping.model.FieldNamingStrategy;
import org.springframework.data.mapping.model.Property; import org.springframework.data.mapping.model.Property;
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -168,6 +170,18 @@ public class SimpleElasticsearchPersistentProperty extends
return; return;
} }
Supplier<Class<?>> getGenericType = () -> {
TypeInformation<?> typeInformation = getTypeInformation();
if (typeInformation.isCollectionLike()) {
// we have a collection of Range<?>
typeInformation = typeInformation.getComponentType();
}
Class<?> genericType = typeInformation.getTypeArguments().get(0).getType();
return genericType;
};
switch (field.type()) { switch (field.type()) {
case Date: case Date:
case Date_Nanos: { case Date_Nanos: {
@ -197,11 +211,11 @@ public class SimpleElasticsearchPersistentProperty extends
return; return;
} }
Class<?> genericType = getTypeInformation().getTypeArguments().get(0).getType(); var genericType = getGenericType.get();
if (TemporalAccessor.class.isAssignableFrom(genericType)) { if (TemporalAccessor.class.isAssignableFrom(genericType)) {
propertyValueConverter = new TemporalRangePropertyValueConverter(this, dateConverters); propertyValueConverter = new TemporalRangePropertyValueConverter(this, genericType, dateConverters);
} else if (Date.class.isAssignableFrom(genericType)) { } else if (Date.class.isAssignableFrom(genericType)) {
propertyValueConverter = new DateRangePropertyValueConverter(this, dateConverters); propertyValueConverter = new DateRangePropertyValueConverter(this, genericType, dateConverters);
} else { } else {
LOGGER.warn( LOGGER.warn(
String.format("Unsupported generic type '{%s' for date range property '%s'.", genericType, getName())); String.format("Unsupported generic type '{%s' for date range property '%s'.", genericType, getName()));
@ -216,7 +230,7 @@ public class SimpleElasticsearchPersistentProperty extends
return; return;
} }
Class<?> genericType = getTypeInformation().getTypeArguments().get(0).getType(); var genericType = getGenericType.get();
if ((field.type() == FieldType.Integer_Range && !Integer.class.isAssignableFrom(genericType)) if ((field.type() == FieldType.Integer_Range && !Integer.class.isAssignableFrom(genericType))
|| (field.type() == FieldType.Float_Range && !Float.class.isAssignableFrom(genericType)) || (field.type() == FieldType.Float_Range && !Float.class.isAssignableFrom(genericType))
|| (field.type() == FieldType.Long_Range && !Long.class.isAssignableFrom(genericType)) || (field.type() == FieldType.Long_Range && !Long.class.isAssignableFrom(genericType))
@ -226,7 +240,7 @@ public class SimpleElasticsearchPersistentProperty extends
return; return;
} }
propertyValueConverter = new NumberRangePropertyValueConverter(this); propertyValueConverter = new NumberRangePropertyValueConverter(this, genericType);
break; break;
} }
case Ip_Range: { case Ip_Range: {

View File

@ -74,7 +74,7 @@ public class BaseQuery implements Query {
protected List<RescorerQuery> rescorerQueries = new ArrayList<>(); protected List<RescorerQuery> rescorerQueries = new ArrayList<>();
@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 List<RuntimeField> runtimeFields = new ArrayList<>();
@Nullable protected PointInTime pointInTime; @Nullable protected PointInTime pointInTime;
private boolean queryIsUpdatedByConverter = false; private boolean queryIsUpdatedByConverter = false;
@Nullable private Integer reactiveBatchSize = null; @Nullable private Integer reactiveBatchSize = null;
@ -117,6 +117,7 @@ public class BaseQuery implements Query {
this.expandWildcards = builder.getExpandWildcards(); this.expandWildcards = builder.getExpandWildcards();
this.docValueFields = builder.getDocValueFields(); this.docValueFields = builder.getDocValueFields();
this.scriptedFields = builder.getScriptedFields(); this.scriptedFields = builder.getScriptedFields();
this.runtimeFields = builder.getRuntimeFields();
} }
/** /**

View File

@ -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.BaseQuery;
import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery; import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery;
import org.springframework.data.elasticsearch.core.query.Query; 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.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.data.util.StreamUtils; import org.springframework.data.util.StreamUtils;
import org.springframework.data.util.Streamable; 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'."); Assert.notNull(id, "Cannot delete entity with id 'null'.");
doDelete(id, getIndexCoordinates()); doDelete(id, null, getIndexCoordinates());
} }
@Override @Override
@ -231,7 +232,7 @@ public class SimpleElasticsearchRepository<T, ID> implements ElasticsearchReposi
Assert.notNull(entity, "Cannot delete 'null' entity."); Assert.notNull(entity, "Cannot delete 'null' entity.");
doDelete(extractIdFromBean(entity), getIndexCoordinates()); doDelete(extractIdFromBean(entity), operations.getEntityRouting(entity), getIndexCoordinates());
} }
@Override @Override
@ -271,10 +272,14 @@ public class SimpleElasticsearchRepository<T, ID> implements ElasticsearchReposi
deleteAllById(ids); deleteAllById(ids);
} }
private void doDelete(@Nullable ID id, IndexCoordinates indexCoordinates) { private void doDelete(@Nullable ID id, @Nullable String routing, IndexCoordinates indexCoordinates) {
if (id != null) { 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);
});
} }
} }

View File

@ -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.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.BaseQuery; import org.springframework.data.elasticsearch.core.query.BaseQuery;
import org.springframework.data.elasticsearch.core.query.Query; 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.data.elasticsearch.repository.ReactiveElasticsearchRepository;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -196,7 +197,10 @@ public class SimpleReactiveElasticsearchRepository<T, ID> implements ReactiveEla
public Mono<Void> delete(T entity) { public Mono<Void> delete(T entity) {
Assert.notNull(entity, "Entity must not be null!"); 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()); .then(doRefresh());
} }

View File

@ -1,4 +1,4 @@
Spring Data Elasticsearch 5.1 GA (2023.0.0) Spring Data Elasticsearch 5.1.7 (2023.0.7)
Copyright (c) [2013-2022] Pivotal Software, Inc. Copyright (c) [2013-2022] Pivotal Software, Inc.
This product is licensed to you under the Apache License, Version 2.0 (the "License"). This product is licensed to you under the Apache License, Version 2.0 (the "License").
@ -13,3 +13,10 @@ conditions of the subcomponent's license, as noted in the LICENSE file.

View File

@ -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();
}
}

View File

@ -18,6 +18,7 @@ package org.springframework.data.elasticsearch.core;
import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.elasticsearch.client.elc.Queries.*; 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.Aggregate;
import co.elastic.clients.elasticsearch._types.aggregations.Buckets; import co.elastic.clients.elasticsearch._types.aggregations.Buckets;
import co.elastic.clients.elasticsearch._types.aggregations.StringTermsAggregate; 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.List;
import java.util.concurrent.atomic.AtomicInteger; 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.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; 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.Aggregation;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchAggregation; import org.springframework.data.elasticsearch.client.elc.ElasticsearchAggregation;
import org.springframework.data.elasticsearch.client.elc.NativeQuery; import org.springframework.data.elasticsearch.client.elc.NativeQuery;
@ -48,6 +52,51 @@ import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration(classes = ReactiveElasticsearchELCIntegrationTests.Config.class) @ContextConfiguration(classes = ReactiveElasticsearchELCIntegrationTests.Config.class)
public class ReactiveElasticsearchELCIntegrationTests extends ReactiveElasticsearchIntegrationTests { 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 @Configuration
@Import({ ReactiveElasticsearchTemplateConfiguration.class }) @Import({ ReactiveElasticsearchTemplateConfiguration.class })
static class Config { static class Config {

View File

@ -28,6 +28,7 @@ import java.lang.Boolean;
import java.lang.Integer; import java.lang.Integer;
import java.lang.Long; import java.lang.Long;
import java.lang.Object; import java.lang.Object;
import java.time.Duration;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
@ -98,7 +99,7 @@ import org.springframework.util.StringUtils;
@SpringIntegrationTest @SpringIntegrationTest
public abstract class ReactiveElasticsearchIntegrationTests { public abstract class ReactiveElasticsearchIntegrationTests {
@Autowired private ReactiveElasticsearchOperations operations; @Autowired protected ReactiveElasticsearchOperations operations;
@Autowired private IndexNameProvider indexNameProvider; @Autowired private IndexNameProvider indexNameProvider;
// region Setup // region Setup
@ -1181,7 +1182,7 @@ public abstract class ReactiveElasticsearchIntegrationTests {
}).verifyComplete(); }).verifyComplete();
} }
@Test // #2496 @Test // #2496, #2576
@DisplayName("should save data from Flux and return saved data in a flux") @DisplayName("should save data from Flux and return saved data in a flux")
void shouldSaveDataFromFluxAndReturnSavedDataInAFlux() { void shouldSaveDataFromFluxAndReturnSavedDataInAFlux() {
@ -1190,9 +1191,11 @@ public abstract class ReactiveElasticsearchIntegrationTests {
.mapToObj(SampleEntity::of) // .mapToObj(SampleEntity::of) //
.collect(Collectors.toList()); .collect(Collectors.toList());
var entityFlux = Flux.fromIterable(entityList); // we add a random delay to make suure the underlying implementation handles irregular incoming data
var entities = Flux.fromIterable(entityList).concatMap(
entity -> Mono.just(entity).delay(Duration.ofMillis((long) (Math.random() * 10))).thenReturn(entity));
operations.save(entityFlux, SampleEntity.class).collectList() // operations.save(entities, SampleEntity.class).collectList() //
.as(StepVerifier::create) // .as(StepVerifier::create) //
.consumeNextWith(savedEntities -> { .consumeNextWith(savedEntities -> {
assertThat(savedEntities).isEqualTo(entityList); assertThat(savedEntities).isEqualTo(entityList);
@ -1202,7 +1205,7 @@ public abstract class ReactiveElasticsearchIntegrationTests {
// endregion // endregion
// region Helper functions // region Helper functions
private SampleEntity randomEntity(String message) { protected SampleEntity randomEntity(@Nullable String message) {
SampleEntity entity = new SampleEntity(); SampleEntity entity = new SampleEntity();
entity.setId(UUID.randomUUID().toString()); entity.setId(UUID.randomUUID().toString());

View File

@ -31,6 +31,7 @@ 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.FieldType;
import org.springframework.data.elasticsearch.annotations.Mapping; 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.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.Criteria; import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery; import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
@ -95,6 +96,88 @@ public abstract class RuntimeFieldsIntegrationTests {
assertThat(searchHits.getSearchHit(0).getId()).isEqualTo("1"); 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 @Test // #2431
@DisplayName("should return value from runtime field defined in mapping") @DisplayName("should return value from runtime field defined in mapping")
void shouldReturnValueFromRuntimeFieldDefinedInMapping() { void shouldReturnValueFromRuntimeFieldDefinedInMapping() {

View File

@ -909,22 +909,109 @@ public class MappingElasticsearchConverterUnitTests {
assertEquals(expected, document.toJson(), false); 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 @Nested
class RangeTests { class RangeTests {
static final String JSON = "{" static final String JSON = """
+ "\"_class\":\"org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverterUnitTests$RangeTests$RangeEntity\"," {
+ "\"integerRange\":{\"gt\":\"1\",\"lt\":\"10\"}," // "_class": "org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverterUnitTests$RangeTests$RangeEntity",
+ "\"floatRange\":{\"gte\":\"1.2\",\"lte\":\"2.5\"}," // "integerRange": {
+ "\"longRange\":{\"gt\":\"2\",\"lte\":\"5\"}," // "gt": "1",
+ "\"doubleRange\":{\"gte\":\"3.2\",\"lt\":\"7.4\"}," // "lt": "10"
+ "\"dateRange\":{\"gte\":\"1970-01-01T00:00:00.000Z\",\"lte\":\"1970-01-01T01:00:00.000Z\"}," // },
+ "\"localDateRange\":{\"gte\":\"2021-07-06\"}," // "floatRange": {
+ "\"localTimeRange\":{\"gte\":\"00:30:00.000\",\"lt\":\"02:30:00.000\"}," // "gte": "1.2",
+ "\"localDateTimeRange\":{\"gt\":\"2021-01-01T00:30:00.000\",\"lt\":\"2021-01-01T02:30:00.000\"}," // "lte": "2.5"
+ "\"offsetTimeRange\":{\"gte\":\"00:30:00.000+02:00\",\"lt\":\"02:30:00.000+02:00\"}," // },
+ "\"zonedDateTimeRange\":{\"gte\":\"2021-01-01T00:30:00.000+02:00\",\"lte\":\"2021-01-01T00:30:00.000+02:00\"}," // "longRange": {
+ "\"nullRange\":null}"; "gt": "2",
"lte": "5"
},
"doubleRange": {
"gte": "3.2",
"lt": "7.4"
},
"dateRange": {
"gte": "1970-01-01T00:00:00.000Z",
"lte": "1970-01-01T01:00:00.000Z"
},
"localDateRange": {
"gte": "2021-07-06"
},
"localTimeRange": {
"gte": "00:30:00.000",
"lt": "02:30:00.000"
},
"localDateTimeRange": {
"gt": "2021-01-01T00:30:00.000",
"lt": "2021-01-01T02:30:00.000"
},
"offsetTimeRange": {
"gte": "00:30:00.000+02:00",
"lt": "02:30:00.000+02:00"
},
"zonedDateTimeRange": {
"gte": "2021-01-01T00:30:00.000+02:00",
"lte": "2021-01-01T00:30:00.000+02:00"
},
"nullRange": null,
"integerRangeList": [
{
"gte": "2",
"lte": "5"
}
]
}
""";
@Test @Test
public void shouldReadRanges() throws JSONException { public void shouldReadRanges() throws JSONException {
@ -955,6 +1042,7 @@ public class MappingElasticsearchConverterUnitTests {
assertThat(e.getZonedDateTimeRange()).isEqualTo( assertThat(e.getZonedDateTimeRange()).isEqualTo(
Range.just(ZonedDateTime.of(LocalDate.of(2021, 1, 1), LocalTime.of(0, 30), ZoneOffset.ofHours(2)))); Range.just(ZonedDateTime.of(LocalDate.of(2021, 1, 1), LocalTime.of(0, 30), ZoneOffset.ofHours(2))));
assertThat(e.getNullRange()).isNull(); assertThat(e.getNullRange()).isNull();
assertThat(e.getIntegerRangeList()).containsExactly(Range.closed(2, 5));
}); });
} }
@ -978,8 +1066,7 @@ public class MappingElasticsearchConverterUnitTests {
entity.setZonedDateTimeRange( entity.setZonedDateTimeRange(
Range.just(ZonedDateTime.of(LocalDate.of(2021, 1, 1), LocalTime.of(0, 30), ZoneOffset.ofHours(2)))); Range.just(ZonedDateTime.of(LocalDate.of(2021, 1, 1), LocalTime.of(0, 30), ZoneOffset.ofHours(2))));
entity.setNullRange(null); entity.setNullRange(null);
entity.setIntegerRangeList(List.of(Range.closed(2, 5)));
// when
Document document = mappingElasticsearchConverter.mapObject(entity); Document document = mappingElasticsearchConverter.mapObject(entity);
// then // then
@ -1004,6 +1091,8 @@ public class MappingElasticsearchConverterUnitTests {
@Field(type = FieldType.Date_Range) private Range<ZonedDateTime> zonedDateTimeRange; @Field(type = FieldType.Date_Range) private Range<ZonedDateTime> zonedDateTimeRange;
@Field(type = FieldType.Date_Range, storeNullValue = true) private Range<ZonedDateTime> nullRange; @Field(type = FieldType.Date_Range, storeNullValue = true) private Range<ZonedDateTime> nullRange;
@Field(type = FieldType.Integer_Range) private List<Range<Integer>> integerRangeList;
public String getId() { public String getId() {
return id; return id;
} }
@ -1100,6 +1189,13 @@ public class MappingElasticsearchConverterUnitTests {
this.nullRange = nullRange; this.nullRange = nullRange;
} }
public List<Range<Integer>> getIntegerRangeList() {
return integerRangeList;
}
public void setIntegerRangeList(List<Range<Integer>> integerRangeList) {
this.integerRangeList = integerRangeList;
}
} }
} }
@ -1953,12 +2049,12 @@ public class MappingElasticsearchConverterUnitTests {
@Language("JSON") @Language("JSON")
var expected = """ var expected = """
{ {
"_class": "org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverterUnitTests$FieldNameDotsEntity", "_class": "org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverterUnitTests$FieldNameDotsEntity",
"id": "42", "id": "42",
"dotted.field": "dotted field" "dotted.field": "dotted field"
} }
"""; """;
var entity = new FieldNameDotsEntity(); var entity = new FieldNameDotsEntity();
entity.setId("42"); entity.setId("42");
entity.setDottedField("dotted field"); entity.setDottedField("dotted field");
@ -3192,6 +3288,7 @@ public class MappingElasticsearchConverterUnitTests {
this.mapToNotWriteWhenEmpty = mapToNotWriteWhenEmpty; this.mapToNotWriteWhenEmpty = mapToNotWriteWhenEmpty;
} }
} }
static class FieldNameDotsEntity { static class FieldNameDotsEntity {
@Id @Id
@Nullable private String id; @Nullable private String id;

View File

@ -63,13 +63,14 @@ public class PropertyValueConvertersUnitTests {
converters.add(new DatePropertyValueConverter(persistentProperty, converters.add(new DatePropertyValueConverter(persistentProperty,
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date)))); Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
Class<?> genericType = Object.class;
converters.add(new DateRangePropertyValueConverter(persistentProperty, converters.add(new DateRangePropertyValueConverter(persistentProperty,
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date)))); genericType, Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
converters.add(new NumberRangePropertyValueConverter(persistentProperty)); converters.add(new NumberRangePropertyValueConverter(persistentProperty, genericType));
converters.add(new TemporalPropertyValueConverter(persistentProperty, converters.add(new TemporalPropertyValueConverter(persistentProperty,
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date)))); Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
converters.add(new TemporalRangePropertyValueConverter(persistentProperty, converters.add(new TemporalRangePropertyValueConverter(persistentProperty,
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date)))); genericType, Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
return converters.stream().map(propertyValueConverter -> arguments( return converters.stream().map(propertyValueConverter -> arguments(
Named.of(propertyValueConverter.getClass().getSimpleName(), propertyValueConverter))); Named.of(propertyValueConverter.getClass().getSimpleName(), propertyValueConverter)));

View File

@ -287,6 +287,12 @@ public abstract class MappingBuilderIntegrationTests extends MappingContextBaseT
indexOps.createWithMapping(); indexOps.createWithMapping();
} }
@Test // #2659
@DisplayName("should write correct mapping for dense vector property")
void shouldWriteCorrectMappingForDenseVectorProperty() {
operations.indexOps(SimilarityEntity.class).createWithMapping();
}
// region Entities // region Entities
@Document(indexName = "#{@indexNameProvider.indexName()}") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class Book { static class Book {
@ -916,5 +922,14 @@ public abstract class MappingBuilderIntegrationTests extends MappingContextBaseT
@Nullable @Nullable
@Field(name = "dotted.field", type = Text) private String dottedField; @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 // endregion
} }

View File

@ -62,7 +62,7 @@ public abstract class SearchAfterIntegrationTests {
@Test @Test
@Order(java.lang.Integer.MAX_VALUE) @Order(java.lang.Integer.MAX_VALUE)
void cleanup() { void cleanup() {
operations.indexOps(IndexCoordinates.of(indexNameProvider.getPrefix() + "*")).delete(); operations.indexOps(IndexCoordinates.of(indexNameProvider.getPrefix() + '*')).delete();
} }
@Test // #1143 @Test // #1143
@ -85,11 +85,11 @@ public abstract class SearchAfterIntegrationTests {
query.setSearchAfter(searchAfter); query.setSearchAfter(searchAfter);
SearchHits<Entity> searchHits = operations.search(query, Entity.class); SearchHits<Entity> searchHits = operations.search(query, Entity.class);
if (searchHits.getSearchHits().size() == 0) { if (searchHits.getSearchHits().isEmpty()) {
break; break;
} }
foundEntities.addAll(searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList())); foundEntities.addAll(searchHits.stream().map(SearchHit::getContent).toList());
searchAfter = searchHits.getSearchHit((int) (searchHits.getSearchHits().size() - 1)).getSortValues(); searchAfter = searchHits.getSearchHit(searchHits.getSearchHits().size() - 1).getSortValues();
if (++loop > 10) { if (++loop > 10) {
fail("loop not terminating"); fail("loop not terminating");
@ -99,16 +99,69 @@ public abstract class SearchAfterIntegrationTests {
assertThat(foundEntities).containsExactlyElementsOf(entities); 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()}") @Document(indexName = "#{@indexNameProvider.indexName()}")
private static class Entity { private static class Entity {
@Nullable @Nullable
@Id private Long id; @Id private Long id;
@Nullable @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.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 @Nullable
@ -121,30 +174,44 @@ public abstract class SearchAfterIntegrationTests {
} }
@Nullable @Nullable
public String getMessage() { public String getKeyword() {
return message; return keyword;
} }
public void setMessage(@Nullable String message) { public void setKeyword(@Nullable String keyword) {
this.message = message; this.keyword = keyword;
}
@Nullable
public Long getValue() {
return value;
}
public void setValue(@Nullable Long value) {
this.value = value;
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) if (this == o)
return true; return true;
if (!(o instanceof Entity entity)) if (o == null || getClass() != o.getClass())
return false; return false;
Entity entity = (Entity) o;
if (!Objects.equals(id, entity.id)) if (!Objects.equals(id, entity.id))
return false; return false;
return Objects.equals(message, entity.message); if (!Objects.equals(keyword, entity.keyword))
return false;
return Objects.equals(value, entity.value);
} }
@Override @Override
public int hashCode() { public int hashCode() {
int result = id != null ? id.hashCode() : 0; 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; return result;
} }
} }

View File

@ -1590,6 +1590,41 @@ public abstract class CustomMethodRepositoryIntegrationTests implements NewElast
assertThat(searchHits.getSearchHit(2).getId()).isEqualTo("oslo"); assertThat(searchHits.getSearchHit(2).getId()).isEqualTo("oslo");
} }
@Test // #2601
void shouldUseGeoSortReverseParameter() {
GeoPoint munich = new GeoPoint(48.137154, 11.5761247);
GeoPoint berlin = new GeoPoint(52.520008, 13.404954);
GeoPoint vienna = new GeoPoint(48.20849, 16.37208);
GeoPoint oslo = new GeoPoint(59.9127, 10.7461);
List<SampleEntity> entities = new ArrayList<>();
SampleEntity entity1 = new SampleEntity();
entity1.setId("berlin");
entity1.setLocation(berlin);
entities.add(entity1);
SampleEntity entity2 = new SampleEntity();
entity2.setId("vienna");
entity2.setLocation(vienna);
entities.add(entity2);
SampleEntity entity3 = new SampleEntity();
entity3.setId("oslo");
entity3.setLocation(oslo);
entities.add(entity3);
repository.saveAll(entities);
SearchHits<SampleEntity> searchHits = repository
.searchBy(Sort.by(new GeoDistanceOrder("location", munich).with(Sort.Direction.DESC)));
assertThat(searchHits.getTotalHits()).isEqualTo(3);
assertThat(searchHits.getSearchHit(0).getId()).isEqualTo("oslo");
assertThat(searchHits.getSearchHit(1).getId()).isEqualTo("berlin");
assertThat(searchHits.getSearchHit(2).getId()).isEqualTo("vienna");
}
@Test // DATAES-749 @Test // DATAES-749
void shouldReturnSearchPage() { void shouldReturnSearchPage() {
List<SampleEntity> entities = createSampleEntities("abc", 20); List<SampleEntity> entities = createSampleEntities("abc", 20);

View File

@ -15,7 +15,7 @@
# #
# #
sde.testcontainers.image-name=docker.elastic.co/elasticsearch/elasticsearch sde.testcontainers.image-name=docker.elastic.co/elasticsearch/elasticsearch
sde.testcontainers.image-version=8.7.0 sde.testcontainers.image-version=8.7.1
# #
# #
# needed as we do a DELETE /* at the end of the tests, will be required from 8.0 on, produces a warning since 7.13 # needed as we do a DELETE /* at the end of the tests, will be required from 8.0 on, produces a warning since 7.13