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

Compare commits

..

25 Commits

Author SHA1 Message Date
Mark Paluch 40a91d01a8 Release version 5.0.2 (2022.0.2).
See #2427
2023-02-17 10:59:28 +01:00
Mark Paluch aab18b55ab Prepare 5.0.2 (2022.0.2).
See #2427
2023-02-17 10:59:14 +01:00
Peter-Josef Meisch 6351b9f026 Upgrade to Elasticsearch 7.17.9.
Original Pull Request #2456
Closes #2454
2023-02-14 18:57:49 +01:00
Peter-Josef Meisch 7d5b9d5b7c @Query annotated repository method does not use Sort parameter.
Original Pull Request #2450
Closes #2449

(cherry picked from commit 4f30a492b9)
2023-02-10 22:49:20 +01:00
Urs Keller 5cf7b2baae Fix ReactiveIndicesTemplate: Refresh not called on bound indices.
Original Pull Request #2444
Closes #2441

(cherry picked from commit 0971acfe25)
2023-02-03 19:58:55 +01:00
Mark Paluch b005c77cad Update CI properties.
See #2427
2023-01-30 10:49:32 +01:00
Mark Paluch d90d0ed71c Upgrade to Maven Wrapper 3.8.7.
See #2439
2023-01-30 10:47:25 +01:00
Peter-Josef Meisch 5b3cf9af4c Fix reading response runtime field by mapping.
Original Pull Request #2432
Closes #2431

(cherry picked from commit d9bf76fb31)
2023-01-22 20:28:48 +01:00
Mark Paluch 85a7ed7dc8 After release cleanups.
See #2366
2023-01-13 11:43:31 +01:00
Mark Paluch a64c24e64b Prepare next development iteration.
See #2366
2023-01-13 11:43:30 +01:00
Mark Paluch bb071a18e7 Release version 5.0.1 (2022.0.1).
See #2366
2023-01-13 11:40:51 +01:00
Mark Paluch 5c1682b908 Prepare 5.0.1 (2022.0.1).
See #2366
2023-01-13 11:40:40 +01:00
Peter-Josef Meisch 9583a05553 AOT/Native support.
Original Pull Request #2423
Closes #2419

(cherry picked from commit 44a5c7545f)
2023-01-08 21:37:39 +01:00
Peter-Josef Meisch 6551a80ccc findAllById returns all requested documents.
Original Pull Request #2421
Closes #2417

(cherry picked from commit 28489ffee8)
2023-01-04 17:30:05 +01:00
Mark Paluch 1c3c09a80e Extend license header copyright years to 2023.
See #2414
2023-01-02 09:50:16 +01:00
Peter-Josef Meisch ec66dfebdd Upgrade Elasticsearch to 8.5.3 (old client to 7.17.8).
Original Pull Request #2412
Closes #2402
2022-12-30 23:45:57 +01:00
Scooby be0327894a IndexQuery's id get ignored in bulkIndexOperation.
Original Pull Request #2407
Closdes #2405

(cherry picked from commit 4d7d0955f9)
2022-12-27 20:02:08 +01:00
Peter-Josef Meisch 4bf1435555 Fix NPE in ElasticsearchExceptionTranslator.
Original Pull Request #2389
Closes #2388

(cherry picked from commit 9446d726bc)
2022-12-05 14:44:50 +01:00
Peter-Josef Meisch 8fe04172f6 Support Kotlin Flow as possible return type in repository functions.
Original Pull Request #2387
Closes #2386

(cherry picked from commit 1fa6c9f3e5)
2022-12-03 22:53:13 +01:00
Peter-Josef Meisch 03b522d956 Upgrade to Elasticsearch 8.5.2.
Original Pull Request #2381
Closes #2379
2022-11-26 08:23:42 +01:00
Peter-Josef Meisch bf317bc6a7 Upgrade to Elasticsearch 8.5.1.
Original Pull Request #2371
Closes #2369
2022-11-19 13:26:32 +01:00
Mark Paluch ea3aa135e4 Update CI properties.
See #2366
2022-11-18 15:31:28 +01:00
Mark Paluch 5c848e4641 Enable upstream build triggers.
See #2336
2022-11-18 15:15:34 +01:00
Mark Paluch 1b7c16ab03 After release cleanups.
See #2336
2022-11-18 14:30:31 +01:00
Mark Paluch 0bcb86a03d Prepare next development iteration.
See #2336
2022-11-18 14:30:30 +01:00
710 changed files with 1893 additions and 9475 deletions
+2 -1
View File
@@ -9,7 +9,8 @@ Make sure that:
-->
- [ ] You have read the [Spring Data contribution guidelines](https://github.com/spring-projects/spring-data-build/blob/master/CONTRIBUTING.adoc).
- [ ] **There is a ticket in the bug tracker for the project in our [issue tracker](https://github.com/spring-projects/spring-data-elasticsearch/issues)**. Add the issue number to the _Closes #issue-number_ line below
- [ ] **There is a ticket in the bug tracker for the project in our [issue tracker](https://github.
com/spring-projects/spring-data-elasticsearch/issues)**. Add the issue number to the _Closes #issue-number_ line below
- [ ] You use the code formatters provided [here](https://github.com/spring-projects/spring-data-build/tree/master/etc/ide) and have them applied to your changes. Dont submit any formatting related changes.
- [ ] You submit test cases (unit or integration tests) that back your changes.
- [ ] You added yourself as author in the headers of the classes you touched. Amend the date range in the Apache license header if needed. For new types, add the license header (copy from another file and set the current year only).
-2
View File
@@ -24,5 +24,3 @@ target
/zap.env
/localdocker.env
.localdocker-env
+2 -2
View File
@@ -1,3 +1,3 @@
#Thu Dec 14 08:37:40 CET 2023
#Mon Jan 30 10:47:25 CET 2023
wrapperUrl=https\://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip
-3
View File
@@ -1,9 +1,6 @@
= Spring Data contribution guidelines
You find the contribution guidelines for Spring Data projects https://github.com/spring-projects/spring-data-build/blob/main/CONTRIBUTING.adoc[here].
**Please read these carefully!**
Do not submit a Pull Request before having created an issue and having discussed it. This prevents you from doing work that might be rejected.
== Running the test locally
Vendored
+27 -45
View File
@@ -1,7 +1,7 @@
def p = [:]
node {
checkout scm
p = readProperties interpolate: true, file: 'ci/pipeline.properties'
checkout scm
p = readProperties interpolate: true, file: 'ci/pipeline.properties'
}
pipeline {
@@ -9,7 +9,7 @@ pipeline {
triggers {
pollSCM 'H/10 * * * *'
upstream(upstreamProjects: "spring-data-commons/3.1.x", threshold: hudson.model.Result.SUCCESS)
upstream(upstreamProjects: "spring-data-commons/3.0.x", threshold: hudson.model.Result.SUCCESS)
}
options {
@@ -18,7 +18,7 @@ pipeline {
}
stages {
stage("test: baseline (main)") {
stage("test: baseline (Java 17)") {
when {
beforeAgent(true)
anyOf {
@@ -32,42 +32,17 @@ pipeline {
options { timeout(time: 30, unit: 'MINUTES') }
environment {
DOCKER_HUB = credentials("${p['docker.credentials']}")
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
}
steps {
script {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.docker']) {
sh "PROFILE=none JENKINS_USER_NAME=${p['jenkins.user.name']} ci/verify.sh"
sh "JENKINS_USER_NAME=${p['jenkins.user.name']} ci/clean.sh"
}
}
}
}
stage("Test other configurations") {
when {
beforeAgent(true)
allOf {
branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP")
not { triggeredBy 'UpstreamCause' }
}
}
parallel {
stage("test: baseline (next)") {
agent {
label 'data'
}
options { timeout(time: 30, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
}
steps {
script {
docker.image(p['docker.java.next.image']).inside(p['docker.java.inside.docker']) {
sh "PROFILE=none JENKINS_USER_NAME=${p['jenkins.user.name']} ci/verify.sh"
sh "JENKINS_USER_NAME=${p['jenkins.user.name']} ci/clean.sh"
}
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.docker']) {
sh "docker login --username ${DOCKER_HUB_USR} --password ${DOCKER_HUB_PSW}"
sh 'PROFILE=none ci/verify.sh'
sh "ci/clean.sh"
}
}
}
@@ -86,21 +61,24 @@ pipeline {
label 'data'
}
options { timeout(time: 20, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
}
steps {
script {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.basic']) {
sh 'MAVEN_OPTS="-Duser.name=' + "${p['jenkins.user.name']}" + ' -Duser.home=/tmp/jenkins-home" ' +
"./mvnw -s settings.xml -Pci,artifactory -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch-non-root " +
"-Dartifactory.server=${p['artifactory.url']} " +
"-Dartifactory.username=${ARTIFACTORY_USR} " +
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
"-Dartifactory.staging-repository=${p['artifactory.repository.snapshot']} " +
"-Dartifactory.build-name=spring-data-elasticsearch " +
"-Dartifactory.build-number=spring-data-elasticsearch-${BRANCH_NAME}-build-${BUILD_NUMBER} " +
"-Dmaven.test.skip=true clean deploy -U -B"
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.basic']) {
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml -Pci,artifactory -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch-non-root ' +
'-Dartifactory.server=https://repo.spring.io ' +
"-Dartifactory.username=${ARTIFACTORY_USR} " +
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
"-Dartifactory.staging-repository=libs-snapshot-local " +
"-Dartifactory.build-name=spring-data-elasticsearch " +
"-Dartifactory.build-number=${BUILD_NUMBER} " +
'-Dmaven.test.skip=true clean deploy -U -B'
}
}
}
}
@@ -110,6 +88,10 @@ pipeline {
post {
changed {
script {
slackSend(
color: (currentBuild.currentResult == 'SUCCESS') ? 'good' : 'danger',
channel: '#spring-data-dev',
message: "${currentBuild.fullDisplayName} - `${currentBuild.currentResult}`\n${env.BUILD_URL}")
emailext(
subject: "[${currentBuild.fullDisplayName}] ${currentBuild.currentResult}",
mimeType: 'text/html',
+4 -4
View File
@@ -137,9 +137,9 @@ To use the Release candidate versions of the upcoming major version, use our Mav
</dependency>
<repository>
<id>spring-snapshot</id>
<id>spring-libs-snapshot</id>
<name>Spring Snapshot Repository</name>
<url>https://repo.spring.io/milestone</url>
<url>https://repo.spring.io/libs-milestone</url>
</repository>
----
@@ -154,9 +154,9 @@ If you'd rather like the latest snapshots of the upcoming major version, use our
</dependency>
<repository>
<id>spring-snapshot</id>
<id>spring-libs-snapshot</id>
<name>Spring Snapshot Repository</name>
<url>https://repo.spring.io/snapshot</url>
<url>https://repo.spring.io/libs-snapshot</url>
</repository>
----
+1 -3
View File
@@ -2,7 +2,5 @@
set -euo pipefail
export JENKINS_USER=${JENKINS_USER_NAME}
MAVEN_OPTS="-Duser.name=${JENKINS_USER} -Duser.home=/tmp/jenkins-home" \
MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" \
./mvnw -s settings.xml clean -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch
+6 -11
View File
@@ -1,21 +1,19 @@
# Java versions
java.main.tag=17.0.9_9-jdk-focal
java.next.tag=20-jdk-jammy
java.main.tag=17.0.6_10-jdk-focal
# Docker container images - standard
docker.java.main.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.main.tag}
docker.java.next.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.next.tag}
# Supported versions of MongoDB
docker.mongodb.4.4.version=4.4.25
docker.mongodb.5.0.version=5.0.21
docker.mongodb.6.0.version=6.0.10
docker.mongodb.4.4.version=4.4.18
docker.mongodb.5.0.version=5.0.14
docker.mongodb.6.0.version=6.0.4
# Supported versions of Redis
docker.redis.6.version=6.2.13
docker.redis.6.version=6.2.10
# Supported versions of Cassandra
docker.cassandra.3.version=3.11.16
docker.cassandra.3.version=3.11.14
# Docker environment settings
docker.java.inside.basic=-v $HOME:/tmp/jenkins-home
@@ -25,6 +23,3 @@ docker.java.inside.docker=-u root -v /var/run/docker.sock:/var/run/docker.sock -
docker.registry=
docker.credentials=hub.docker.com-springbuildmaster
artifactory.credentials=02bd1690-b54f-4c9f-819d-a77cb7a9822c
artifactory.url=https://repo.spring.io
artifactory.repository.snapshot=libs-snapshot-local
jenkins.user.name=spring-builds+jenkins
+2 -4
View File
@@ -5,8 +5,6 @@ set -euo pipefail
mkdir -p /tmp/jenkins-home/.m2/spring-data-elasticsearch
chown -R 1001:1001 .
export JENKINS_USER=${JENKINS_USER_NAME}
MAVEN_OPTS="-Duser.name=${JENKINS_USER} -Duser.home=/tmp/jenkins-home" \
MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" \
./mvnw -s settings.xml \
-P${PROFILE} clean dependency:list verify -Dsort -U -B -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch
-P${PROFILE} clean dependency:list verify -Dsort -U -B -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch
+85 -15
View File
@@ -5,12 +5,12 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>5.1.9</version>
<version>5.0.2</version>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>3.1.9</version>
<version>3.0.2</version>
</parent>
<name>Spring Data Elasticsearch</name>
@@ -18,22 +18,21 @@
<url>https://github.com/spring-projects/spring-data-elasticsearch</url>
<properties>
<springdata.commons>3.1.9</springdata.commons>
<springdata.commons>3.0.2</springdata.commons>
<!-- version of the RestHighLevelClient -->
<elasticsearch-rhlc>7.17.15</elasticsearch-rhlc>
<elasticsearch-rhlc>7.17.9</elasticsearch-rhlc>
<!-- version of the new ElasticsearchClient -->
<elasticsearch-java>8.7.1</elasticsearch-java>
<elasticsearch-java>8.5.3</elasticsearch-java>
<log4j>2.18.0</log4j>
<!-- netty dependency can be removed once the WebClient code is gone -->
<netty>4.1.90.Final</netty>
<netty>4.1.65.Final</netty>
<blockhound-junit>1.0.8.RELEASE</blockhound-junit>
<hoverfly>0.14.4</hoverfly>
<blockhound-junit>1.0.6.RELEASE</blockhound-junit>
<hoverfly>0.14.3</hoverfly>
<jsonassert>1.5.1</jsonassert>
<testcontainers>1.18.0</testcontainers>
<wiremock>2.35.0</wiremock>
<testcontainers>1.17.3</testcontainers>
<wiremock>2.33.2</wiremock>
<java-module-name>spring.data.elasticsearch</java-module-name>
@@ -44,6 +43,7 @@
-->
<mvn.unit-test.goal>test</mvn.unit-test.goal>
<mvn.integration-test-elasticsearch.goal>integration-test</mvn.integration-test-elasticsearch.goal>
<mvn.integration-test-opensearch.goal>none</mvn.integration-test-opensearch.goal>
</properties>
<developers>
@@ -197,7 +197,7 @@
<dependency>
<groupId>javax.interceptor</groupId>
<artifactId>javax.interceptor-api</artifactId>
<version>1.2.2</version>
<version>1.2.1</version>
<scope>test</scope>
</dependency>
@@ -279,6 +279,24 @@
<scope>test</scope>
</dependency>
<!--
we don't use lombok in Spring Data Elasticsearch anymore. But the dependency is set in the parent project, and so the
lombok compiler stuff is executed regardless of the fact that we don't need it.
On AdoptOpenJdk 16.0.0 this leads to an error, so the project does not build.
Therefore we replace lombok with a jar - that just contains an empty file - that lives in a local maven repository in
src/test/resources/local-maven-repo/
It was installed with
mvn deploy:deploy-file -DgroupId=org.projectlombok -DartifactId=lombok -Dversion=999999 -Durl=file:./src/test/resources/local-maven-repo/ -DrepositoryId=local-maven-repo -DupdateReleaseInfo=true -Dfile=path/to/empty.jar
-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<!--suppress MavenPackageUpdate -->
<version>999999</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
@@ -401,8 +419,45 @@
</systemPropertyVariables>
</configuration>
</execution>
<!-- execution to run the integration tests against Opensearch -->
<execution>
<id>integration-test-opensearch</id>
<phase>${mvn.integration-test-opensearch.goal}</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<groups>integration-test</groups>
<systemPropertyVariables>
<sde.integration-test.environment>opensearch</sde.integration-test.environment>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<version>1.7.5</version>
<dependencies>
<dependency>
<groupId>org.pitest</groupId>
<artifactId>pitest-junit5-plugin</artifactId>
<version>0.12</version>
</dependency>
</dependencies>
<configuration>
<jvmArgs>
<jvmArg>-XX:+AllowRedefinitionToAddDeleteMethods</jvmArg>
</jvmArgs>
<excludedGroups>integration-test</excludedGroups>
<targetClasses>
<param>org.springframework.data.elasticsearch.core.geo.*</param>
</targetClasses>
<excludedMethods>toString</excludedMethods>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
@@ -411,7 +466,7 @@
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
</plugin>
</plugins>
</plugins>
</build>
<profiles>
@@ -464,8 +519,23 @@
</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>
+1 -1
View File
@@ -5,7 +5,7 @@ BioMed Central Development Team; Oliver Drotbohm; Greg Turnquist; Christoph Stro
ifdef::backend-epub3[:front-cover-image: image:epub-cover.png[Front Cover,1050,1600]]
:spring-data-commons-docs: ../../../../spring-data-commons/src/main/asciidoc
(C) 2013-2024 The original author(s).
(C) 2013-2022 The original author(s).
NOTE: Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.
+12 -13
View File
@@ -17,9 +17,9 @@ include::reference/elasticsearch-new.adoc[leveloffset=+1]
* Version Control - https://github.com/spring-projects/spring-data-elasticsearch
* API Documentation - https://docs.spring.io/spring-data/elasticsearch/docs/current/api/
* Bugtracker - https://github.com/spring-projects/spring-data-elasticsearch/issues
* Release repository - https://repo1.maven.org/maven2/
* Milestone repository - https://repo.spring.io/milestone/
* Snapshot repository - https://repo.spring.io/snapshot/
* Release repository - https://repo.spring.io/libs-release
* Milestone repository - https://repo.spring.io/libs-milestone
* Snapshot repository - https://repo.spring.io/libs-snapshot
[[preface.requirements]]
== Requirements
@@ -37,17 +37,16 @@ built and tested.
[cols="^,^,^,^,^",options="header"]
|===
| Spring Data Release Train | Spring Data Elasticsearch | Elasticsearch | Spring Framework | Spring Boot
| 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
| 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.0 (Pascal) | 4.2.xfootnote:oom[] | 7.12.0 | 5.3.x | 2.5.x
| 2020.0 (Ockham) | 4.1.xfootnote:oom[] | 7.9.3 | 5.3.2 | 2.4.x
| Neumann | 4.0.xfootnote:oom[] | 7.6.2 | 5.2.12 |2.3.x
| Moore | 3.2.xfootnote:oom[] |6.8.12 | 5.2.12| 2.2.x
| Lovelace | 3.1.xfootnote:oom[] | 6.2.2 | 5.1.19 |2.1.x
| Kay | 3.0.xfootnote:oom[] | 5.5.0 | 5.0.13 | 2.0.x
| Ingalls | 2.1.xfootnote:oom[] | 2.4.0 | 4.3.25 | 1.5.x
| 2021.2 (Raj) | 4.4.x | 7.17.3 | 5.3.x | 2.7.x
| 2021.1 (Q) | 4.3.x | 7.15.2 | 5.3.x | 2.6.x
| 2021.0 (Pascal) | 4.2.xfootnote:oom[Out of maintenance] | 7.12.0 | 5.3.x | 2.5.x
| 2020.0 (Ockham)footnote:oom[] | 4.1.xfootnote:oom[] | 7.9.3 | 5.3.2 | 2.4.x
| Neumannfootnote:oom[] | 4.0.xfootnote:oom[] | 7.6.2 | 5.2.12 |2.3.x
| Moorefootnote:oom[] | 3.2.xfootnote:oom[] |6.8.12 | 5.2.12| 2.2.x
| Lovelacefootnote:oom[] | 3.1.xfootnote:oom[] | 6.2.2 | 5.1.19 |2.1.x
| Kayfootnote:oom[] | 3.0.xfootnote:oom[] | 5.5.0 | 5.0.13 | 2.0.x
| Ingallsfootnote:oom[] | 2.1.xfootnote:oom[] | 2.4.0 | 4.3.25 | 1.5.x
|===
Support for upcoming versions of Elasticsearch is being tracked and general compatibility should be given assuming
@@ -240,7 +240,7 @@ ClientConfiguration clientConfiguration = ClientConfiguration.builder()
<.> Define default headers, if they need to be customized
<.> Use the builder to provide cluster addresses, set default `HttpHeaders` or enable SSL.
<.> Optionally enable SSL. There exist overloads of this function that can take a `SSLContext` or as an alternative the fingerprint of the certificate as it is output by Elasticsearch 8 on startup.
<.> Optionally enable SSL.
<.> Optionally set a proxy.
<.> Optionally set a path prefix, mostly used when different clusters a behind some reverse proxy.
<.> Set the connection timeout.
@@ -224,11 +224,11 @@ The following code shows as an example how to retrieve all entries that have a _
SearchHits<Statement> hasVotes() {
Query query = NativeQuery.builder()
.withQuery(co.elastic.clients.elasticsearch._types.query_dsl.Query.of(qb -> qb
.withQuery(co.elastic.clients.elasticsearch._types.query_dsl.Query.of(qb -> qb //
.hasChild(hc -> hc
.queryName("vote")
.query(matchAllQueryAsQuery())
.scoreMode(ChildScoreMode.None)
.queryName("vote") //
.query(matchAllQueryAsQuery()) //
.scoreMode(ChildScoreMode.None)//
)))
.build();
@@ -154,7 +154,7 @@ The old deprecated `RestHighLevelClient` can still be used, but you will need to
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.17.5</version>
<version>7.17.9</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
@@ -165,4 +165,4 @@ The old deprecated `RestHighLevelClient` can still be used, but you will need to
----
====
Make sure to specify the version 7.17.6 explicitly, otherwise maven will resolve to 8.5.0, and this does not exist.
Make sure to specify the version 7.17.9 explicitly, otherwise maven will resolve to 8.5.3, and this does not exist.
@@ -1,26 +0,0 @@
[[elasticsearch-migration-guide-5.0-5.1]]
= Upgrading from 5.0.x to 5.1.x
This section describes breaking changes from version 5.0.x to 5.1.x and how removed features can be replaced by new introduced features.
[[elasticsearch-migration-guide-5.0-5.1.breaking-changes]]
== Breaking Changes
In the `org.springframework.data.elasticsearch.core.index.AliasData` class, which is used for alias information returned from Elasticsearch, the property `filter` (of type `Document`) is replaced by `filterQuery` which is of type
`org.springframework.data.elasticsearch.core.query.Query`.
`org.springframework.data.elasticsearch.annotations.Similarity` was an enum class until 5.1. This enum was used in the `@Field` annotation to specify a similarity value.
But besides the values defined by the enum, it is possible to have similarities with custom names in Elasticsearch.
Therefore, the annotation property was changed from the type of the enum to a simple `String`.
The previous enum values like `Similarity.Default` do still exist as String constants, so existing code will compile unmodified.
Adaptions are necessary when this enum was used at other places than as a property of the `@Field` annotation.
[[elasticsearch-migration-guide-5.0-5.1.deprecations]]
== Deprecations
=== template functions
The functions in the `IndexOperations` and `ReactiverIndexOperations` to manage index templates that were introduced in Spring Data Elasticsearch 4.1
have been deprecated. They were using the old Elasticsearch API that was deprecated in Elasticsearch version 7.8.
Please use the new functions that are based on the compsable index template API instead.
@@ -17,6 +17,7 @@ The following arguments are available:
* `refreshIntervall`, defaults to _"1s"_
* `indexStoreType`, defaults to _"fs"_
It is as well possible to define https://www.elastic.co/guide/en/elasticsearch/reference/7.11/index-modules-index-sorting.html[index sorting] (check the linked Elasticsearch documentation for the possible field types and values):
====
@@ -132,7 +133,9 @@ stream.close();
----
====
There are no methods in the `SearchOperations` API to access the scroll id, if it should be necessary to access this, the following methods of the `AbstractElasticsearchTemplate` can be used (this is the base implementation for the different `ElasticsearchOperations` implementations):
There are no methods in the `SearchOperations` API to access the scroll id, if it should be necessary to access this,
the following methods of the `AbstractElasticsearchTemplate` can be used (this is the base implementation for the
different `ElasticsearchOperations` implementations:
====
[source,java]
@@ -278,8 +281,9 @@ This works with every implementation of the `Query` interface.
[[elasticsearch.misc.point-in-time]]
== Point In Time (PIT) API
`ElasticsearchOperations` supports the point in time API of Elasticsearch (see https://www.elastic.co/guide/en/elasticsearch/reference/8.3/point-in-time-api.html).
The following code snippet shows how to use this feature with a fictional `Person` class:
`ElasticsearchOperations` supports the point in time API of Elasticsearch (see https://www.elastic
.co/guide/en/elasticsearch/reference/8.3/point-in-time-api.html). The following code snippet shows how to use this
feature with a fictional `Person` class:
====
[source,java]
@@ -307,115 +311,8 @@ SearchHits<Person> searchHits2 = operations.search(query2, Person.class);
operations.closePointInTime(searchHits2.getPointInTimeId()); <.>
----
<.> create a point in time for an index (can be multiple names) and a keep-alive duration and retrieve its id
<.> pass that id into the query to search together with the next keep-alive value
<.> for the next query, use the id returned from the previous search
<.> when done, close the point in time using the last returned id
====
[[elasticsearch.misc.searchtemplates]]
== Search Template support
Use of the search template API is supported.
To use this, it first is necessary to create a stored script.
The `ElasticsearchOperations` interface extends `ScriptOperations` which provides the necessary functions.
The example used here assumes that we have `Person` entity with a property named `firstName`.
A search template script can be saved like this:
====
[source,java]
----
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.script.Script;
operations.putScript( <.>
Script.builder()
.withId("person-firstname") <.>
.withLanguage("mustache") <.>
.withSource(""" <.>
{
"query": {
"bool": {
"must": [
{
"match": {
"firstName": "{{firstName}}" <.>
}
}
]
}
},
"from": "{{from}}", <.>
"size": "{{size}}" <.>
}
""")
.build()
);
----
<.> Use the `putScript()` method to store a search template script
<.> The name / id of the script
<.> Scripts that are used in search templates must be in the _mustache_ language.
<.> The script source
<.> The search parameter in the script
<.> Paging request offset
<.> Paging request size
====
To use a search template in a search query, Spring Data Elasticsearch provides the `SearchTemplateQuery`, an implementation of the `org.springframework.data.elasticsearch.core.query.Query` interface.
In the following code, we will add a call using a search template query to a custom repository implementation (see
<<repositories.custom-implementations>>) as
an example how this can be integrated into a repository call.
We first define the custom repository fragment interface:
====
[source,java]
----
interface PersonCustomRepository {
SearchPage<Person> findByFirstNameWithSearchTemplate(String firstName, Pageable pageable);
}
----
====
The implementation of this repository fragment looks like this:
====
[source,java]
----
public class PersonCustomRepositoryImpl implements PersonCustomRepository {
private final ElasticsearchOperations operations;
public PersonCustomRepositoryImpl(ElasticsearchOperations operations) {
this.operations = operations;
}
@Override
public SearchPage<Person> findByFirstNameWithSearchTemplate(String firstName, Pageable pageable) {
var query = SearchTemplateQuery.builder() <.>
.withId("person-firstname") <.>
.withParams(
Map.of( <.>
"firstName", firstName,
"from", pageable.getOffset(),
"size", pageable.getPageSize()
)
)
.build();
SearchHits<Person> searchHits = operations.search(query, Person.class); <.>
return SearchHitSupport.searchPageFor(searchHits, pageable);
}
}
----
<.> Create a `SearchTemplateQuery`
<.> Provide the id of the search template
<.> The parameters are passed in a `Map<String,Object>`
<.> Do the search in the same way as with the other query types.
====
@@ -1,11 +1,10 @@
[[new-features]]
= What's new
[[new-features.5-1-0]]
== New in Spring Data Elasticsearch 5.1
[[new-features.5-0-1]]
== New in Spring Data Elasticsearch 5.0.1
* Upgrade to Elasticsearch 8.7.0
* Allow specification of the TLS certificate when connecting to an Elasticsearch 8 cluster
* Upgrade to Elasticsearch 8.5.3
[[new-features.5-0-0]]
== New in Spring Data Elasticsearch 5.0
@@ -1,9 +1,9 @@
[[elasticsearch.mapping]]
= Elasticsearch Object Mapping
Spring Data Elasticsearch Object Mapping is the process that maps a Java object - the domain entity - into the JSON representation that is stored in Elasticsearch and back.
The class that is internally used for this mapping is the
`MappingElasticsearchConverter`.
Spring Data Elasticsearch Object Mapping is the process that maps a Java object - the domain entity - into the JSON
representation that is stored in Elasticsearch and back. The class that is internally used for this mapping is the
`MappingElasticsearcvhConverter`.
[[elasticsearch.mapping.meta-model]]
== Meta Model Object Mapping
@@ -52,15 +52,21 @@ The mapping metadata infrastructure is defined in a separate spring-data-commons
[[elasticsearch.mapping.meta-model.annotations.read-write]]
==== Controlling which properties are written to and read from Elasticsearch
This section details the annotations that define if the value of a property is written to or read from Elasticsearch.
This section details the annotations that define if the value of a property is written to or
read from Elasticsearch.
`@Transient`: A property annotated with this annotation will not be written to the mapping, it's value will not be sent to Elasticsearch and when documents are returned from Elasticsearch, this property will not be set in the resulting entity.
`@Transient`: A property annotated with this annotation will not be written to the mapping, it's value will not be
sent to Elasticsearch and when documents are returned from Elasticsearch, this property will not be set in the
resulting entity.
`@ReadOnlyProperty`: A property with this annotaiton will not have its value written to Elasticsearch, but when returning data, the proeprty will be filled with the value returned in the document from Elasticsearch.
One use case for this are runtime fields defined in the index mapping.
`@ReadOnlyProperty`: A property with this annotaiton will not have its value written to Elasticsearch, but when
returning data, the proeprty will be filled with the value returned in the document from Elasticsearch. One use case
for this are runtime fields defined in the index mapping.
`@WriteOnlyProperty`: A property with this annotaiton will have its value stored in Elasticsearch but will not be set
with any value when reading document. This can be used for example for synthesized fields which should go into the
Elasticsearch index but are not used elsewhere.
`@WriteOnlyProperty`: A property with this annotaiton will have its value stored in Elasticsearch but will not be set with any value when reading document.
This can be used for example for synthesized fields which should go into the Elasticsearch index but are not used elsewhere.
[[elasticsearch.mapping.meta-model.annotations.date-formats]]
==== Date format mapping
@@ -104,7 +110,8 @@ The following table shows the different attributes and the mapping created from
NOTE: If you are using a custom date format, you need to use _uuuu_ for the year instead of _yyyy_.
This is due to a https://www.elastic.co/guide/en/elasticsearch/reference/current/migrate-to-java-time.html#java-time-migration-incompatible-date-formats[change in Elasticsearch 7].
Check the code of the `org.springframework.data.elasticsearch.annotations.DateFormat` enum for a complete list of predefined values and their patterns.
Check the code of the `org.springframework.data.elasticsearch.annotations.DateFormat` enum for a complete list of
predefined values and their patterns.
[[elasticsearch.mapping.meta-model.annotations.range]]
==== Range types
@@ -165,13 +172,12 @@ A `FieldNamingStrategy` applies to all entities; it can be overwritten by settin
[[elasticsearch.mapping.meta-model.annotations.non-field-backed-properties]]
==== Non-field-backed properties
Normally the properties used in an entity are fields of the entity class.
There might be cases, when a property value is calculated in the entity and should be stored in Elasticsearch.
In this case, the getter method (`getProperty()`) can be annotated with the `@Field` annotation, in addition to that the method must be annotated with `@AccessType(AccessType.Type
.PROPERTY)`.
The third annotation that is needed in such a case is `@WriteOnlyProperty`, as such a value is only written to Elasticsearch.
A full example:
Normally the properties used in an entity are fields of the entity class. There might be cases, when a property value
is calculated in the entity and should be stored in Elasticsearch. In this case, the getter method (`getProperty()`) can be
annotated
with the `@Field` annotation, in addition to that the method must be annotated with `@AccessType(AccessType.Type
.PROPERTY)`. The third annotation that is needed in such a case is `@WriteOnlyProperty`, as such a value is only
written to Elasticsearch. A full example:
====
[source,java]
----
@@ -184,19 +190,6 @@ public String getProperty() {
----
====
[[elasticsearch.mapping.meta-model.annotations.misc]]
==== Other property annotations
===== @IndexedIndexName
This annotation can be set on a String property of an entity.
This property will not be written to the mapping, it will not be stored in Elasticsearch and its value will not be read from an Elasticsearch document.
After an entity is persisted, for example with a call to `ElasticsearchOperations.save(T entity)`, the entity
returned from that call will contain the name of the index that an entity was saved to in that property.
This is useful when the index name is dynamically set by a bean, or when writing to a write alias.
Putting some value into such a property does not set the index into which an entity is stored!
[[elasticsearch.mapping.meta-model.rules]]
=== Mapping Rules
@@ -419,15 +412,12 @@ Looking at the `Configuration` from the <<elasticsearch.mapping.meta-model, prev
[source,java]
----
@Configuration
public class Config extends ElasticsearchConfiguration {
public class Config extends AbstractElasticsearchConfiguration {
@NonNull
@Override
public ClientConfiguration clientConfiguration() {
return ClientConfiguration.builder() //
.connectedTo("localhost:9200") //
.build();
}
@Override
public RestHighLevelClient elasticsearchClient() {
return RestClients.create(ClientConfiguration.create("localhost:9200")).rest();
}
@Bean
@Override
@@ -438,7 +428,7 @@ public class Config extends ElasticsearchConfiguration {
@WritingConverter <2>
static class AddressToMap implements Converter<Address, Map<String, Object>> {
@Override
public Map<String, Object> convert(Address source) {
@@ -35,7 +35,6 @@ There is support for automatic creation of indices and writing the mappings when
The example shows how to use an injected `ElasticsearchOperations` instance in a Spring REST controller.
The example assumes that `Person` is a class that is annotated with `@Document`, `@Id` etc (see <<elasticsearch.mapping.meta-model.annotations>>).
.ElasticsearchOperations usage
====
[source,java]
@@ -66,8 +65,8 @@ public class TestController {
----
<.> Let Spring inject the provided `ElasticsearchOperations` bean in the constructor.
<.> Store some entity in the Elasticsearch cluster.
The id is read from the returned entity, as it might have been null in the `person` object and been created by Elasticsearch.
<.> Store some entity in the Elasticsearch cluster. The id is read from the returned entity, as it might have been
null in the `person` object and been created by Elasticsearch.
<.> Retrieve the entity with a get by id.
====
@@ -147,7 +146,7 @@ Conditions for the same field can be chained, they will be combined with a logic
====
[source,java]
----
Criteria criteria = new Criteria("price").greaterThan(42.0).lessThan(34.0);
Criteria criteria = new Criteria("price").greaterThan(42.0).lessThan(34.0L);
Query query = new CriteriaQuery(criteria);
----
====
@@ -234,9 +233,3 @@ Query query = NativeQuery.builder()
SearchHits<Person> searchHits = operations.search(query, Person.class);
----
====
[[elasticsearch.operations.searchtemplateScOp§query]]
=== SearchTemplateQuery
This is a special implementation of the `Query` interface to be used in combination with a stored search template.
See <<elasticsearch.misc.searchtemplates>> for further information.
@@ -15,6 +15,4 @@ include::elasticsearch-migration-guide-4.3-4.4.adoc[]
include::elasticsearch-migration-guide-4.4-5.0.adoc[]
include::elasticsearch-migration-guide-5.0-5.1.adoc[]
:leveloffset: -1
@@ -37,7 +37,7 @@ public class Person {
[source,java]
----
ReactiveElasticsearchOperations operations;
ReactiveELasticsearchOperations operations; <.>
// ...
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2024 the original author or authors.
* Copyright 2020-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2024 the original author or authors.
* Copyright 2022-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2024 the original author or authors.
* Copyright 2019-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,29 +0,0 @@
/*
* Copyright 2022-2024 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;
import org.springframework.dao.NonTransientDataAccessResourceException;
/**
* @author Peter-Josef Meisch
* @since 5.1
*/
public class ResourceNotFoundException extends NonTransientDataAccessResourceException {
public ResourceNotFoundException(String msg) {
super(msg);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2024 the original author or authors.
* Copyright 2020-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2024 the original author or authors.
* Copyright 2019-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2024 the original author or authors.
* Copyright 2013-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2024 the original author or authors.
* Copyright 2014-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2024 the original author or authors.
* Copyright 2013-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.
@@ -77,22 +77,6 @@ public @interface Document {
*/
Dynamic dynamic() default Dynamic.INHERIT;
/**
* Specifies if the id property should also be stored in the Elasticsearch document source. Default value is
* {@literal true}
*
* @since 5.1
*/
boolean storeIdInSource() default true;
/**
* Specifies if the version property should also be stored in the Elasticsearch document source. Default value is
* true.
*
* @since 5.1
*/
boolean storeVersionInSource() default true;
/**
* @since 4.3
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2024 the original author or authors.
* Copyright 2013-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.
@@ -140,7 +140,7 @@ public @interface Field {
/**
* @since 4.0
*/
String similarity() default Similarity.Default;
Similarity similarity() default Similarity.Default;
/**
* @since 4.0
@@ -210,12 +210,4 @@ public @interface Field {
* @since 4.3
*/
boolean excludeFromSource() default false;
/**
* when this field is a {{@link String}}, a {{@link java.util.Collection}} or a {{@link java.util.Map}} that is empty
* this property controlls whether the empty value is sent to Elasticsearch.
*
* @since 5.1
*/
boolean storeEmptyValue() default true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2024 the original author or authors.
* Copyright 2013-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2024 the original author or authors.
* Copyright 2013-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2024 the original author or authors.
* Copyright 2017-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2024 the original author or authors.
* Copyright 2020-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2024 the original author or authors.
* Copyright 2020-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2024 the original author or authors.
* Copyright 2020-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2024 the original author or authors.
* Copyright 2019-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2024 the original author or authors.
* Copyright 2019-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.
@@ -1,42 +0,0 @@
/*
* Copyright 2023-2024 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.annotations;
import org.springframework.data.annotation.ReadOnlyProperty;
import org.springframework.data.annotation.Transient;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to mark a String property of an entity to be filled with the name of the index where the entity was
* stored after it is indexed into Elasticsearch. This can be used when the name of the index is dynamically created
* or when a document was indexed into a write alias.
*
* This can not be used to specify the index where an entity should be written to.
*
* @author Peter-Josef Meisch
* @since 5.1
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Documented
@Field(type = FieldType.Auto) // prevents the property being written to the index mapping
public @interface IndexedIndexName {
}
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2024 the original author or authors.
* Copyright 2014-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.
@@ -109,7 +109,7 @@ public @interface InnerField {
/**
* @since 4.0
*/
String similarity() default Similarity.Default;
Similarity similarity() default Similarity.Default;
/**
* @since 4.0
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2024 the original author or authors.
* Copyright 2020-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2024 the original author or authors.
* Copyright 2020-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2024 the original author or authors.
* Copyright 2014-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2024 the original author or authors.
* Copyright 2014-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2024 the original author or authors.
* Copyright 2020-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2024 the original author or authors.
* Copyright 2013-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2024 the original author or authors.
* Copyright 2014-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2024 the original author or authors.
* Copyright 2019-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.
@@ -19,9 +19,18 @@ package org.springframework.data.elasticsearch.annotations;
* @author Peter-Josef Meisch
* @since 4.0
*/
public final class Similarity {
public final static String Default = "default";
public final static String BM25 = "BM25";
public final static String classic = "classic";
public final static String Boolean = "boolean";
public enum Similarity {
Default("default"), BM25("BM25"), classic("classic"), Boolean("boolean");
// need to use a custom name because 'boolean' can't be used as enum name
private final String toStringName;
Similarity(String name) {
this.toStringName = name;
}
@Override
public String toString() {
return toStringName;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2024 the original author or authors.
* Copyright 2022-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2024 the original author or authors.
* Copyright 2019-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2024 the original author or authors.
* Copyright 2022-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 the original author or authors.
* 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.
@@ -21,7 +21,7 @@ import org.springframework.data.util.ReactiveWrappers;
/**
* @author Peter-Josef Meisch
* @since 5.1
* @since 5.0.1
*/
public class ElasticsearchAotPredicates {
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 the original author or authors.
* 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.
@@ -39,7 +39,7 @@ import org.springframework.lang.Nullable;
/**
* @author Peter-Josef Meisch
* @since 5.1
* @since 5.0.1
*/
public class ElasticsearchRuntimeHints implements RuntimeHintsRegistrar {
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2024 the original author or authors.
* Copyright 2018-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.
@@ -20,6 +20,7 @@ import java.net.SocketAddress;
import java.time.Duration;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.net.ssl.HostnameVerifier;
@@ -27,6 +28,7 @@ import javax.net.ssl.SSLContext;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.web.reactive.function.client.WebClient;
/**
* Configuration interface exposing common client configuration properties for Elasticsearch clients.
@@ -120,12 +122,6 @@ public interface ClientConfiguration {
*/
Optional<SSLContext> getSslContext();
/**
* @return the optional SHA-256 fingerprint of the self-signed http_ca.crt certificate output by Elasticsearch at
* startup time.
*/
Optional<String> getCaFingerprint();
/**
* Returns the {@link HostnameVerifier} to use. Can be {@link Optional#empty()} if not configured.
*
@@ -167,6 +163,11 @@ public interface ClientConfiguration {
*/
Optional<String> getProxy();
/**
* @return the function for configuring a WebClient.
*/
Function<WebClient, WebClient> getWebClientConfigurer();
/**
* @return the client configuration callbacks
* @since 4.3
@@ -254,15 +255,6 @@ public interface ClientConfiguration {
* @return the {@link TerminalClientConfigurationBuilder}.
*/
TerminalClientConfigurationBuilder usingSsl(SSLContext sslContext, HostnameVerifier hostnameVerifier);
/**
* Connect via https using a SSLContext that is build from the given certificate fingerprint.
*
* @param caFingerprint the SHA-256 fingerprint of the self-signed http_ca.crt certificate output by Elasticsearch
* at startup time.
* @return the {@link TerminalClientConfigurationBuilder}.
*/
TerminalClientConfigurationBuilder usingSsl(String caFingerprint);
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2024 the original author or authors.
* Copyright 2018-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.
@@ -20,6 +20,7 @@ import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.net.ssl.HostnameVerifier;
@@ -32,6 +33,7 @@ import org.springframework.data.elasticsearch.client.ClientConfiguration.Termina
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.reactive.function.client.WebClient;
/**
* Default builder implementation for {@link ClientConfiguration}.
@@ -49,15 +51,15 @@ class ClientConfigurationBuilder
private final List<InetSocketAddress> hosts = new ArrayList<>();
private HttpHeaders headers = new HttpHeaders();
private boolean useSsl;
@Nullable private SSLContext sslContext;
@Nullable private String caFingerprint;
@Nullable private HostnameVerifier hostnameVerifier;
private @Nullable SSLContext sslContext;
private @Nullable HostnameVerifier hostnameVerifier;
private Duration connectTimeout = Duration.ofSeconds(10);
private Duration soTimeout = Duration.ofSeconds(5);
@Nullable private String username;
@Nullable private String password;
@Nullable private String pathPrefix;
@Nullable private String proxy;
private @Nullable String username;
private @Nullable String password;
private @Nullable String pathPrefix;
private @Nullable String proxy;
private final Function<WebClient, WebClient> webClientConfigurer = Function.identity();
private Supplier<HttpHeaders> headersSupplier = HttpHeaders::new;
@Deprecated private final HttpClientConfigCallback httpClientConfigurer = httpClientBuilder -> httpClientBuilder;
private final List<ClientConfiguration.ClientConfigurationCallback<?>> clientConfigurers = new ArrayList<>();
@@ -137,20 +139,10 @@ class ClientConfigurationBuilder
return this;
}
@Override
public TerminalClientConfigurationBuilder usingSsl(String caFingerprint) {
Assert.notNull(caFingerprint, "caFingerprint must not be null");
this.useSsl = true;
this.caFingerprint = caFingerprint;
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.elasticsearch.client.ClientConfiguration.TerminalClientConfigurationBuilder#withDefaultHeaders(org.springframework.http.HttpHeaders)
*/
* (non-Javadoc)
* @see org.springframework.data.elasticsearch.client.ClientConfiguration.TerminalClientConfigurationBuilder#withDefaultHeaders(org.springframework.http.HttpHeaders)
*/
@Override
public TerminalClientConfigurationBuilder withDefaultHeaders(HttpHeaders defaultHeaders) {
@@ -237,12 +229,8 @@ class ClientConfigurationBuilder
headers.setBasicAuth(username, password);
}
if (sslContext != null && caFingerprint != null) {
throw new IllegalArgumentException("Either SSLContext or caFingerprint must be set, but not both");
}
return new DefaultClientConfiguration(hosts, headers, useSsl, sslContext, caFingerprint, soTimeout, connectTimeout,
pathPrefix, hostnameVerifier, proxy, httpClientConfigurer, clientConfigurers, headersSupplier);
return new DefaultClientConfiguration(hosts, headers, useSsl, sslContext, soTimeout, connectTimeout, pathPrefix,
hostnameVerifier, proxy, webClientConfigurer, httpClientConfigurer, clientConfigurers, headersSupplier);
}
private static InetSocketAddress parse(String hostAndPort) {
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2024 the original author or authors.
* Copyright 2018-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2024 the original author or authors.
* Copyright 2018-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.
@@ -19,6 +19,7 @@ import java.net.InetSocketAddress;
import java.time.Duration;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.net.ssl.HostnameVerifier;
@@ -27,6 +28,7 @@ import javax.net.ssl.SSLContext;
import org.elasticsearch.client.RestClientBuilder.HttpClientConfigCallback;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.web.reactive.function.client.WebClient;
/**
* Default {@link ClientConfiguration} implementation.
@@ -42,33 +44,33 @@ class DefaultClientConfiguration implements ClientConfiguration {
private final List<InetSocketAddress> hosts;
private final HttpHeaders headers;
private final boolean useSsl;
@Nullable private final SSLContext sslContext;
@Nullable private final String caFingerprint;
private final @Nullable SSLContext sslContext;
private final Duration soTimeout;
private final Duration connectTimeout;
@Nullable private final String pathPrefix;
@Nullable private final HostnameVerifier hostnameVerifier;
@Nullable private final String proxy;
private final @Nullable String pathPrefix;
private final @Nullable HostnameVerifier hostnameVerifier;
private final @Nullable String proxy;
private final Function<WebClient, WebClient> webClientConfigurer;
private final HttpClientConfigCallback httpClientConfigurer;
private final Supplier<HttpHeaders> headersSupplier;
private final List<ClientConfigurationCallback<?>> clientConfigurers;
DefaultClientConfiguration(List<InetSocketAddress> hosts, HttpHeaders headers, boolean useSsl,
@Nullable SSLContext sslContext, @Nullable String caFingerprint, Duration soTimeout, Duration connectTimeout,
@Nullable String pathPrefix, @Nullable HostnameVerifier hostnameVerifier, @Nullable String proxy,
HttpClientConfigCallback httpClientConfigurer, List<ClientConfigurationCallback<?>> clientConfigurers,
Supplier<HttpHeaders> headersSupplier) {
@Nullable SSLContext sslContext, Duration soTimeout, Duration connectTimeout, @Nullable String pathPrefix,
@Nullable HostnameVerifier hostnameVerifier, @Nullable String proxy,
Function<WebClient, WebClient> webClientConfigurer, HttpClientConfigCallback httpClientConfigurer,
List<ClientConfigurationCallback<?>> clientConfigurers, Supplier<HttpHeaders> headersSupplier) {
this.hosts = List.copyOf(hosts);
this.headers = headers;
this.useSsl = useSsl;
this.sslContext = sslContext;
this.caFingerprint = caFingerprint;
this.soTimeout = soTimeout;
this.connectTimeout = connectTimeout;
this.pathPrefix = pathPrefix;
this.hostnameVerifier = hostnameVerifier;
this.proxy = proxy;
this.webClientConfigurer = webClientConfigurer;
this.httpClientConfigurer = httpClientConfigurer;
this.clientConfigurers = clientConfigurers;
this.headersSupplier = headersSupplier;
@@ -94,11 +96,6 @@ class DefaultClientConfiguration implements ClientConfiguration {
return Optional.ofNullable(this.sslContext);
}
@Override
public Optional<String> getCaFingerprint() {
return Optional.ofNullable(this.caFingerprint);
}
@Override
public Optional<HostnameVerifier> getHostNameVerifier() {
return Optional.ofNullable(this.hostnameVerifier);
@@ -125,6 +122,11 @@ class DefaultClientConfiguration implements ClientConfiguration {
return Optional.ofNullable(proxy);
}
@Override
public Function<WebClient, WebClient> getWebClientConfigurer() {
return webClientConfigurer;
}
@Override
public <T> List<ClientConfigurationCallback<?>> getClientConfigurers() {
return clientConfigurers;
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2024 the original author or authors.
* Copyright 2018-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2024 the original author or authors.
* Copyright 2018-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2024 the original author or authors.
* Copyright 2018-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2024 the original author or authors.
* Copyright 2022-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2024 the original author or authors.
* Copyright 2022-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2024 the original author or authors.
* Copyright 2022-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -15,7 +15,7 @@
*/
package org.springframework.data.elasticsearch.client.elc;
import static org.springframework.data.elasticsearch.client.elc.Queries.*;
import static org.springframework.data.elasticsearch.client.elc.QueryBuilders.*;
import static org.springframework.util.StringUtils.*;
import co.elastic.clients.elasticsearch._types.FieldValue;
@@ -39,7 +39,6 @@ import org.springframework.util.Assert;
* query.
*
* @author Peter-Josef Meisch
* @author Ezequiel Antúnez Camacho
* @since 4.4
*/
class CriteriaQueryProcessor {
@@ -330,13 +329,6 @@ class CriteriaQueryProcessor {
throw new CriteriaQueryException("value for " + fieldName + " is not an Iterable");
}
break;
case REGEXP:
queryBuilder //
.regexp(rb -> rb //
.field(fieldName) //
.value(value.toString()) //
.boost(boost)); //
break;
default:
throw new CriteriaQueryException("Could not build query for " + entry);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -138,7 +138,7 @@ final class DocumentAdapters {
document.setPrimaryTerm(hit.primaryTerm() != null && hit.primaryTerm() > 0 ? hit.primaryTerm() : 0);
float score = hit.score() != null ? hit.score().floatValue() : Float.NaN;
return new SearchDocumentAdapter(document, score, hit.sort().stream().map(TypeUtils::toObject).toArray(),
return new SearchDocumentAdapter(document, score, hit.sort().stream().map(TypeUtils::toString).toArray(),
documentFields, highlightFields, innerHits, nestedMetaData, explanation, matchedQueries, hit.routing());
}
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2024 the original author or authors.
* Copyright 2022-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2024 the original author or authors.
* Copyright 2022-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2024 the original author or authors.
* Copyright 2022-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -19,7 +19,6 @@ import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.TransportOptions;
import co.elastic.clients.transport.TransportUtils;
import co.elastic.clients.transport.Version;
import co.elastic.clients.transport.rest_client.RestClientOptions;
import co.elastic.clients.transport.rest_client.RestClientTransport;
@@ -35,10 +34,13 @@ import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.apache.http.*;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
@@ -195,10 +197,6 @@ public final class ElasticsearchClients {
}
builder.setHttpClientConfigCallback(clientBuilder -> {
if (clientConfiguration.getCaFingerprint().isPresent()) {
clientBuilder
.setSSLContext(TransportUtils.sslContextFromCaFingerprint(clientConfiguration.getCaFingerprint().get()));
}
clientConfiguration.getSslContext().ifPresent(clientBuilder::setSSLContext);
clientConfiguration.getHostNameVerifier().ifPresent(clientBuilder::setSSLHostnameVerifier);
clientBuilder.addInterceptorLast(new CustomHeaderInjector(clientConfiguration.getHeadersSupplier()));
@@ -272,14 +270,7 @@ public final class ElasticsearchClients {
TransportOptions transportOptionsWithHeader = transportOptionsBuilder
.addHeader(X_SPRING_DATA_ELASTICSEARCH_CLIENT, clientType).build();
// we need to create our own objectMapper that keeps null values in order to provide the storeNullValue
// functionality. The one Elasticsearch would provide removes the nulls. We remove unwanted nulls before they get
// into this mapper, so we can safely keep them here.
var objectMapper = (new ObjectMapper())
.configure(SerializationFeature.INDENT_OUTPUT, false)
.setSerializationInclusion(JsonInclude.Include.ALWAYS);
return new RestClientTransport(restClient, new JacksonJsonpMapper(objectMapper), transportOptionsWithHeader);
return new RestClientTransport(restClient, new JacksonJsonpMapper(), transportOptionsWithHeader);
}
private static List<String> formattedHosts(List<InetSocketAddress> hosts, boolean useSsl) {
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -30,7 +30,6 @@ import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.elasticsearch.NoSuchIndexException;
import org.springframework.data.elasticsearch.ResourceNotFoundException;
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
/**
@@ -78,20 +77,16 @@ public class ElasticsearchExceptionTranslator implements PersistenceExceptionTra
var errorType = response.error().type();
var errorReason = response.error().reason() != null ? response.error().reason() : "undefined reason";
if (response.status() == 404) {
if (response.status() == 404 && "index_not_found_exception".equals(errorType)) {
if ("index_not_found_exception".equals(errorType)) {
// noinspection RegExpRedundantEscape
Pattern pattern = Pattern.compile(".*no such index \\[(.*)\\]");
String index = "";
Matcher matcher = pattern.matcher(errorReason);
if (matcher.matches()) {
index = matcher.group(1);
}
return new NoSuchIndexException(index);
// noinspection RegExpRedundantEscape
Pattern pattern = Pattern.compile(".*no such index \\[(.*)\\]");
String index = "";
Matcher matcher = pattern.matcher(errorReason);
if (matcher.matches()) {
index = matcher.group(1);
}
return new ResourceNotFoundException(errorReason);
return new NoSuchIndexException(index);
}
String body = JsonUtils.toJson(response, jsonpMapper);
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -55,12 +55,10 @@ import org.springframework.data.elasticsearch.core.query.ByQueryResponse;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.query.SearchTemplateQuery;
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
import org.springframework.data.elasticsearch.core.query.UpdateResponse;
import org.springframework.data.elasticsearch.core.reindex.ReindexRequest;
import org.springframework.data.elasticsearch.core.reindex.ReindexResponse;
import org.springframework.data.elasticsearch.core.script.Script;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -69,7 +67,6 @@ import org.springframework.util.Assert;
* Elasticsearch client.
*
* @author Peter-Josef Meisch
* @author Hamid Rahimi
* @since 4.4
*/
public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
@@ -115,20 +112,16 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
// region child templates
@Override
public IndexOperations indexOps(Class<?> clazz) {
return new IndicesTemplate(client.indices(), getClusterTemplate(), elasticsearchConverter, clazz);
return new IndicesTemplate(client.indices(), elasticsearchConverter, clazz);
}
@Override
public IndexOperations indexOps(IndexCoordinates index) {
return new IndicesTemplate(client.indices(), getClusterTemplate(), elasticsearchConverter, index);
return new IndicesTemplate(client.indices(), elasticsearchConverter, index);
}
@Override
public ClusterOperations cluster() {
return getClusterTemplate();
}
private ClusterTemplate getClusterTemplate() {
return new ClusterTemplate(client.cluster(), elasticsearchConverter);
}
// endregion
@@ -178,8 +171,8 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
Assert.notNull(query, "query must not be null");
DeleteByQueryRequest request = requestConverter.documentDeleteByQueryRequest(query, routingResolver.getRouting(),
clazz, index, getRefreshPolicy());
DeleteByQueryRequest request = requestConverter.documentDeleteByQueryRequest(query, clazz, index,
getRefreshPolicy());
DeleteByQueryResponse response = execute(client -> client.deleteByQuery(request));
@@ -222,8 +215,8 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
Object queryObject = query.getObject();
if (queryObject != null) {
query.setObject(updateIndexedObject(queryObject, new IndexedObjectInformation(indexResponse.id(),
indexResponse.index(), indexResponse.seqNo(), indexResponse.primaryTerm(), indexResponse.version())));
query.setObject(updateIndexedObject(queryObject, IndexedObjectInformation.of(indexResponse.id(),
indexResponse.seqNo(), indexResponse.primaryTerm(), indexResponse.version())));
}
return indexResponse.id();
@@ -313,8 +306,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
Assert.notNull(query, "query must not be null");
Assert.notNull(index, "index must not be null");
SearchRequest searchRequest = requestConverter.searchRequest(query, routingResolver.getRouting(), clazz, index,
true);
SearchRequest searchRequest = requestConverter.searchRequest(query, clazz, index, true, false);
SearchResponse<EntityAsMap> searchResponse = execute(client -> client.search(searchRequest, EntityAsMap.class));
@@ -325,22 +317,11 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
public <T> SearchHits<T> search(Query query, Class<T> clazz, IndexCoordinates index) {
Assert.notNull(query, "query must not be null");
Assert.notNull(clazz, "clazz must not be null");
Assert.notNull(index, "index must not be null");
if (query instanceof SearchTemplateQuery searchTemplateQuery) {
return doSearch(searchTemplateQuery, clazz, index);
} else {
return doSearch(query, clazz, index);
}
}
protected <T> SearchHits<T> doSearch(Query query, Class<T> clazz, IndexCoordinates index) {
SearchRequest searchRequest = requestConverter.searchRequest(query, routingResolver.getRouting(), clazz, index,
false);
SearchRequest searchRequest = requestConverter.searchRequest(query, clazz, index, false, false);
SearchResponse<EntityAsMap> searchResponse = execute(client -> client.search(searchRequest, EntityAsMap.class));
// noinspection DuplicatedCode
ReadDocumentCallback<T> readDocumentCallback = new ReadDocumentCallback<>(elasticsearchConverter, clazz, index);
SearchDocumentResponse.EntityCreator<T> entityCreator = getEntityCreator(readDocumentCallback);
SearchDocumentResponseCallback<SearchHits<T>> callback = new ReadSearchDocumentResponseCallback<>(clazz, index);
@@ -348,18 +329,6 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
return callback.doWith(SearchDocumentResponseBuilder.from(searchResponse, entityCreator, jsonpMapper));
}
protected <T> SearchHits<T> doSearch(SearchTemplateQuery query, Class<T> clazz, IndexCoordinates index) {
var searchTemplateRequest = requestConverter.searchTemplate(query, routingResolver.getRouting(), index);
var searchTemplateResponse = execute(client -> client.searchTemplate(searchTemplateRequest, EntityAsMap.class));
// noinspection DuplicatedCode
ReadDocumentCallback<T> readDocumentCallback = new ReadDocumentCallback<>(elasticsearchConverter, clazz, index);
SearchDocumentResponse.EntityCreator<T> entityCreator = getEntityCreator(readDocumentCallback);
SearchDocumentResponseCallback<SearchHits<T>> callback = new ReadSearchDocumentResponseCallback<>(clazz, index);
return callback.doWith(SearchDocumentResponseBuilder.from(searchTemplateResponse, entityCreator, jsonpMapper));
}
@Override
protected <T> SearchHits<T> doSearch(MoreLikeThisQuery query, Class<T> clazz, IndexCoordinates index) {
@@ -380,8 +349,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
Assert.notNull(query, "query must not be null");
Assert.notNull(query.getPageable(), "pageable of query must not be null.");
SearchRequest request = requestConverter.searchRequest(query, routingResolver.getRouting(), clazz, index, false,
scrollTimeInMillis);
SearchRequest request = requestConverter.searchRequest(query, clazz, index, false, scrollTimeInMillis);
SearchResponse<EntityAsMap> response = execute(client -> client.search(request, EntityAsMap.class));
return getSearchScrollHits(clazz, index, response);
@@ -473,34 +441,10 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
return doMultiSearch(multiSearchQueryParameters);
}
@Override
public List<SearchHits<?>> multiSearch(List<? extends Query> queries, List<Class<?>> classes,
List<IndexCoordinates> indexes) {
Assert.notNull(queries, "queries must not be null");
Assert.notNull(classes, "classes must not be null");
Assert.notNull(indexes, "indexes must not be null");
Assert.isTrue(queries.size() == classes.size() && queries.size() == indexes.size(),
"queries, classes and indexes must have the same size");
List<MultiSearchQueryParameter> multiSearchQueryParameters = new ArrayList<>(queries.size());
Iterator<Class<?>> it = classes.iterator();
Iterator<IndexCoordinates> indexesIt = indexes.iterator();
for (Query query : queries) {
Class<?> clazz = it.next();
IndexCoordinates index = indexesIt.next();
multiSearchQueryParameters.add(new MultiSearchQueryParameter(query, clazz, index));
}
return doMultiSearch(multiSearchQueryParameters);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private List<SearchHits<?>> doMultiSearch(List<MultiSearchQueryParameter> multiSearchQueryParameters) {
MsearchRequest request = requestConverter.searchMsearchRequest(multiSearchQueryParameters,
routingResolver.getRouting());
MsearchRequest request = requestConverter.searchMsearchRequest(multiSearchQueryParameters);
MsearchResponse<EntityAsMap> msearchResponse = execute(client -> client.msearch(request, EntityAsMap.class));
List<MultiSearchResponseItem<EntityAsMap>> responseItems = msearchResponse.responses();
@@ -569,35 +513,6 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
// endregion
// region script methods
@Override
public boolean putScript(Script script) {
Assert.notNull(script, "script must not be null");
var request = requestConverter.scriptPut(script);
return execute(client -> client.putScript(request)).acknowledged();
}
@Nullable
@Override
public Script getScript(String name) {
Assert.notNull(name, "name must not be null");
var request = requestConverter.scriptGet(name);
return responseConverter.scriptResponse(execute(client -> client.getScript(request)));
}
public boolean deleteScript(String name) {
Assert.notNull(name, "name must not be null");
DeleteScriptRequest request = requestConverter.scriptDelete(name);
return execute(client -> client.deleteScript(request)).acknowledged();
}
// endregion
// region client callback
/**
* Callback interface to be used with {@link #execute(ElasticsearchTemplate.ClientCallback)} for operating directly on
@@ -660,8 +575,8 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
failedDocuments);
}
return bulkResponse.items().stream().map(
item -> new IndexedObjectInformation(item.id(), item.index(), item.seqNo(), item.primaryTerm(), item.version()))
return bulkResponse.items().stream()
.map(item -> IndexedObjectInformation.of(item.id(), item.seqNo(), item.primaryTerm(), item.version()))
.collect(Collectors.toList());
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2024 the original author or authors.
* Copyright 2022-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -37,15 +37,15 @@ import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.ResourceUtil;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.index.*;
import org.springframework.data.elasticsearch.core.index.DeleteIndexTemplateRequest;
import org.springframework.data.elasticsearch.core.index.AliasActions;
import org.springframework.data.elasticsearch.core.index.AliasData;
import org.springframework.data.elasticsearch.core.index.DeleteTemplateRequest;
import org.springframework.data.elasticsearch.core.index.ExistsIndexTemplateRequest;
import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest;
import org.springframework.data.elasticsearch.core.index.GetIndexTemplateRequest;
import org.springframework.data.elasticsearch.core.index.GetTemplateRequest;
import org.springframework.data.elasticsearch.core.index.PutIndexTemplateRequest;
import org.springframework.data.elasticsearch.core.index.MappingBuilder;
import org.springframework.data.elasticsearch.core.index.PutTemplateRequest;
import org.springframework.data.elasticsearch.core.index.Settings;
import org.springframework.data.elasticsearch.core.index.TemplateData;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.lang.Nullable;
@@ -62,37 +62,30 @@ public class IndicesTemplate extends ChildTemplate<ElasticsearchTransport, Elast
private static final Logger LOGGER = LoggerFactory.getLogger(IndicesTemplate.class);
// we need a cluster client as well because ES has put some methods from the indices API into the cluster client
// (component templates)
private final ClusterTemplate clusterTemplate;
protected final ElasticsearchConverter elasticsearchConverter;
@Nullable protected final Class<?> boundClass;
@Nullable protected final IndexCoordinates boundIndex;
public IndicesTemplate(ElasticsearchIndicesClient client, ClusterTemplate clusterTemplate,
ElasticsearchConverter elasticsearchConverter, Class<?> boundClass) {
public IndicesTemplate(ElasticsearchIndicesClient client, ElasticsearchConverter elasticsearchConverter,
Class<?> boundClass) {
super(client, elasticsearchConverter);
Assert.notNull(clusterTemplate, "cluster must not be null");
Assert.notNull(elasticsearchConverter, "elasticsearchConverter must not be null");
Assert.notNull(boundClass, "boundClass may not be null");
this.clusterTemplate = clusterTemplate;
this.elasticsearchConverter = elasticsearchConverter;
this.boundClass = boundClass;
this.boundIndex = null;
}
public IndicesTemplate(ElasticsearchIndicesClient client, ClusterTemplate clusterTemplate,
ElasticsearchConverter elasticsearchConverter, IndexCoordinates boundIndex) {
public IndicesTemplate(ElasticsearchIndicesClient client, ElasticsearchConverter elasticsearchConverter,
IndexCoordinates boundIndex) {
super(client, elasticsearchConverter);
Assert.notNull(clusterTemplate, "cluster must not be null");
Assert.notNull(elasticsearchConverter, "elasticsearchConverter must not be null");
Assert.notNull(boundIndex, "boundIndex must not be null");
this.clusterTemplate = clusterTemplate;
this.elasticsearchConverter = elasticsearchConverter;
this.boundClass = null;
this.boundIndex = boundIndex;
@@ -345,87 +338,6 @@ public class IndicesTemplate extends ChildTemplate<ElasticsearchTransport, Elast
return execute(client -> client.deleteTemplate(deleteTemplateRequestES)).acknowledged();
}
@Override
public boolean putIndexTemplate(PutIndexTemplateRequest putIndexTemplateRequest) {
co.elastic.clients.elasticsearch.indices.PutIndexTemplateRequest putIndexTemplateRequestES = requestConverter
.indicesPutIndexTemplateRequest(putIndexTemplateRequest);
return execute(client -> client.putIndexTemplate(putIndexTemplateRequestES)).acknowledged();
}
@Override
public boolean existsIndexTemplate(ExistsIndexTemplateRequest existsIndexTemplateRequest) {
Assert.notNull(existsIndexTemplateRequest, "existsIndexTemplateRequest must not be null");
co.elastic.clients.elasticsearch.indices.ExistsIndexTemplateRequest existsTemplateRequestES = requestConverter
.indicesExistsIndexTemplateRequest(existsIndexTemplateRequest);
return execute(client -> client.existsIndexTemplate(existsTemplateRequestES)).value();
}
@Override
public List<TemplateResponse> getIndexTemplate(GetIndexTemplateRequest getIndexTemplateRequest) {
Assert.notNull(getIndexTemplateRequest, "getIndexTemplateRequest must not be null");
co.elastic.clients.elasticsearch.indices.GetIndexTemplateRequest getIndexTemplateRequestES = requestConverter
.indicesGetIndexTemplateRequest(getIndexTemplateRequest);
var getIndexTemplateResponse = execute(client -> client.getIndexTemplate(getIndexTemplateRequestES));
return responseConverter.getIndexTemplates(getIndexTemplateResponse);
}
@Override
public boolean deleteIndexTemplate(DeleteIndexTemplateRequest deleteIndexTemplateRequest) {
Assert.notNull(deleteIndexTemplateRequest, "deleteIndexTemplateRequest must not be null");
co.elastic.clients.elasticsearch.indices.DeleteIndexTemplateRequest deleteIndexTemplateRequestES = requestConverter
.indicesDeleteIndexTemplateRequest(deleteIndexTemplateRequest);
return execute(client -> client.deleteIndexTemplate(deleteIndexTemplateRequestES)).acknowledged();
}
@Override
public boolean putComponentTemplate(PutComponentTemplateRequest putComponentTemplateRequest) {
Assert.notNull(putComponentTemplateRequest, "putComponentTemplateRequest must not be null");
co.elastic.clients.elasticsearch.cluster.PutComponentTemplateRequest putComponentTemplateRequestES = requestConverter
.clusterPutComponentTemplateRequest(putComponentTemplateRequest);
// the new Elasticsearch client has this call in the cluster index
return clusterTemplate.execute(client -> client.putComponentTemplate(putComponentTemplateRequestES)).acknowledged();
}
@Override
public boolean existsComponentTemplate(ExistsComponentTemplateRequest existsComponentTemplateRequest) {
Assert.notNull(existsComponentTemplateRequest, "existsComponentTemplateRequest must not be null");
co.elastic.clients.elasticsearch.cluster.ExistsComponentTemplateRequest existsComponentTemplateRequestES = requestConverter
.clusterExistsComponentTemplateRequest(existsComponentTemplateRequest);
return clusterTemplate.execute(client -> client.existsComponentTemplate(existsComponentTemplateRequestES)).value();
}
@Override
public List<TemplateResponse> getComponentTemplate(GetComponentTemplateRequest getComponentTemplateRequest) {
co.elastic.clients.elasticsearch.cluster.GetComponentTemplateRequest getComponentTemplateRequestES = requestConverter
.clusterGetComponentTemplateRequest(getComponentTemplateRequest);
var response = clusterTemplate.execute(client -> client.getComponentTemplate(getComponentTemplateRequestES));
return responseConverter.clusterGetComponentTemplates(response);
}
@Override
public boolean deleteComponentTemplate(DeleteComponentTemplateRequest deleteComponentTemplateRequest) {
Assert.notNull(deleteComponentTemplateRequest, "deleteComponentTemplateRequest must not be null");
co.elastic.clients.elasticsearch.cluster.DeleteComponentTemplateRequest deleteComponentTemplateRequestES = requestConverter
.clusterDeleteComponentTemplateRequest(deleteComponentTemplateRequest);
return clusterTemplate.execute(client -> client.deleteComponentTemplate(deleteComponentTemplateRequestES))
.acknowledged();
}
@Override
public List<IndexInformation> getInformation(IndexCoordinates indexCoordinates) {
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -15,7 +15,6 @@
*/
package org.springframework.data.elasticsearch.client.elc;
import co.elastic.clients.elasticsearch._types.KnnQuery;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregation;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
@@ -31,7 +30,6 @@ import java.util.Map;
import org.springframework.data.elasticsearch.core.query.BaseQuery;
import org.springframework.data.elasticsearch.core.query.ScriptedField;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* A {@link org.springframework.data.elasticsearch.core.query.Query} implementation using query builders from the new
@@ -44,16 +42,15 @@ import org.springframework.util.Assert;
public class NativeQuery extends BaseQuery {
@Nullable private final Query query;
@Nullable private org.springframework.data.elasticsearch.core.query.Query springDataQuery;
@Nullable private Query filter;
// note: the new client does not have pipeline aggs, these are just set up as normal aggs
private final Map<String, Aggregation> aggregations = new LinkedHashMap<>();
@Nullable private Suggester suggester;
@Nullable private FieldCollapse fieldCollapse;
private List<ScriptedField> scriptedFields = Collections.emptyList();
private List<SortOptions> sortOptions = Collections.emptyList();
private Map<String, JsonData> searchExtensions = Collections.emptyMap();
@Nullable private KnnQuery knnQuery;
public NativeQuery(NativeQueryBuilder builder) {
super(builder);
@@ -62,15 +59,9 @@ public class NativeQuery extends BaseQuery {
this.aggregations.putAll(builder.getAggregations());
this.suggester = builder.getSuggester();
this.fieldCollapse = builder.getFieldCollapse();
this.scriptedFields = builder.getScriptedFields();
this.sortOptions = builder.getSortOptions();
this.searchExtensions = builder.getSearchExtensions();
if (builder.getSpringDataQuery() != null) {
Assert.isTrue(!NativeQuery.class.isAssignableFrom(builder.getSpringDataQuery().getClass()),
"Cannot add an NativeQuery in a NativeQuery");
}
this.springDataQuery = builder.getSpringDataQuery();
this.knnQuery = builder.getKnnQuery();
}
public NativeQuery(@Nullable Query query) {
@@ -105,6 +96,10 @@ public class NativeQuery extends BaseQuery {
return fieldCollapse;
}
public List<ScriptedField> getScriptedFields() {
return scriptedFields;
}
public List<SortOptions> getSortOptions() {
return sortOptions;
}
@@ -112,25 +107,4 @@ public class NativeQuery extends BaseQuery {
public Map<String, JsonData> getSearchExtensions() {
return searchExtensions;
}
/**
* @see NativeQueryBuilder#withQuery(org.springframework.data.elasticsearch.core.query.Query).
* @since 5.1
*/
public void setSpringDataQuery(@Nullable org.springframework.data.elasticsearch.core.query.Query springDataQuery) {
this.springDataQuery = springDataQuery;
}
/**
* @since 5.1
*/
@Nullable
public KnnQuery getKnnQuery() {
return knnQuery;
}
@Nullable
public org.springframework.data.elasticsearch.core.query.Query getSpringDataQuery() {
return springDataQuery;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2024 the original author or authors.
* Copyright 2022-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.
@@ -15,7 +15,6 @@
*/
package org.springframework.data.elasticsearch.client.elc;
import co.elastic.clients.elasticsearch._types.KnnQuery;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregation;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
@@ -32,6 +31,7 @@ import java.util.Map;
import java.util.function.Function;
import org.springframework.data.elasticsearch.core.query.BaseQueryBuilder;
import org.springframework.data.elasticsearch.core.query.ScriptedField;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -47,12 +47,10 @@ public class NativeQueryBuilder extends BaseQueryBuilder<NativeQuery, NativeQuer
private final Map<String, Aggregation> aggregations = new LinkedHashMap<>();
@Nullable private Suggester suggester;
@Nullable private FieldCollapse fieldCollapse;
private final List<ScriptedField> scriptedFields = new ArrayList<>();
private List<SortOptions> sortOptions = new ArrayList<>();
private Map<String, JsonData> searchExtensions = new LinkedHashMap<>();
@Nullable private org.springframework.data.elasticsearch.core.query.Query springDataQuery;
@Nullable private KnnQuery knnQuery;
public NativeQueryBuilder() {}
@Nullable
@@ -79,6 +77,10 @@ public class NativeQueryBuilder extends BaseQueryBuilder<NativeQuery, NativeQuer
return fieldCollapse;
}
public List<ScriptedField> getScriptedFields() {
return scriptedFields;
}
public List<SortOptions> getSortOptions() {
return sortOptions;
}
@@ -87,16 +89,6 @@ public class NativeQueryBuilder extends BaseQueryBuilder<NativeQuery, NativeQuer
return this.searchExtensions;
}
@Nullable
public KnnQuery getKnnQuery() {
return knnQuery;
}
@Nullable
public org.springframework.data.elasticsearch.core.query.Query getSpringDataQuery() {
return springDataQuery;
}
public NativeQueryBuilder withQuery(Query query) {
Assert.notNull(query, "query must not be null");
@@ -143,10 +135,17 @@ public class NativeQueryBuilder extends BaseQueryBuilder<NativeQuery, NativeQuer
return this;
}
public NativeQueryBuilder withScriptedField(ScriptedField scriptedField) {
Assert.notNull(scriptedField, "scriptedField must not be null");
this.scriptedFields.add(scriptedField);
return this;
}
public NativeQueryBuilder withSort(List<SortOptions> values) {
Assert.notEmpty(values, "values must not be empty");
sortOptions.clear();
sortOptions.addAll(values);
@@ -185,32 +184,11 @@ public class NativeQueryBuilder extends BaseQueryBuilder<NativeQuery, NativeQuer
Assert.notNull(searchExtensions, "searchExtensions must not be null");
this.searchExtensions.putAll(searchExtensions);
return this;
}
/**
* Allows to use a {@link org.springframework.data.elasticsearch.core.query.Query} within a NativeQuery. Cannot be
* used together with {@link #withQuery(Query)} that sets an Elasticsearch query. Passing in a {@link NativeQuery}
* will result in an exception when {@link #build()} is called.
*
* @since 5.1
*/
public NativeQueryBuilder withQuery(org.springframework.data.elasticsearch.core.query.Query query) {
this.springDataQuery = query;
return this;
}
/**
* @since 5.1
*/
public NativeQueryBuilder withKnnQuery(KnnQuery knnQuery) {
this.knnQuery = knnQuery;
searchExtensions.putAll(searchExtensions);
return this;
}
public NativeQuery build() {
Assert.isTrue(query == null || springDataQuery == null, "Cannot have both a native query and a Spring Data query");
return new NativeQuery(this);
}
}
@@ -1,196 +0,0 @@
/*
* Copyright 2022-2024 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._types.FieldValue;
import co.elastic.clients.elasticsearch._types.LatLonGeoLocation;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregation;
import co.elastic.clients.elasticsearch._types.query_dsl.IdsQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchAllQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Operator;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch._types.query_dsl.QueryStringQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.TermQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.WildcardQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.WrapperQuery;
import co.elastic.clients.util.ObjectBuilder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import java.util.function.Function;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
import org.springframework.data.elasticsearch.core.query.BaseQueryBuilder;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Utility class simplifying the creation of some more complex queries and type.
*
* @author Peter-Josef Meisch
* @since 4.4
*/
public final class Queries {
private Queries() {}
public static IdsQuery idsQuery(List<String> ids) {
Assert.notNull(ids, "ids must not be null");
return IdsQuery.of(i -> i.values(ids));
}
public static Query idsQueryAsQuery(List<String> ids) {
Assert.notNull(ids, "ids must not be null");
Function<Query.Builder, ObjectBuilder<Query>> builder = b -> b.ids(idsQuery(ids));
return builder.apply(new Query.Builder()).build();
}
public static MatchQuery matchQuery(String fieldName, String query, @Nullable Operator operator,
@Nullable Float boost) {
Assert.notNull(fieldName, "fieldName must not be null");
Assert.notNull(query, "query must not be null");
return MatchQuery.of(mb -> mb.field(fieldName).query(FieldValue.of(query)).operator(operator).boost(boost));
}
public static Query matchQueryAsQuery(String fieldName, String query, @Nullable Operator operator,
@Nullable Float boost) {
Function<Query.Builder, ObjectBuilder<Query>> builder = b -> b.match(matchQuery(fieldName, query, operator, boost));
return builder.apply(new Query.Builder()).build();
}
public static MatchAllQuery matchAllQuery() {
return MatchAllQuery.of(b -> b);
}
public static Query matchAllQueryAsQuery() {
Function<Query.Builder, ObjectBuilder<Query>> builder = b -> b.matchAll(matchAllQuery());
return builder.apply(new Query.Builder()).build();
}
public static QueryStringQuery queryStringQuery(String fieldName, String query, @Nullable Float boost) {
return queryStringQuery(fieldName, query, null, null, boost);
}
public static QueryStringQuery queryStringQuery(String fieldName, String query, Operator defaultOperator,
@Nullable Float boost) {
return queryStringQuery(fieldName, query, null, defaultOperator, boost);
}
public static QueryStringQuery queryStringQuery(String fieldName, String query, @Nullable Boolean analyzeWildcard,
@Nullable Float boost) {
return queryStringQuery(fieldName, query, analyzeWildcard, null, boost);
}
public static QueryStringQuery queryStringQuery(String fieldName, String query, @Nullable Boolean analyzeWildcard,
@Nullable Operator defaultOperator, @Nullable Float boost) {
Assert.notNull(fieldName, "fieldName must not be null");
Assert.notNull(query, "query must not be null");
return QueryStringQuery.of(qs -> qs.fields(fieldName).query(query).analyzeWildcard(analyzeWildcard)
.defaultOperator(defaultOperator).boost(boost));
}
public static TermQuery termQuery(String fieldName, String value) {
Assert.notNull(fieldName, "fieldName must not be null");
Assert.notNull(value, "value must not be null");
return TermQuery.of(t -> t.field(fieldName).value(FieldValue.of(value)));
}
public static Query termQueryAsQuery(String fieldName, String value) {
Function<Query.Builder, ObjectBuilder<Query>> builder = q -> q.term(termQuery(fieldName, value));
return builder.apply(new Query.Builder()).build();
}
public static WildcardQuery wildcardQuery(String field, String value) {
Assert.notNull(field, "field must not be null");
Assert.notNull(value, "value must not be null");
return WildcardQuery.of(w -> w.field(field).wildcard(value));
}
public static Query wildcardQueryAsQuery(String field, String value) {
Function<Query.Builder, ObjectBuilder<Query>> builder = q -> q.wildcard(wildcardQuery(field, value));
return builder.apply(new Query.Builder()).build();
}
public static Query wrapperQueryAsQuery(String query) {
Function<Query.Builder, ObjectBuilder<Query>> builder = q -> q.wrapper(wrapperQuery(query));
return builder.apply(new Query.Builder()).build();
}
public static WrapperQuery wrapperQuery(String query) {
Assert.notNull(query, "query must not be null");
String encodedValue = Base64.getEncoder().encodeToString(query.getBytes(StandardCharsets.UTF_8));
return WrapperQuery.of(wq -> wq.query(encodedValue));
}
public static LatLonGeoLocation latLon(GeoPoint geoPoint) {
Assert.notNull(geoPoint, "geoPoint must not be null");
return latLon(geoPoint.getLat(), geoPoint.getLon());
}
public static LatLonGeoLocation latLon(double lat, double lon) {
return LatLonGeoLocation.of(_0 -> _0.lat(lat).lon(lon));
}
public static org.springframework.data.elasticsearch.core.query.Query getTermsAggsQuery(String aggsName,
String aggsField) {
return NativeQuery.builder() //
.withQuery(Queries.matchAllQueryAsQuery()) //
.withAggregation(aggsName, Aggregation.of(a -> a //
.terms(ta -> ta.field(aggsField)))) //
.withMaxResults(0) //
.build();
}
public static org.springframework.data.elasticsearch.core.query.Query queryWithIds(String... ids) {
return NativeQuery.builder().withIds(ids).build();
}
public static BaseQueryBuilder<?, ?> getBuilderWithMatchAllQuery() {
return NativeQuery.builder().withQuery(matchAllQueryAsQuery());
}
public static BaseQueryBuilder<?, ?> getBuilderWithTermQuery(String field, String value) {
return NativeQuery.builder().withQuery(termQueryAsQuery(field, value));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2024 the original author or authors.
* Copyright 2022-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.
@@ -42,9 +42,7 @@ import org.springframework.util.Assert;
*
* @author Peter-Josef Meisch
* @since 4.4
* @deprecated since 5.1, use {@link Queries} instead.
*/
@Deprecated(forRemoval = true)
public final class QueryBuilders {
private QueryBuilders() {}
@@ -64,7 +62,6 @@ public final class QueryBuilders {
return builder.apply(new Query.Builder()).build();
}
public static MatchQuery matchQuery(String fieldName, String query, @Nullable Operator operator,
@Nullable Float boost) {
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -20,8 +20,8 @@ import co.elastic.clients.elasticsearch.cluster.HealthResponse;
import co.elastic.clients.transport.ElasticsearchTransport;
import reactor.core.publisher.Mono;
import org.springframework.data.elasticsearch.client.erhlc.ReactiveClusterOperations;
import org.springframework.data.elasticsearch.core.cluster.ClusterHealth;
import org.springframework.data.elasticsearch.core.cluster.ReactiveClusterOperations;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -237,29 +237,6 @@ public class ReactiveElasticsearchClient extends ApiClient<ElasticsearchTranspor
return search(fn.apply(new SearchRequest.Builder()).build(), tDocumentClass);
}
/**
* @since 5.1
*/
public <T> Mono<SearchTemplateResponse<T>> searchTemplate(SearchTemplateRequest request, Class<T> tDocumentClass) {
Assert.notNull(request, "request must not be null");
Assert.notNull(tDocumentClass, "tDocumentClass must not be null");
return Mono.fromFuture(transport.performRequestAsync(request,
SearchTemplateRequest.createSearchTemplateEndpoint(this.getDeserializer(tDocumentClass)), transportOptions));
}
/**
* @since 5.1
*/
public <T> Mono<SearchTemplateResponse<T>> searchTemplate(
Function<SearchTemplateRequest.Builder, ObjectBuilder<SearchTemplateRequest>> fn, Class<T> tDocumentClass) {
Assert.notNull(fn, "fn must not be null");
return searchTemplate(fn.apply(new SearchTemplateRequest.Builder()).build(), tDocumentClass);
}
public <T> Mono<ScrollResponse<T>> scroll(ScrollRequest request, Class<T> tDocumentClass) {
Assert.notNull(request, "request must not be null");
@@ -343,67 +320,4 @@ public class ReactiveElasticsearchClient extends ApiClient<ElasticsearchTranspor
}
// endregion
// region script api
/**
* @since 5.1
*/
public Mono<PutScriptResponse> putScript(PutScriptRequest request) {
Assert.notNull(request, "request must not be null");
return Mono.fromFuture(transport.performRequestAsync(request, PutScriptRequest._ENDPOINT, transportOptions));
}
/**
* @since 5.1
*/
public Mono<PutScriptResponse> putScript(Function<PutScriptRequest.Builder, ObjectBuilder<PutScriptRequest>> fn) {
Assert.notNull(fn, "fn must not be null");
return putScript(fn.apply(new PutScriptRequest.Builder()).build());
}
/**
* @since 5.1
*/
public Mono<GetScriptResponse> getScript(GetScriptRequest request) {
Assert.notNull(request, "request must not be null");
return Mono.fromFuture(transport.performRequestAsync(request, GetScriptRequest._ENDPOINT, transportOptions));
}
/**
* @since 5.1
*/
public Mono<GetScriptResponse> getScript(Function<GetScriptRequest.Builder, ObjectBuilder<GetScriptRequest>> fn) {
Assert.notNull(fn, "fn must not be null");
return getScript(fn.apply(new GetScriptRequest.Builder()).build());
}
/**
* @since 5.1
*/
public Mono<DeleteScriptResponse> deleteScript(DeleteScriptRequest request) {
Assert.notNull(request, "request must not be null");
return Mono.fromFuture(transport.performRequestAsync(request, DeleteScriptRequest._ENDPOINT, transportOptions));
}
/**
* @since 5.1
*/
public Mono<DeleteScriptResponse> deleteScript(
Function<DeleteScriptRequest.Builder, ObjectBuilder<DeleteScriptRequest>> fn) {
Assert.notNull(fn, "fn must not be null");
return deleteScript(fn.apply(new DeleteScriptRequest.Builder()).build());
}
// endregion
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -16,10 +16,10 @@
package org.springframework.data.elasticsearch.client.elc;
import co.elastic.clients.ApiClient;
import co.elastic.clients.elasticsearch.cluster.*;
import co.elastic.clients.elasticsearch.cluster.HealthRequest;
import co.elastic.clients.elasticsearch.cluster.HealthResponse;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.TransportOptions;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import co.elastic.clients.util.ObjectBuilder;
import reactor.core.publisher.Mono;
@@ -53,47 +53,4 @@ public class ReactiveElasticsearchClusterClient
public Mono<HealthResponse> health(Function<HealthRequest.Builder, ObjectBuilder<HealthRequest>> fn) {
return health(fn.apply(new HealthRequest.Builder()).build());
}
public Mono<PutComponentTemplateResponse> putComponentTemplate(
PutComponentTemplateRequest putComponentTemplateRequest) {
return Mono.fromFuture(transport.performRequestAsync(putComponentTemplateRequest,
PutComponentTemplateRequest._ENDPOINT, transportOptions));
}
public Mono<PutComponentTemplateResponse> putComponentTemplate(
Function<PutComponentTemplateRequest.Builder, ObjectBuilder<PutComponentTemplateRequest>> fn) {
return putComponentTemplate(fn.apply(new PutComponentTemplateRequest.Builder()).build());
}
public Mono<GetComponentTemplateResponse> getComponentTemplate(
GetComponentTemplateRequest getComponentTemplateRequest) {
return Mono.fromFuture(transport.performRequestAsync(getComponentTemplateRequest,
GetComponentTemplateRequest._ENDPOINT, transportOptions));
}
public Mono<GetComponentTemplateResponse> getComponentTemplate(
Function<GetComponentTemplateRequest.Builder, ObjectBuilder<GetComponentTemplateRequest>> fn) {
return getComponentTemplate(fn.apply(new GetComponentTemplateRequest.Builder()).build());
}
public Mono<BooleanResponse> existsComponentTemplate(ExistsComponentTemplateRequest existsComponentTemplateRequest) {
return Mono.fromFuture(transport.performRequestAsync(existsComponentTemplateRequest,
ExistsComponentTemplateRequest._ENDPOINT, transportOptions));
}
public Mono<BooleanResponse> existsComponentTemplate(
Function<ExistsComponentTemplateRequest.Builder, ObjectBuilder<ExistsComponentTemplateRequest>> fn) {
return existsComponentTemplate(fn.apply(new ExistsComponentTemplateRequest.Builder()).build());
}
public Mono<DeleteComponentTemplateResponse> deleteComponentTemplate(
DeleteComponentTemplateRequest deleteComponentTemplateRequest) {
return Mono.fromFuture(transport.performRequestAsync(deleteComponentTemplateRequest,
DeleteComponentTemplateRequest._ENDPOINT, transportOptions));
}
public Mono<DeleteComponentTemplateResponse> deleteComponentTemplate(
Function<DeleteComponentTemplateRequest.Builder, ObjectBuilder<DeleteComponentTemplateRequest>> fn) {
return deleteComponentTemplate(fn.apply(new DeleteComponentTemplateRequest.Builder()).build());
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2024 the original author or authors.
* Copyright 2021-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.

Some files were not shown because too many files have changed in this diff Show More