1
0
mirror of synced 2026-05-23 12:43:17 +00:00

Compare commits

..

31 Commits

Author SHA1 Message Date
Mark Paluch 89528e0e59 Release version 5.0.3 (2022.0.3).
See #2462
2023-03-03 10:59:34 +01:00
Mark Paluch 42e49e8ff7 Prepare 5.0.3 (2022.0.3).
See #2462
2023-03-03 10:59:18 +01:00
Peter-Josef Meisch b52fc2f0d7 Fix putMapping request creation .
Original Pull Request #2483
Closes #2487

(cherry picked from commit 63cebd7038)
2023-02-26 15:43:00 +01:00
Mark Paluch 1923721ebf Upgrade to Maven Wrapper 3.9.0.
See #2472
2023-02-20 11:59:41 +01:00
Mark Paluch 8834cbfe03 After release cleanups.
See #2427
2023-02-17 11:02:27 +01:00
Mark Paluch 2dabb2f89f Prepare next development iteration.
See #2427
2023-02-17 11:02:26 +01:00
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
176 changed files with 1163 additions and 8005 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 @@
#Mon Jul 03 09:48:29 CEST 2023
#Mon Feb 20 11:59:41 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.3/apache-maven-3.9.3-bin.zip
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.0/apache-maven-3.9.0-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
+25 -44
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 ci/verify.sh'
sh "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 ci/verify.sh'
sh "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"
}
}
}
@@ -93,15 +68,17 @@ pipeline {
steps {
script {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.basic']) {
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml -Pci,artifactory -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch-non-root ' +
'-Dartifactory.server=https://repo.spring.io ' +
"-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'
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'
}
}
}
}
@@ -111,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>
----
+6 -8
View File
@@ -1,21 +1,19 @@
# Java versions
java.main.tag=17.0.7_7-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.22
docker.mongodb.5.0.version=5.0.18
docker.mongodb.6.0.version=6.0.7
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.12
docker.redis.6.version=6.2.10
# Supported versions of Cassandra
docker.cassandra.3.version=3.11.15
docker.cassandra.3.version=3.11.14
# Docker environment settings
docker.java.inside.basic=-v $HOME:/tmp/jenkins-home
+85 -15
View File
@@ -5,12 +5,12 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>5.1.2</version>
<version>5.0.3</version>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>3.1.2</version>
<version>3.0.3</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.2</springdata.commons>
<springdata.commons>3.0.3</springdata.commons>
<!-- version of the RestHighLevelClient -->
<elasticsearch-rhlc>7.17.11</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>
+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,29 +0,0 @@
/*
* 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.
* 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);
}
}
@@ -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
*/
@@ -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,42 +0,0 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.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 {
}
@@ -109,7 +109,7 @@ public @interface InnerField {
/**
* @since 4.0
*/
String similarity() default Similarity.Default;
Similarity similarity() default Similarity.Default;
/**
* @since 4.0
@@ -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;
}
}
@@ -21,7 +21,7 @@ import org.springframework.data.util.ReactiveWrappers;
/**
* @author Peter-Josef Meisch
* @since 5.1
* @since 5.0.1
*/
public class ElasticsearchAotPredicates {
@@ -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 {
@@ -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);
}
/**
@@ -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) {
@@ -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;
@@ -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);
}
@@ -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,7 +34,13 @@ import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
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;
@@ -192,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()));
@@ -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);
@@ -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());
}
@@ -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) {
@@ -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;
}
}
@@ -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-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.client.elc;
import co.elastic.clients.elasticsearch._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));
}
}
@@ -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) {
@@ -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;
/**
@@ -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
}
@@ -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());
}
}
@@ -15,10 +15,11 @@
*/
package org.springframework.data.elasticsearch.client.elc;
import static co.elastic.clients.util.ApiTypeHelper.DANGEROUS_disableRequiredPropertiesCheck;
import static org.springframework.data.elasticsearch.client.elc.TypeUtils.result;
import static co.elastic.clients.util.ApiTypeHelper.*;
import static org.springframework.data.elasticsearch.client.elc.TypeUtils.*;
import co.elastic.clients.elasticsearch._types.Result;
import co.elastic.clients.elasticsearch._types.Time;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem;
import co.elastic.clients.elasticsearch.core.get.GetResult;
@@ -34,34 +35,35 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.BulkFailureException;
import org.springframework.data.elasticsearch.NoSuchIndexException;
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
import org.springframework.data.elasticsearch.client.UnsupportedBackendOperation;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.cluster.ReactiveClusterOperations;
import org.springframework.data.elasticsearch.client.erhlc.ReactiveClusterOperations;
import org.springframework.data.elasticsearch.client.util.ScrollState;
import org.springframework.data.elasticsearch.core.AbstractReactiveElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.AggregationContainer;
import org.springframework.data.elasticsearch.core.IndexedObjectInformation;
import org.springframework.data.elasticsearch.core.MultiGetItem;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
import org.springframework.data.elasticsearch.core.ReactiveIndexOperations;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.document.SearchDocument;
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.data.elasticsearch.core.query.BulkOptions;
import org.springframework.data.elasticsearch.core.query.ByQueryResponse;
import org.springframework.data.elasticsearch.core.query.Query;
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;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
* Implementation of {@link org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations} using the new
@@ -72,8 +74,6 @@ import org.springframework.util.StringUtils;
*/
public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearchTemplate {
private static final Logger LOGGER = LoggerFactory.getLogger(ReactiveElasticsearchTemplate.class);
private final ReactiveElasticsearchClient client;
private final RequestConverter requestConverter;
private final ResponseConverter responseConverter;
@@ -102,7 +102,6 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
.zipWith(//
Mono.from(execute((ClientCallback<Publisher<IndexResponse>>) client -> client.index(indexRequest))) //
.map(indexResponse -> new IndexResponseMetaData(indexResponse.id(), //
indexResponse.index(), //
indexResponse.seqNo(), //
indexResponse.primaryTerm(), //
indexResponse.version() //
@@ -130,43 +129,13 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
.flatMap(indexAndResponse -> {
T savedEntity = entities.entityAt(indexAndResponse.getT1());
BulkResponseItem response = indexAndResponse.getT2();
updateIndexedObject(savedEntity, new IndexedObjectInformation( //
response.id(), //
response.index(), //
response.seqNo(), //
response.primaryTerm(), //
response.version()));
updateIndexedObject(savedEntity, IndexedObjectInformation.of(response.id(), response.seqNo(),
response.primaryTerm(), response.version()));
return maybeCallbackAfterSave(savedEntity, index);
});
});
}
@Override
protected Mono<Boolean> doExists(String id, IndexCoordinates index) {
Assert.notNull(id, "id must not be null");
Assert.notNull(index, "index must not be null");
GetRequest getRequest = requestConverter.documentGetRequest(id, routingResolver.getRouting(), index, true);
return Mono.from(execute(
((ClientCallback<Publisher<GetResponse<EntityAsMap>>>) client -> client.get(getRequest, EntityAsMap.class))))
.map(GetResult::found) //
.onErrorReturn(NoSuchIndexException.class, false);
}
@Override
public Mono<ByQueryResponse> delete(Query query, Class<?> entityType, IndexCoordinates index) {
Assert.notNull(query, "query must not be null");
DeleteByQueryRequest request = requestConverter.documentDeleteByQueryRequest(query, routingResolver.getRouting(),
entityType, index, getRefreshPolicy());
return Mono
.from(execute((ClientCallback<Publisher<DeleteByQueryResponse>>) client -> client.deleteByQuery(request)))
.map(responseConverter::byQueryResponse);
}
@Override
public <T> Mono<T> get(String id, Class<T> entityType, IndexCoordinates index) {
@@ -214,29 +183,6 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
: Mono.just(response.task()));
}
@Override
public Mono<UpdateResponse> update(UpdateQuery updateQuery, IndexCoordinates index) {
Assert.notNull(updateQuery, "UpdateQuery must not be null");
Assert.notNull(index, "Index must not be null");
UpdateRequest<Document, ?> request = requestConverter.documentUpdateRequest(updateQuery, index, getRefreshPolicy(),
routingResolver.getRouting());
return Mono.from(execute(
(ClientCallback<Publisher<co.elastic.clients.elasticsearch.core.UpdateResponse<Document>>>) client -> client
.update(request, Document.class)))
.flatMap(response -> {
UpdateResponse.Result result = result(response.result());
return result == null ? Mono.empty() : Mono.just(UpdateResponse.of(result));
});
}
@Override
public Mono<ByQueryResponse> updateByQuery(UpdateQuery updateQuery, IndexCoordinates index) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public Mono<Void> bulkUpdate(List<UpdateQuery> queries, BulkOptions bulkOptions, IndexCoordinates index) {
@@ -333,116 +279,87 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
return new ReactiveElasticsearchTemplate(client, converter);
}
@Override
protected Mono<Boolean> doExists(String id, IndexCoordinates index) {
Assert.notNull(id, "id must not be null");
Assert.notNull(index, "index must not be null");
GetRequest getRequest = requestConverter.documentGetRequest(id, routingResolver.getRouting(), index, true);
return Mono.from(execute(
((ClientCallback<Publisher<GetResponse<EntityAsMap>>>) client -> client.get(getRequest, EntityAsMap.class))))
.map(GetResult::found) //
.onErrorReturn(NoSuchIndexException.class, false);
}
@Override
public Mono<ByQueryResponse> delete(Query query, Class<?> entityType, IndexCoordinates index) {
Assert.notNull(query, "query must not be null");
DeleteByQueryRequest request = requestConverter.documentDeleteByQueryRequest(query, entityType, index,
getRefreshPolicy());
return Mono
.from(execute((ClientCallback<Publisher<DeleteByQueryResponse>>) client -> client.deleteByQuery(request)))
.map(responseConverter::byQueryResponse);
}
// region search operations
@Override
protected Flux<SearchDocument> doFind(Query query, Class<?> 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");
return Flux.defer(() -> {
boolean useScroll = !(query.getPageable().isPaged() || query.isLimiting());
SearchRequest searchRequest = requestConverter.searchRequest(query, clazz, index, false, useScroll);
if (useScroll) {
return doScroll(searchRequest);
} else {
return doFind(searchRequest);
}
});
if (query instanceof SearchTemplateQuery searchTemplateQuery) {
return Flux.defer(() -> doSearch(searchTemplateQuery, clazz, index));
} else {
return Flux.defer(() -> {
boolean queryIsUnbounded = !(query.getPageable().isPaged() || query.isLimiting());
return queryIsUnbounded ? doFindUnbounded(query, clazz, index) : doFindBounded(query, clazz, index);
});
}
}
private Flux<SearchDocument> doFindUnbounded(Query query, Class<?> clazz, IndexCoordinates index) {
private Flux<SearchDocument> doScroll(SearchRequest searchRequest) {
if (query instanceof BaseQuery baseQuery) {
var pitKeepAlive = Duration.ofMinutes(5);
// setup functions for Flux.usingWhen()
Mono<PitSearchAfter> resourceSupplier = openPointInTime(index, pitKeepAlive, true)
.map(pit -> new PitSearchAfter(baseQuery, pit));
Time scrollTimeout = searchRequest.scroll() != null ? searchRequest.scroll() : Time.of(t -> t.time("1m"));
Function<PitSearchAfter, Publisher<?>> asyncComplete = this::cleanupPit;
Flux<ResponseBody<EntityAsMap>> searchResponses = Flux.usingWhen(Mono.fromSupplier(ScrollState::new), //
state -> Mono
.from(execute((ClientCallback<Publisher<ResponseBody<EntityAsMap>>>) client -> client.search(searchRequest,
EntityAsMap.class))) //
.expand(entityAsMapSearchResponse -> {
BiFunction<PitSearchAfter, Throwable, Publisher<?>> asyncError = (psa, ex) -> {
if (LOGGER.isErrorEnabled()) {
LOGGER.error(String.format("Error during pit/search_after"), ex);
}
return cleanupPit(psa);
};
state.updateScrollId(entityAsMapSearchResponse.scrollId());
Function<PitSearchAfter, Publisher<?>> asyncCancel = psa -> {
if (LOGGER.isWarnEnabled()) {
LOGGER.warn(String.format("pit/search_after was cancelled"));
}
return cleanupPit(psa);
};
Function<PitSearchAfter, Publisher<? extends ResponseBody<EntityAsMap>>> resourceClosure = psa -> {
baseQuery.setPointInTime(new Query.PointInTime(psa.getPit(), pitKeepAlive));
baseQuery.addSort(Sort.by("_shard_doc"));
SearchRequest firstSearchRequest = requestConverter.searchRequest(baseQuery, routingResolver.getRouting(),
clazz, index, false, true);
return Mono.from(execute((ClientCallback<Publisher<ResponseBody<EntityAsMap>>>) client -> client
.search(firstSearchRequest, EntityAsMap.class))).expand(entityAsMapSearchResponse -> {
var hits = entityAsMapSearchResponse.hits().hits();
if (CollectionUtils.isEmpty(hits)) {
if (entityAsMapSearchResponse.hits() == null
|| CollectionUtils.isEmpty(entityAsMapSearchResponse.hits().hits())) {
return Mono.empty();
}
List<Object> sortOptions = hits.get(hits.size() - 1).sort().stream().map(TypeUtils::toObject)
.collect(Collectors.toList());
baseQuery.setSearchAfter(sortOptions);
SearchRequest followSearchRequest = requestConverter.searchRequest(baseQuery,
routingResolver.getRouting(), clazz, index, false, true);
return Mono.from(execute((ClientCallback<Publisher<ResponseBody<EntityAsMap>>>) client -> client
.search(followSearchRequest, EntityAsMap.class)));
});
return Mono.from(execute((ClientCallback<Publisher<ScrollResponse<EntityAsMap>>>) client1 -> {
ScrollRequest scrollRequest = ScrollRequest
.of(sr -> sr.scrollId(state.getScrollId()).scroll(scrollTimeout));
return client1.scroll(scrollRequest, EntityAsMap.class);
}));
}),
this::cleanupScroll, (state, ex) -> cleanupScroll(state), this::cleanupScroll);
};
Flux<ResponseBody<EntityAsMap>> searchResponses = Flux.usingWhen(resourceSupplier, resourceClosure, asyncComplete,
asyncError, asyncCancel);
return searchResponses.flatMapIterable(entityAsMapSearchResponse -> entityAsMapSearchResponse.hits().hits())
.map(entityAsMapHit -> DocumentAdapters.from(entityAsMapHit, jsonpMapper));
} else {
return Flux.error(new IllegalArgumentException("Query must be derived from BaseQuery"));
}
return searchResponses.flatMapIterable(entityAsMapSearchResponse -> entityAsMapSearchResponse.hits().hits())
.map(entityAsMapHit -> DocumentAdapters.from(entityAsMapHit, jsonpMapper));
}
private Publisher<?> cleanupPit(PitSearchAfter psa) {
var baseQuery = psa.getBaseQuery();
baseQuery.setPointInTime(null);
baseQuery.setSearchAfter(null);
baseQuery.setSort(psa.getSort());
var pit = psa.getPit();
return StringUtils.hasText(pit) ? closePointInTime(pit) : Mono.empty();
}
private Publisher<?> cleanupScroll(ScrollState state) {
static private class PitSearchAfter {
private final BaseQuery baseQuery;
@Nullable private final Sort sort;
private final String pit;
PitSearchAfter(BaseQuery baseQuery, String pit) {
this.baseQuery = baseQuery;
this.sort = baseQuery.getSort();
this.pit = pit;
if (state.getScrollIds().isEmpty()) {
return Mono.empty();
}
public BaseQuery getBaseQuery() {
return baseQuery;
}
@Nullable
public Sort getSort() {
return sort;
}
public String getPit() {
return pit;
}
return execute((ClientCallback<Publisher<ClearScrollResponse>>) client -> client
.clearScroll(ClearScrollRequest.of(csr -> csr.scrollId(state.getScrollIds()))));
}
@Override
@@ -451,8 +368,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
Assert.notNull(query, "query must not be null");
Assert.notNull(index, "index must not be null");
SearchRequest searchRequest = requestConverter.searchRequest(query, routingResolver.getRouting(), entityType, index,
true);
SearchRequest searchRequest = requestConverter.searchRequest(query, entityType, index, true, false);
return Mono
.from(execute((ClientCallback<Publisher<ResponseBody<EntityAsMap>>>) client -> client.search(searchRequest,
@@ -460,10 +376,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
.map(searchResponse -> searchResponse.hits().total() != null ? searchResponse.hits().total().value() : 0L);
}
private Flux<SearchDocument> doFindBounded(Query query, Class<?> clazz, IndexCoordinates index) {
SearchRequest searchRequest = requestConverter.searchRequest(query, routingResolver.getRouting(), clazz, index,
false, false);
private Flux<SearchDocument> doFind(SearchRequest searchRequest) {
return Mono
.from(execute((ClientCallback<Publisher<ResponseBody<EntityAsMap>>>) client -> client.search(searchRequest,
@@ -472,25 +385,13 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
.map(entityAsMapHit -> DocumentAdapters.from(entityAsMapHit, jsonpMapper));
}
private Flux<SearchDocument> doSearch(SearchTemplateQuery query, Class<?> clazz, IndexCoordinates index) {
var request = requestConverter.searchTemplate(query, routingResolver.getRouting(), index);
return Mono
.from(execute((ClientCallback<Publisher<SearchTemplateResponse<EntityAsMap>>>) client -> client
.searchTemplate(request, EntityAsMap.class))) //
.flatMapIterable(entityAsMapSearchResponse -> entityAsMapSearchResponse.hits().hits()) //
.map(entityAsMapHit -> DocumentAdapters.from(entityAsMapHit, jsonpMapper));
}
@Override
protected <T> Mono<SearchDocumentResponse> doFindForResponse(Query query, Class<?> clazz, IndexCoordinates index) {
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,
false);
SearchRequest searchRequest = requestConverter.searchRequest(query, clazz, index, false, false);
// noinspection unchecked
SearchDocumentCallback<T> callback = new ReadSearchDocumentCallback<>((Class<T>) clazz, index);
@@ -538,37 +439,6 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
// endregion
// region script operations
@Override
public Mono<Boolean> putScript(Script script) {
Assert.notNull(script, "script must not be null");
var request = requestConverter.scriptPut(script);
return Mono.from(execute((ClientCallback<Publisher<PutScriptResponse>>) client -> client.putScript(request)))
.map(PutScriptResponse::acknowledged);
}
@Override
public Mono<Script> getScript(String name) {
Assert.notNull(name, "name must not be null");
var request = requestConverter.scriptGet(name);
return Mono.from(execute((ClientCallback<Publisher<GetScriptResponse>>) client -> client.getScript(request)))
.mapNotNull(responseConverter::scriptResponse);
}
@Override
public Mono<Boolean> deleteScript(String name) {
Assert.notNull(name, "name must not be null");
var request = requestConverter.scriptDelete(name);
return Mono.from(execute((ClientCallback<Publisher<DeleteScriptResponse>>) client -> client.deleteScript(request)))
.map(DeleteScriptResponse::acknowledged);
}
// endregion
@Override
public Mono<String> getVendor() {
return Mono.just("Elasticsearch");
@@ -588,6 +458,29 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
})).map(infoResponse -> infoResponse.version().number());
}
@Override
public Mono<UpdateResponse> update(UpdateQuery updateQuery, IndexCoordinates index) {
Assert.notNull(updateQuery, "UpdateQuery must not be null");
Assert.notNull(index, "Index must not be null");
UpdateRequest<Document, ?> request = requestConverter.documentUpdateRequest(updateQuery, index, getRefreshPolicy(),
routingResolver.getRouting());
return Mono.from(execute(
(ClientCallback<Publisher<co.elastic.clients.elasticsearch.core.UpdateResponse<Document>>>) client -> client
.update(request, Document.class)))
.flatMap(response -> {
UpdateResponse.Result result = result(response.result());
return result == null ? Mono.empty() : Mono.just(UpdateResponse.of(result));
});
}
@Override
public Mono<ByQueryResponse> updateByQuery(UpdateQuery updateQuery, IndexCoordinates index) {
throw new UnsupportedOperationException("not implemented");
}
@Override
@Deprecated
public <T> Publisher<T> execute(ReactiveElasticsearchOperations.ClientCallback<Publisher<T>> callback) {
@@ -606,34 +499,27 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
@Override
public ReactiveIndexOperations indexOps(IndexCoordinates index) {
return new ReactiveIndicesTemplate(client.indices(), getReactiveClusterTemplate(), converter, index);
return new ReactiveIndicesTemplate(client.indices(), converter, index);
}
@Override
public ReactiveIndexOperations indexOps(Class<?> clazz) {
return new ReactiveIndicesTemplate(client.indices(), getReactiveClusterTemplate(), converter, clazz);
return new ReactiveIndicesTemplate(client.indices(), converter, clazz);
}
@Override
public ReactiveClusterOperations cluster() {
return getReactiveClusterTemplate();
}
/**
* @since 5.1
*/
private ReactiveClusterTemplate getReactiveClusterTemplate() {
return new ReactiveClusterTemplate(client.cluster(), converter);
}
@Override
public Query matchAllQuery() {
return NativeQuery.builder().withQuery(Queries.matchAllQueryAsQuery()).build();
return NativeQuery.builder().withQuery(QueryBuilders.matchAllQueryAsQuery()).build();
}
@Override
public Query idsQuery(List<String> ids) {
return NativeQuery.builder().withQuery(Queries.idsQueryAsQuery(ids)).build();
return NativeQuery.builder().withQuery(QueryBuilders.idsQueryAsQuery(ids)).build();
}
/**
@@ -15,7 +15,7 @@
*/
package org.springframework.data.elasticsearch.client.elc;
import static org.springframework.util.StringUtils.hasText;
import static org.springframework.util.StringUtils.*;
import co.elastic.clients.elasticsearch._types.AcknowledgedResponseBase;
import co.elastic.clients.elasticsearch.indices.*;
@@ -37,15 +37,15 @@ import org.springframework.data.elasticsearch.core.ReactiveIndexOperations;
import org.springframework.data.elasticsearch.core.ReactiveResourceUtil;
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.PutTemplateRequest;
import org.springframework.data.elasticsearch.core.index.ReactiveMappingBuilder;
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;
@@ -58,35 +58,27 @@ public class ReactiveIndicesTemplate
extends ReactiveChildTemplate<ElasticsearchTransport, ReactiveElasticsearchIndicesClient>
implements ReactiveIndexOperations {
// 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 ReactiveClusterTemplate clusterTemplate;
@Nullable private final Class<?> boundClass;
private final IndexCoordinates boundIndexCoordinates;
public ReactiveIndicesTemplate(ReactiveElasticsearchIndicesClient client, ReactiveClusterTemplate clusterTemplate,
public ReactiveIndicesTemplate(ReactiveElasticsearchIndicesClient client,
ElasticsearchConverter elasticsearchConverter, IndexCoordinates index) {
super(client, elasticsearchConverter);
Assert.notNull(index, "index must not be null");
Assert.notNull(clusterTemplate, "clusterTemplate must not be null");
this.clusterTemplate = clusterTemplate;
this.boundClass = null;
this.boundIndexCoordinates = index;
}
public ReactiveIndicesTemplate(ReactiveElasticsearchIndicesClient client, ReactiveClusterTemplate clusterTemplate,
public ReactiveIndicesTemplate(ReactiveElasticsearchIndicesClient client,
ElasticsearchConverter elasticsearchConverter, Class<?> clazz) {
super(client, elasticsearchConverter);
Assert.notNull(clazz, "clazz must not be null");
Assert.notNull(clusterTemplate, "clusterTemplate must not be null");
this.clusterTemplate = clusterTemplate;
this.boundClass = clazz;
this.boundIndexCoordinates = getIndexCoordinatesFor(clazz);
}
@@ -279,99 +271,6 @@ public class ReactiveIndicesTemplate
return putTemplateResponse.map(PutTemplateResponse::acknowledged);
}
@Override
public Mono<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 Mono.from(clusterTemplate.execute(client -> client.putComponentTemplate(putComponentTemplateRequestES)))
.map(AcknowledgedResponseBase::acknowledged);
}
@Override
public Flux<TemplateResponse> getComponentTemplate(GetComponentTemplateRequest getComponentTemplateRequest) {
Assert.notNull(getComponentTemplateRequest, "getComponentTemplateRequest must not be null");
co.elastic.clients.elasticsearch.cluster.GetComponentTemplateRequest getComponentTemplateRequestES = requestConverter
.clusterGetComponentTemplateRequest(getComponentTemplateRequest);
return Flux.from(clusterTemplate.execute(client -> client.getComponentTemplate(getComponentTemplateRequestES)))
.flatMapIterable(responseConverter::clusterGetComponentTemplates);
}
@Override
public Mono<Boolean> existsComponentTemplate(ExistsComponentTemplateRequest existsComponentTemplateRequest) {
Assert.notNull(existsComponentTemplateRequest, "existsComponentTemplateRequest must not be null");
co.elastic.clients.elasticsearch.cluster.ExistsComponentTemplateRequest existsComponentTemplateRequestES = requestConverter
.clusterExistsComponentTemplateRequest(existsComponentTemplateRequest);
return Mono
.from(clusterTemplate.execute(client -> client.existsComponentTemplate(existsComponentTemplateRequestES)))
.map(BooleanResponse::value);
}
@Override
public Mono<Boolean> deleteComponentTemplate(DeleteComponentTemplateRequest deleteComponentTemplateRequest) {
Assert.notNull(deleteComponentTemplateRequest, "deleteComponentTemplateRequest must not be null");
co.elastic.clients.elasticsearch.cluster.DeleteComponentTemplateRequest deleteComponentTemplateRequestES = requestConverter
.clusterDeleteComponentTemplateRequest(deleteComponentTemplateRequest);
return Mono
.from(clusterTemplate.execute(client -> client.deleteComponentTemplate(deleteComponentTemplateRequestES)))
.map(AcknowledgedResponseBase::acknowledged);
}
@Override
public Mono<Boolean> putIndexTemplate(PutIndexTemplateRequest putIndexTemplateRequest) {
Assert.notNull(putIndexTemplateRequest, "putIndexTemplateRequest must not be null");
co.elastic.clients.elasticsearch.indices.PutIndexTemplateRequest putIndexTemplateRequestES = requestConverter
.indicesPutIndexTemplateRequest(putIndexTemplateRequest);
return Mono.from(execute(client -> client.putIndexTemplate(putIndexTemplateRequestES)))
.map(PutIndexTemplateResponse::acknowledged);
}
@Override
public Mono<Boolean> existsIndexTemplate(ExistsIndexTemplateRequest existsIndexTemplateRequest) {
Assert.notNull(existsIndexTemplateRequest, "existsIndexTemplateRequest must not be null");
co.elastic.clients.elasticsearch.indices.ExistsIndexTemplateRequest existsIndexTemplateRequestES = requestConverter
.indicesExistsIndexTemplateRequest(existsIndexTemplateRequest);
return Mono.from(execute(client -> client.existsIndexTemplate(existsIndexTemplateRequestES)))
.map(BooleanResponse::value);
}
@Override
public Flux<TemplateResponse> getIndexTemplate(GetIndexTemplateRequest getIndexTemplateRequest) {
Assert.notNull(getIndexTemplateRequest, "getIndexTemplateRequest must not be null");
co.elastic.clients.elasticsearch.indices.GetIndexTemplateRequest getIndexTemplateRequestES = requestConverter
.indicesGetIndexTemplateRequest(getIndexTemplateRequest);
return Mono.from(execute(client -> client.getIndexTemplate(getIndexTemplateRequestES)))
.flatMapIterable(responseConverter::getIndexTemplates);
}
@Override
public Mono<Boolean> deleteIndexTemplate(DeleteIndexTemplateRequest deleteIndexTemplateRequest) {
Assert.notNull(deleteIndexTemplateRequest, "deleteIndexTemplateRequest must not be null");
co.elastic.clients.elasticsearch.indices.DeleteIndexTemplateRequest deleteIndexTemplateRequestES = requestConverter
.indicesDeleteIndexTemplateRequest(deleteIndexTemplateRequest);
return Mono.from(execute(client -> client.deleteIndexTemplate(deleteIndexTemplateRequestES)))
.map(AcknowledgedResponseBase::acknowledged);
}
@Override
public Mono<TemplateData> getTemplate(GetTemplateRequest getTemplateRequest) {
@@ -15,8 +15,12 @@
*/
package org.springframework.data.elasticsearch.client.elc;
import static org.springframework.data.elasticsearch.client.elc.TypeUtils.*;
import static org.springframework.util.CollectionUtils.*;
import static org.springframework.data.elasticsearch.client.elc.TypeUtils.searchType;
import static org.springframework.data.elasticsearch.client.elc.TypeUtils.slices;
import static org.springframework.data.elasticsearch.client.elc.TypeUtils.time;
import static org.springframework.data.elasticsearch.client.elc.TypeUtils.timeStringMs;
import static org.springframework.data.elasticsearch.client.elc.TypeUtils.toFloat;
import static org.springframework.util.CollectionUtils.isEmpty;
import co.elastic.clients.elasticsearch._types.Conflicts;
import co.elastic.clients.elasticsearch._types.FieldValue;
@@ -27,16 +31,24 @@ import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.VersionType;
import co.elastic.clients.elasticsearch._types.WaitForActiveShardOptions;
import co.elastic.clients.elasticsearch._types.mapping.FieldType;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch._types.mapping.RuntimeField;
import co.elastic.clients.elasticsearch._types.mapping.RuntimeFieldType;
import co.elastic.clients.elasticsearch._types.query_dsl.FieldAndFormat;
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
import co.elastic.clients.elasticsearch._types.query_dsl.Like;
import co.elastic.clients.elasticsearch.cluster.DeleteComponentTemplateRequest;
import co.elastic.clients.elasticsearch.cluster.ExistsComponentTemplateRequest;
import co.elastic.clients.elasticsearch.cluster.GetComponentTemplateRequest;
import co.elastic.clients.elasticsearch.cluster.HealthRequest;
import co.elastic.clients.elasticsearch.cluster.PutComponentTemplateRequest;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.BulkRequest;
import co.elastic.clients.elasticsearch.core.ClosePointInTimeRequest;
import co.elastic.clients.elasticsearch.core.DeleteByQueryRequest;
import co.elastic.clients.elasticsearch.core.DeleteRequest;
import co.elastic.clients.elasticsearch.core.GetRequest;
import co.elastic.clients.elasticsearch.core.IndexRequest;
import co.elastic.clients.elasticsearch.core.MgetRequest;
import co.elastic.clients.elasticsearch.core.MsearchRequest;
import co.elastic.clients.elasticsearch.core.OpenPointInTimeRequest;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.UpdateByQueryRequest;
import co.elastic.clients.elasticsearch.core.UpdateRequest;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
import co.elastic.clients.elasticsearch.core.bulk.CreateOperation;
import co.elastic.clients.elasticsearch.core.bulk.IndexOperation;
@@ -46,16 +58,26 @@ import co.elastic.clients.elasticsearch.core.msearch.MultisearchBody;
import co.elastic.clients.elasticsearch.core.search.Highlight;
import co.elastic.clients.elasticsearch.core.search.Rescore;
import co.elastic.clients.elasticsearch.core.search.SourceConfig;
import co.elastic.clients.elasticsearch.indices.*;
import co.elastic.clients.elasticsearch.indices.ExistsIndexTemplateRequest;
import co.elastic.clients.elasticsearch.indices.CreateIndexRequest;
import co.elastic.clients.elasticsearch.indices.DeleteIndexRequest;
import co.elastic.clients.elasticsearch.indices.ExistsRequest;
import co.elastic.clients.elasticsearch.indices.GetAliasRequest;
import co.elastic.clients.elasticsearch.indices.GetIndexRequest;
import co.elastic.clients.elasticsearch.indices.GetIndicesSettingsRequest;
import co.elastic.clients.elasticsearch.indices.GetMappingRequest;
import co.elastic.clients.elasticsearch.indices.IndexSettings;
import co.elastic.clients.elasticsearch.indices.PutMappingRequest;
import co.elastic.clients.elasticsearch.indices.RefreshRequest;
import co.elastic.clients.elasticsearch.indices.UpdateAliasesRequest;
import co.elastic.clients.elasticsearch.indices.update_aliases.Action;
import co.elastic.clients.json.JsonData;
import co.elastic.clients.json.JsonpDeserializer;
import co.elastic.clients.json.JsonpMapper;
import jakarta.json.stream.JsonGenerator;
import jakarta.json.stream.JsonParser;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
@@ -75,25 +97,34 @@ import org.springframework.data.elasticsearch.core.RefreshPolicy;
import org.springframework.data.elasticsearch.core.ScriptType;
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.AliasAction;
import org.springframework.data.elasticsearch.core.index.AliasActionParameters;
import org.springframework.data.elasticsearch.core.index.AliasActions;
import org.springframework.data.elasticsearch.core.index.DeleteTemplateRequest;
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.PutTemplateRequest;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.data.elasticsearch.core.query.BaseQuery;
import org.springframework.data.elasticsearch.core.query.BulkOptions;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.elasticsearch.core.query.GeoDistanceOrder;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery;
import org.springframework.data.elasticsearch.core.query.Order;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.query.RescorerQuery;
import org.springframework.data.elasticsearch.core.query.ScriptData;
import org.springframework.data.elasticsearch.core.query.SourceFilter;
import org.springframework.data.elasticsearch.core.query.StringQuery;
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
import org.springframework.data.elasticsearch.core.reindex.ReindexRequest;
import org.springframework.data.elasticsearch.core.reindex.Remote;
import org.springframework.data.elasticsearch.core.script.Script;
import org.springframework.data.elasticsearch.support.DefaultStringObjectMap;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
@@ -105,7 +136,6 @@ import org.springframework.util.StringUtils;
* @author scoobyzhang
* @since 4.4
*/
@SuppressWarnings("ClassCanBeRecord")
class RequestConverter {
// the default max result window size of Elasticsearch
@@ -123,101 +153,9 @@ class RequestConverter {
}
// region Cluster client
public co.elastic.clients.elasticsearch.cluster.HealthRequest clusterHealthRequest() {
public HealthRequest clusterHealthRequest() {
return new HealthRequest.Builder().build();
}
public co.elastic.clients.elasticsearch.cluster.PutComponentTemplateRequest clusterPutComponentTemplateRequest(
org.springframework.data.elasticsearch.core.index.PutComponentTemplateRequest putComponentTemplateRequest) {
Assert.notNull(putComponentTemplateRequest, "putComponentTemplateRequest must not be null");
return PutComponentTemplateRequest.of(b -> b //
.name(putComponentTemplateRequest.name()) //
.create(putComponentTemplateRequest.create()) //
.version(putComponentTemplateRequest.version()) //
.masterTimeout(time(putComponentTemplateRequest.masterTimeout())) //
.template(isb -> {
var componentTemplateData = putComponentTemplateRequest.template();
isb //
.mappings(typeMapping(componentTemplateData.mapping())) //
.settings(indexSettings(componentTemplateData.settings()));
// same code schema, but different Elasticsearch builder types
// noinspection DuplicatedCode
var aliasActions = componentTemplateData.aliasActions();
if (aliasActions != null) {
aliasActions.getActions().forEach(aliasAction -> {
if (aliasAction instanceof AliasAction.Add add) {
var parameters = add.getParameters();
// noinspection DuplicatedCode
String[] parametersAliases = parameters.getAliases();
if (parametersAliases != null) {
for (String aliasName : parametersAliases) {
isb.aliases(aliasName, aliasBuilder -> buildAlias(parameters, aliasBuilder));
}
}
}
});
}
return isb;
}));
}
private Alias.Builder buildAlias(AliasActionParameters parameters, Alias.Builder aliasBuilder) {
// noinspection DuplicatedCode
if (parameters.getRouting() != null) {
aliasBuilder.routing(parameters.getRouting());
}
if (parameters.getIndexRouting() != null) {
aliasBuilder.indexRouting(parameters.getIndexRouting());
}
if (parameters.getSearchRouting() != null) {
aliasBuilder.searchRouting(parameters.getSearchRouting());
}
if (parameters.getHidden() != null) {
aliasBuilder.isHidden(parameters.getHidden());
}
if (parameters.getWriteIndex() != null) {
aliasBuilder.isWriteIndex(parameters.getWriteIndex());
}
Query filterQuery = parameters.getFilterQuery();
if (filterQuery != null) {
co.elastic.clients.elasticsearch._types.query_dsl.Query esQuery = getQuery(filterQuery, null);
if (esQuery != null) {
aliasBuilder.filter(esQuery);
}
}
return aliasBuilder;
}
public ExistsComponentTemplateRequest clusterExistsComponentTemplateRequest(
org.springframework.data.elasticsearch.core.index.ExistsComponentTemplateRequest existsComponentTemplateRequest) {
Assert.notNull(existsComponentTemplateRequest, "existsComponentTemplateRequest must not be null");
return ExistsComponentTemplateRequest.of(b -> b.name(existsComponentTemplateRequest.templateName()));
}
public GetComponentTemplateRequest clusterGetComponentTemplateRequest(
org.springframework.data.elasticsearch.core.index.GetComponentTemplateRequest getComponentTemplateRequest) {
Assert.notNull(getComponentTemplateRequest, "getComponentTemplateRequest must not be null");
return GetComponentTemplateRequest.of(b -> b.name(getComponentTemplateRequest.templateName()));
}
public DeleteComponentTemplateRequest clusterDeleteComponentTemplateRequest(
org.springframework.data.elasticsearch.core.index.DeleteComponentTemplateRequest deleteComponentTemplateRequest) {
return DeleteComponentTemplateRequest.of(b -> b.name(deleteComponentTemplateRequest.templateName()));
}
// endregion
// region Indices client
@@ -234,12 +172,20 @@ class RequestConverter {
Assert.notNull(indexCoordinates, "indexCoordinates must not be null");
Assert.notNull(settings, "settings must not be null");
CreateIndexRequest.Builder createRequestBuilder = new CreateIndexRequest.Builder();
createRequestBuilder.index(indexCoordinates.getIndexName());
// note: the new client does not support the index.storeType anymore
return new CreateIndexRequest.Builder() //
.index(indexCoordinates.getIndexName()) //
.settings(indexSettings(settings)) //
.mappings(typeMapping(mapping)) //
.build();
createRequestBuilder.settings(IndexSettings.of(b -> b //
.withJson(new StringReader(Document.from(settings).toJson()))));
if (mapping != null) {
createRequestBuilder.mappings(TypeMapping.of(b -> b //
.withJson(new StringReader(mapping.toJson()))));
}
return createRequestBuilder.build();
}
public RefreshRequest indicesRefreshRequest(IndexCoordinates indexCoordinates) {
@@ -340,7 +286,18 @@ class RequestConverter {
Assert.notNull(indexCoordinates, "indexCoordinates must not be null");
return new GetMappingRequest.Builder().index(List.of(indexCoordinates.getIndexNames())).build();
return new GetMappingRequest.Builder().index(Arrays.asList(indexCoordinates.getIndexNames())).build();
}
private Property getProperty(Object value) {
// noinspection SpellCheckingInspection
ByteArrayOutputStream baos = new ByteArrayOutputStream();
JsonGenerator generator = jsonpMapper.jsonProvider().createGenerator(baos);
jsonpMapper.serialize(value, generator);
generator.close();
// noinspection SpellCheckingInspection
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
return fromJson(bais, Property._DESERIALIZER);
}
public GetIndicesSettingsRequest indicesGetSettingsRequest(IndexCoordinates indexCoordinates,
@@ -397,7 +354,7 @@ class RequestConverter {
}
if (putTemplateRequest.getMappings() != null) {
builder.mappings(typeMapping(putTemplateRequest.getMappings()));
builder.mappings(fromJson(putTemplateRequest.getMappings().toJson(), TypeMapping._DESERIALIZER));
}
if (putTemplateRequest.getVersion() != null) {
@@ -408,14 +365,43 @@ class RequestConverter {
if (aliasActions != null) {
aliasActions.getActions().forEach(aliasAction -> {
AliasActionParameters parameters = aliasAction.getParameters();
// noinspection DuplicatedCode
String[] parametersAliases = parameters.getAliases();
if (parametersAliases != null) {
for (String aliasName : parametersAliases) {
builder.aliases(aliasName, aliasBuilder -> {
return buildAlias(parameters, aliasBuilder);
// noinspection DuplicatedCode
if (parameters.getRouting() != null) {
aliasBuilder.routing(parameters.getRouting());
}
if (parameters.getIndexRouting() != null) {
aliasBuilder.indexRouting(parameters.getIndexRouting());
}
if (parameters.getSearchRouting() != null) {
aliasBuilder.searchRouting(parameters.getSearchRouting());
}
if (parameters.getHidden() != null) {
aliasBuilder.isHidden(parameters.getHidden());
}
if (parameters.getWriteIndex() != null) {
aliasBuilder.isWriteIndex(parameters.getWriteIndex());
}
Query filterQuery = parameters.getFilterQuery();
if (filterQuery != null) {
co.elastic.clients.elasticsearch._types.query_dsl.Query esQuery = getQuery(filterQuery, null);
if (esQuery != null) {
aliasBuilder.filter(esQuery);
}
}
return aliasBuilder;
});
}
}
@@ -425,55 +411,6 @@ class RequestConverter {
return builder.build();
}
public co.elastic.clients.elasticsearch.indices.PutIndexTemplateRequest indicesPutIndexTemplateRequest(
PutIndexTemplateRequest putIndexTemplateRequest) {
Assert.notNull(putIndexTemplateRequest, "putIndexTemplateRequest must not be null");
var builder = new co.elastic.clients.elasticsearch.indices.PutIndexTemplateRequest.Builder()
.name(putIndexTemplateRequest.name()) //
.indexPatterns(Arrays.asList(putIndexTemplateRequest.indexPatterns())) //
.template(t -> {
t //
.settings(indexSettings(putIndexTemplateRequest.settings())) //
.mappings(typeMapping(putIndexTemplateRequest.mapping()));
// same code schema, but different Elasticsearch builder types
// noinspection DuplicatedCode
var aliasActions = putIndexTemplateRequest.aliasActions();
if (aliasActions != null) {
aliasActions.getActions().forEach(aliasAction -> {
if (aliasAction instanceof AliasAction.Add add) {
var parameters = add.getParameters();
// noinspection DuplicatedCode
String[] parametersAliases = parameters.getAliases();
if (parametersAliases != null) {
for (String aliasName : parametersAliases) {
t.aliases(aliasName, aliasBuilder -> buildAlias(parameters, aliasBuilder));
}
}
}
});
}
return t;
});
if (!putIndexTemplateRequest.composedOf().isEmpty()) {
builder.composedOf(putIndexTemplateRequest.composedOf());
}
return builder.build();
}
public ExistsIndexTemplateRequest indicesExistsIndexTemplateRequest(
org.springframework.data.elasticsearch.core.index.ExistsIndexTemplateRequest existsIndexTemplateRequest) {
Assert.notNull(existsIndexTemplateRequest, "existsIndexTemplateRequest must not be null");
return co.elastic.clients.elasticsearch.indices.ExistsIndexTemplateRequest
.of(b -> b.name(existsIndexTemplateRequest.templateName()));
}
public co.elastic.clients.elasticsearch.indices.ExistsTemplateRequest indicesExistsTemplateRequest(
ExistsTemplateRequest existsTemplateRequest) {
@@ -483,24 +420,6 @@ class RequestConverter {
.of(etr -> etr.name(existsTemplateRequest.getTemplateName()));
}
public co.elastic.clients.elasticsearch.indices.GetIndexTemplateRequest indicesGetIndexTemplateRequest(
GetIndexTemplateRequest getIndexTemplateRequest) {
Assert.notNull(getIndexTemplateRequest, "getIndexTemplateRequest must not be null");
return co.elastic.clients.elasticsearch.indices.GetIndexTemplateRequest
.of(gitr -> gitr.name(getIndexTemplateRequest.templateName()));
}
public co.elastic.clients.elasticsearch.indices.DeleteIndexTemplateRequest indicesDeleteIndexTemplateRequest(
DeleteIndexTemplateRequest deleteIndexTemplateRequest) {
Assert.notNull(deleteIndexTemplateRequest, "deleteIndexTemplateRequest must not be null");
return co.elastic.clients.elasticsearch.indices.DeleteIndexTemplateRequest
.of(ditr -> ditr.name(deleteIndexTemplateRequest.templateName()));
}
public co.elastic.clients.elasticsearch.indices.DeleteTemplateRequest indicesDeleteTemplateRequest(
DeleteTemplateRequest existsTemplateRequest) {
@@ -572,7 +491,7 @@ class RequestConverter {
}
}
builder.refresh(refresh(refreshPolicy));
builder.refresh(TypeUtils.refresh(refreshPolicy));
return builder.build();
}
@@ -739,9 +658,9 @@ class RequestConverter {
builder.timeout(tb -> tb.time(Long.valueOf(bulkOptions.getTimeout().toMillis()).toString() + "ms"));
}
builder.refresh(refresh(refreshPolicy));
builder.refresh(TypeUtils.refresh(refreshPolicy));
if (bulkOptions.getRefreshPolicy() != null) {
builder.refresh(refresh(bulkOptions.getRefreshPolicy()));
builder.refresh(TypeUtils.refresh(bulkOptions.getRefreshPolicy()));
}
if (bulkOptions.getWaitForActiveShards() != null) {
@@ -884,13 +803,13 @@ class RequestConverter {
ReindexRequest.Dest dest = reindexRequest.getDest();
return d //
.index(dest.getIndex().getIndexName()) //
.versionType(versionType(dest.getVersionType())) //
.opType(opType(dest.getOpType()));
.versionType(TypeUtils.versionType(dest.getVersionType())) //
.opType(TypeUtils.opType(dest.getOpType()));
} //
);
if (reindexRequest.getConflicts() != null) {
builder.conflicts(conflicts(reindexRequest.getConflicts()));
builder.conflicts(TypeUtils.conflicts(reindexRequest.getConflicts()));
}
ReindexRequest.Script script = reindexRequest.getScript();
@@ -903,7 +822,7 @@ class RequestConverter {
if (reindexRequest.getWaitForActiveShards() != null) {
builder.waitForActiveShards(wfas -> wfas //
.count(waitForActiveShardsCount(reindexRequest.getWaitForActiveShards())));
.count(TypeUtils.waitForActiveShardsCount(reindexRequest.getWaitForActiveShards())));
}
builder //
@@ -928,13 +847,13 @@ class RequestConverter {
if (routing != null) {
r.routing(routing);
}
r.refresh(refresh(refreshPolicy));
r.refresh(TypeUtils.refresh(refreshPolicy));
return r;
});
}
public DeleteByQueryRequest documentDeleteByQueryRequest(Query query, @Nullable String routing, Class<?> clazz,
IndexCoordinates index, @Nullable RefreshPolicy refreshPolicy) {
public DeleteByQueryRequest documentDeleteByQueryRequest(Query query, Class<?> clazz, IndexCoordinates index,
@Nullable RefreshPolicy refreshPolicy) {
Assert.notNull(query, "query must not be null");
Assert.notNull(index, "index must not be null");
@@ -953,8 +872,6 @@ class RequestConverter {
if (query.getRoute() != null) {
b.routing(query.getRoute());
} else if (StringUtils.hasText(routing)) {
b.routing(routing);
}
return b;
@@ -1001,7 +918,7 @@ class RequestConverter {
.docAsUpsert(query.getDocAsUpsert()) //
.ifSeqNo(query.getIfSeqNo() != null ? Long.valueOf(query.getIfSeqNo()) : null) //
.ifPrimaryTerm(query.getIfPrimaryTerm() != null ? Long.valueOf(query.getIfPrimaryTerm()) : null) //
.refresh(refresh(refreshPolicy)) //
.refresh(TypeUtils.refresh(refreshPolicy)) //
.retryOnConflict(query.getRetryOnConflict()) //
;
@@ -1085,7 +1002,7 @@ class RequestConverter {
}
if (updateQuery.getWaitForActiveShards() != null) {
ub.waitForActiveShards(w -> w.count(waitForActiveShardsCount(updateQuery.getWaitForActiveShards())));
ub.waitForActiveShards(w -> w.count(TypeUtils.waitForActiveShardsCount(updateQuery.getWaitForActiveShards())));
}
return ub;
@@ -1096,24 +1013,19 @@ class RequestConverter {
// region search
public <T> SearchRequest searchRequest(Query query, @Nullable String routing, @Nullable Class<T> clazz,
IndexCoordinates indexCoordinates, boolean forCount) {
return searchRequest(query, routing, clazz, indexCoordinates, forCount, false, null);
public <T> SearchRequest searchRequest(Query query, @Nullable Class<T> clazz, IndexCoordinates indexCoordinates,
boolean forCount, long scrollTimeInMillis) {
return searchRequest(query, clazz, indexCoordinates, forCount, true, scrollTimeInMillis);
}
public <T> SearchRequest searchRequest(Query query, @Nullable String routing, @Nullable Class<T> clazz,
IndexCoordinates indexCoordinates, boolean forCount, long scrollTimeInMillis) {
return searchRequest(query, routing, clazz, indexCoordinates, forCount, true, scrollTimeInMillis);
public <T> SearchRequest searchRequest(Query query, @Nullable Class<T> clazz, IndexCoordinates indexCoordinates,
boolean forCount, boolean useScroll) {
return searchRequest(query, clazz, indexCoordinates, forCount, useScroll, null);
}
public <T> SearchRequest searchRequest(Query query, @Nullable String routing, @Nullable Class<T> clazz,
IndexCoordinates indexCoordinates, boolean forCount, boolean forBatchedSearch) {
return searchRequest(query, routing, clazz, indexCoordinates, forCount, forBatchedSearch, null);
}
public <T> SearchRequest searchRequest(Query query, @Nullable String routing, @Nullable Class<T> clazz,
IndexCoordinates indexCoordinates, boolean forCount, boolean forBatchedSearch,
@Nullable Long scrollTimeInMillis) {
public <T> SearchRequest searchRequest(Query query, @Nullable Class<T> clazz, IndexCoordinates indexCoordinates,
boolean forCount, boolean useScroll, @Nullable Long scrollTimeInMillis) {
String[] indexNames = indexCoordinates.getIndexNames();
Assert.notNull(query, "query must not be null");
@@ -1121,7 +1033,7 @@ class RequestConverter {
elasticsearchConverter.updateQuery(query, clazz);
SearchRequest.Builder builder = new SearchRequest.Builder();
prepareSearchRequest(query, routing, clazz, indexCoordinates, builder, forCount, forBatchedSearch);
prepareSearchRequest(query, clazz, indexCoordinates, builder, forCount, useScroll);
if (scrollTimeInMillis != null) {
builder.scroll(t -> t.time(scrollTimeInMillis + "ms"));
@@ -1129,20 +1041,13 @@ class RequestConverter {
builder.query(getQuery(query, clazz));
if (StringUtils.hasText(query.getRoute())) {
builder.routing(query.getRoute());
}
if (StringUtils.hasText(routing)) {
builder.routing(routing);
}
addFilter(query, builder);
return builder.build();
}
public MsearchRequest searchMsearchRequest(
List<ElasticsearchTemplate.MultiSearchQueryParameter> multiSearchQueryParameters, @Nullable String routing) {
List<ElasticsearchTemplate.MultiSearchQueryParameter> multiSearchQueryParameters) {
// basically the same stuff as in prepareSearchRequest, but the new Elasticsearch has different builders for a
// normal search and msearch
@@ -1155,16 +1060,11 @@ class RequestConverter {
.header(h -> {
h //
.index(Arrays.asList(param.index().getIndexNames())) //
.routing(query.getRoute()) //
.searchType(searchType(query.getSearchType())) //
.requestCache(query.getRequestCache()) //
;
if (StringUtils.hasText(query.getRoute())) {
h.routing(query.getRoute());
} else if (StringUtils.hasText(routing)) {
h.routing(routing);
}
if (query.getPreference() != null) {
h.preference(query.getPreference());
}
@@ -1246,14 +1146,13 @@ class RequestConverter {
}
if (!isEmpty(query.getIndicesBoost())) {
bb.indicesBoost(query.getIndicesBoost().stream()
.map(indexBoost -> Map.of(indexBoost.getIndexName(), Double.valueOf(indexBoost.getBoost())))
.collect(Collectors.toList()));
Map<String, Double> boosts = new LinkedHashMap<>();
query.getIndicesBoost()
.forEach(indexBoost -> boosts.put(indexBoost.getIndexName(), (double) indexBoost.getBoost()));
// noinspection unchecked
bb.indicesBoost(boosts);
}
query.getScriptedFields().forEach(scriptedField -> bb.scriptFields(scriptedField.getFieldName(),
sf -> sf.script(getScript(scriptedField.getScriptData()))));
if (query instanceof NativeQuery) {
prepareNativeSearch((NativeQuery) query, bb);
}
@@ -1268,8 +1167,8 @@ class RequestConverter {
});
}
private <T> void prepareSearchRequest(Query query, @Nullable String routing, @Nullable Class<T> clazz,
IndexCoordinates indexCoordinates, SearchRequest.Builder builder, boolean forCount, boolean forBatchedSearch) {
private <T> void prepareSearchRequest(Query query, @Nullable Class<T> clazz, IndexCoordinates indexCoordinates,
SearchRequest.Builder builder, boolean forCount, boolean useScroll) {
String[] indexNames = indexCoordinates.getIndexNames();
@@ -1279,31 +1178,16 @@ class RequestConverter {
builder //
.version(true) //
.trackScores(query.getTrackScores()) //
.allowNoIndices(query.getAllowNoIndices()) //
.source(getSourceConfig(query)) //
.searchType(searchType(query.getSearchType())) //
.timeout(timeStringMs(query.getTimeout())) //
.requestCache(query.getRequestCache()) //
;
.trackScores(query.getTrackScores());
var pointInTime = query.getPointInTime();
if (pointInTime != null) {
builder.pit(pb -> pb.id(pointInTime.id()).keepAlive(time(pointInTime.keepAlive())));
} else {
builder //
.index(Arrays.asList(indexNames)) //
;
var expandWildcards = query.getExpandWildcards();
if (expandWildcards != null && !expandWildcards.isEmpty()) {
builder.expandWildcards(expandWildcards(expandWildcards));
}
builder.index(Arrays.asList(indexNames));
if (query.getRoute() != null) {
builder.routing(query.getRoute());
} else if (StringUtils.hasText(routing)) {
builder.routing(routing);
}
if (query.getPreference() != null) {
@@ -1323,6 +1207,8 @@ class RequestConverter {
builder.from(0).size(INDEX_MAX_RESULT_WINDOW);
}
builder.source(getSourceConfig(query));
if (!isEmpty(query.getFields())) {
builder.fields(fb -> {
query.getFields().forEach(fb::field);
@@ -1346,6 +1232,8 @@ class RequestConverter {
builder.minScore((double) query.getMinScore());
}
builder.searchType(searchType(query.getSearchType()));
if (query.getSort() != null) {
List<SortOptions> sortOptions = getSortOptions(query.getSort(), persistentEntity);
@@ -1356,9 +1244,6 @@ class RequestConverter {
addHighlight(query, builder);
query.getScriptedFields().forEach(scriptedField -> builder.scriptFields(scriptedField.getFieldName(),
sf -> sf.script(getScript(scriptedField.getScriptData()))));
if (query instanceof NativeQuery) {
prepareNativeSearch((NativeQuery) query, builder);
}
@@ -1371,6 +1256,8 @@ class RequestConverter {
builder.trackTotalHits(th -> th.count(query.getTrackTotalHitsUpTo()));
}
builder.timeout(timeStringMs(query.getTimeout()));
if (query.getExplain()) {
builder.explain(true);
}
@@ -1382,6 +1269,8 @@ class RequestConverter {
query.getRescorerQueries().forEach(rescorerQuery -> builder.rescore(getRescore(rescorerQuery)));
builder.requestCache(query.getRequestCache());
if (!query.getRuntimeFields().isEmpty()) {
Map<String, RuntimeField> runtimeMappings = new HashMap<>();
@@ -1402,23 +1291,21 @@ class RequestConverter {
builder.size(0) //
.trackTotalHits(th -> th.count(Integer.MAX_VALUE)) //
.source(SourceConfig.of(sc -> sc.fetch(false)));
} else if (forBatchedSearch) {
} else if (useScroll) {
// request_cache is not allowed on scroll requests.
builder.requestCache(null);
Duration scrollTimeout = query.getScrollTime() != null ? query.getScrollTime() : Duration.ofMinutes(1);
builder.scroll(time(scrollTimeout));
// limit the number of documents in a batch
builder.size(query.getReactiveBatchSize());
builder.size(500);
}
if (!isEmpty(query.getIndicesBoost())) {
builder.indicesBoost(query.getIndicesBoost().stream()
.map(indexBoost -> Map.of(indexBoost.getIndexName(), Double.valueOf(indexBoost.getBoost())))
.collect(Collectors.toList()));
}
if (!isEmpty(query.getDocValueFields())) {
builder.docvalueFields(query.getDocValueFields().stream() //
.map(docValueField -> FieldAndFormat.of(b -> b.field(docValueField.field()).format(docValueField.format())))
.toList());
Map<String, Double> boosts = new LinkedHashMap<>();
query.getIndicesBoost()
.forEach(indexBoost -> boosts.put(indexBoost.getIndexName(), (double) indexBoost.getBoost()));
// noinspection unchecked
builder.indicesBoost(boosts);
}
}
@@ -1427,7 +1314,7 @@ class RequestConverter {
return Rescore.of(r -> r //
.query(rq -> rq //
.query(getQuery(rescorerQuery.getQuery(), null)) //
.scoreMode(scoreMode(rescorerQuery.getScoreMode())) //
.scoreMode(TypeUtils.scoreMode(rescorerQuery.getScoreMode())) //
.queryWeight(rescorerQuery.getQueryWeight() != null ? Double.valueOf(rescorerQuery.getQueryWeight()) : 1.0) //
.rescoreQueryWeight(
rescorerQuery.getRescoreQueryWeight() != null ? Double.valueOf(rescorerQuery.getRescoreQueryWeight())
@@ -1486,10 +1373,10 @@ class RequestConverter {
return SortOptions.of(so -> so //
.geoDistance(gd -> gd //
.field(fieldName) //
.location(loc -> loc.latlon(Queries.latLon(geoDistanceOrder.getGeoPoint()))) //
.distanceType(geoDistanceType(geoDistanceOrder.getDistanceType())).mode(sortMode(finalMode)) //
.order(sortOrder(geoDistanceOrder.getDirection())) //
.unit(distanceUnit(geoDistanceOrder.getUnit())) //
.location(loc -> loc.latlon(QueryBuilders.latLon(geoDistanceOrder.getGeoPoint())))//
.distanceType(TypeUtils.geoDistanceType(geoDistanceOrder.getDistanceType()))
.mode(TypeUtils.sortMode(finalMode)) //
.unit(TypeUtils.distanceUnit(geoDistanceOrder.getUnit())) //
.ignoreUnmapped(geoDistanceOrder.getIgnoreUnmapped())));
} else {
String missing = (order.getNullHandling() == Sort.NullHandling.NULLS_FIRST) ? "_first"
@@ -1499,10 +1386,10 @@ class RequestConverter {
.field(f -> {
f.field(fieldName) //
.order(sortOrder) //
.mode(sortMode(finalMode));
.mode(TypeUtils.sortMode(finalMode));
if (finalUnmappedType != null) {
FieldType fieldType = fieldType(finalUnmappedType);
FieldType fieldType = TypeUtils.fieldType(finalUnmappedType);
if (fieldType != null) {
f.unmappedType(fieldType);
@@ -1522,15 +1409,13 @@ class RequestConverter {
@SuppressWarnings("DuplicatedCode")
private void prepareNativeSearch(NativeQuery query, SearchRequest.Builder builder) {
query.getScriptedFields().forEach(scriptedField -> builder.scriptFields(scriptedField.getFieldName(),
sf -> sf.script(getScript(scriptedField.getScriptData()))));
builder //
.suggest(query.getSuggester()) //
.collapse(query.getFieldCollapse()) //
.sort(query.getSortOptions()) //
;
if (query.getKnnQuery() != null) {
builder.knn(query.getKnnQuery());
}
.sort(query.getSortOptions());
if (!isEmpty(query.getAggregations())) {
builder.aggregations(query.getAggregations());
@@ -1544,15 +1429,14 @@ class RequestConverter {
@SuppressWarnings("DuplicatedCode")
private void prepareNativeSearch(NativeQuery query, MultisearchBody.Builder builder) {
query.getScriptedFields().forEach(scriptedField -> builder.scriptFields(scriptedField.getFieldName(),
sf -> sf.script(getScript(scriptedField.getScriptData()))));
builder //
.suggest(query.getSuggester()) //
.collapse(query.getFieldCollapse()) //
.sort(query.getSortOptions());
if (query.getKnnQuery() != null) {
builder.knn(query.getKnnQuery());
}
if (!isEmpty(query.getAggregations())) {
builder.aggregations(query.getAggregations());
}
@@ -1577,13 +1461,11 @@ class RequestConverter {
if (query instanceof CriteriaQuery) {
esQuery = CriteriaQueryProcessor.createQuery(((CriteriaQuery) query).getCriteria());
} else if (query instanceof StringQuery) {
esQuery = Queries.wrapperQueryAsQuery(((StringQuery) query).getSource());
esQuery = QueryBuilders.wrapperQueryAsQuery(((StringQuery) query).getSource());
} else if (query instanceof NativeQuery nativeQuery) {
if (nativeQuery.getQuery() != null) {
esQuery = nativeQuery.getQuery();
} else if (nativeQuery.getSpringDataQuery() != null) {
esQuery = getQuery(nativeQuery.getSpringDataQuery(), clazz);
}
} else {
throw new IllegalArgumentException("unhandled Query implementation " + query.getClass().getName());
@@ -1675,74 +1557,8 @@ class RequestConverter {
return ClosePointInTimeRequest.of(cpit -> cpit.id(pit));
}
public SearchTemplateRequest searchTemplate(SearchTemplateQuery query, @Nullable String routing,
IndexCoordinates index) {
Assert.notNull(query, "query must not be null");
return SearchTemplateRequest.of(builder -> {
builder //
.allowNoIndices(query.getAllowNoIndices()) //
.explain(query.getExplain()) //
.id(query.getId()) //
.index(Arrays.asList(index.getIndexNames())) //
.preference(query.getPreference()) //
.searchType(searchType(query.getSearchType())).source(query.getSource()) //
;
if (query.getRoute() != null) {
builder.routing(query.getRoute());
} else if (StringUtils.hasText(routing)) {
builder.routing(routing);
}
var expandWildcards = query.getExpandWildcards();
if (!expandWildcards.isEmpty()) {
builder.expandWildcards(expandWildcards(expandWildcards));
}
if (query.hasScrollTime()) {
builder.scroll(time(query.getScrollTime()));
}
if (!CollectionUtils.isEmpty(query.getParams())) {
Function<Map.Entry<String, Object>, String> keyMapper = Map.Entry::getKey;
Function<Map.Entry<String, Object>, JsonData> valueMapper = entry -> JsonData.of(entry.getValue(), jsonpMapper);
Map<String, JsonData> params = query.getParams().entrySet().stream()
.collect(Collectors.toMap(keyMapper, valueMapper));
builder.params(params);
}
return builder;
});
}
// endregion
public PutScriptRequest scriptPut(Script script) {
Assert.notNull(script, "script must not be null");
return PutScriptRequest.of(b -> b //
.id(script.id()) //
.script(sb -> sb //
.lang(script.language()) //
.source(script.source())));
}
public GetScriptRequest scriptGet(String name) {
Assert.notNull(name, "name must not be null");
return GetScriptRequest.of(b -> b.id(name));
}
public DeleteScriptRequest scriptDelete(String name) {
Assert.notNull(name, "name must not be null");
return DeleteScriptRequest.of(b -> b.id(name));
}
// region helper functions
public <T> T fromJson(String json, JsonpDeserializer<T> deserializer) {
@@ -15,28 +15,27 @@
*/
package org.springframework.data.elasticsearch.client.elc;
import static org.springframework.data.elasticsearch.client.elc.JsonUtils.toJson;
import static org.springframework.data.elasticsearch.client.elc.TypeUtils.removePrefixFromJson;
import static org.springframework.data.elasticsearch.client.elc.TypeUtils.typeMapping;
import static org.springframework.data.elasticsearch.client.elc.JsonUtils.*;
import co.elastic.clients.elasticsearch._types.BulkIndexByScrollFailure;
import co.elastic.clients.elasticsearch._types.ErrorCause;
import co.elastic.clients.elasticsearch._types.Time;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.cluster.ComponentTemplateSummary;
import co.elastic.clients.elasticsearch.cluster.GetComponentTemplateResponse;
import co.elastic.clients.elasticsearch.cluster.HealthResponse;
import co.elastic.clients.elasticsearch.core.DeleteByQueryResponse;
import co.elastic.clients.elasticsearch.core.GetScriptResponse;
import co.elastic.clients.elasticsearch.core.UpdateByQueryResponse;
import co.elastic.clients.elasticsearch.core.mget.MultiGetError;
import co.elastic.clients.elasticsearch.core.mget.MultiGetResponseItem;
import co.elastic.clients.elasticsearch.indices.*;
import co.elastic.clients.elasticsearch.indices.get_index_template.IndexTemplateItem;
import co.elastic.clients.elasticsearch.indices.get_mapping.IndexMappingRecord;
import co.elastic.clients.json.JsonpMapper;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -47,12 +46,12 @@ import org.springframework.data.elasticsearch.core.IndexInformation;
import org.springframework.data.elasticsearch.core.MultiGetItem;
import org.springframework.data.elasticsearch.core.cluster.ClusterHealth;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.index.*;
import org.springframework.data.elasticsearch.core.index.AliasData;
import org.springframework.data.elasticsearch.core.index.Settings;
import org.springframework.data.elasticsearch.core.index.TemplateData;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.ByQueryResponse;
import org.springframework.data.elasticsearch.core.query.StringQuery;
import org.springframework.data.elasticsearch.core.reindex.ReindexResponse;
import org.springframework.data.elasticsearch.core.script.Script;
import org.springframework.data.elasticsearch.support.DefaultStringObjectMap;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -96,54 +95,6 @@ class ResponseConverter {
.withUnassignedShards(healthResponse.unassignedShards()) //
.build(); //
}
public List<TemplateResponse> clusterGetComponentTemplates(
GetComponentTemplateResponse getComponentTemplateResponse) {
Assert.notNull(getComponentTemplateResponse, "getComponentTemplateResponse must not be null");
var componentTemplates = new ArrayList<TemplateResponse>();
getComponentTemplateResponse.componentTemplates().forEach(componentTemplate -> {
componentTemplates.add(clusterGetComponentTemplate(componentTemplate));
});
return componentTemplates;
}
private TemplateResponse clusterGetComponentTemplate(
co.elastic.clients.elasticsearch.cluster.ComponentTemplate componentTemplate) {
var componentTemplateNode = componentTemplate.componentTemplate();
var componentTemplateSummary = componentTemplateNode.template();
return TemplateResponse.builder() //
.withName(componentTemplate.name()) //
.withVersion(componentTemplateNode.version()) //
.withTemplateData(clusterGetComponentTemplateData(componentTemplateSummary)) //
.build();
}
private TemplateResponseData clusterGetComponentTemplateData(
ComponentTemplateSummary componentTemplateSummary) {
var mapping = typeMapping(componentTemplateSummary.mappings());
var settings = new Settings();
componentTemplateSummary.settings().forEach((key, indexSettings) -> {
settings.put(key, Settings.parse(removePrefixFromJson(indexSettings.toString())));
});
Function<? super Map.Entry<String, AliasDefinition>, String> keyMapper = Map.Entry::getKey;
Function<? super Map.Entry<String, AliasDefinition>, AliasData> valueMapper = entry -> indicesGetAliasData(
entry.getKey(), entry.getValue());
Map<String, AliasData> aliases = componentTemplateSummary.aliases().entrySet().stream()
.collect(Collectors.toMap(keyMapper, valueMapper));
return TemplateResponseData.builder() //
.withMapping(mapping) //
.withSettings(settings) //
.withAliases(aliases) //
.build();
}
// endregion
// region indices client
@@ -239,19 +190,18 @@ class ResponseConverter {
}
private AliasData indicesGetAliasData(String aliasName, Alias alias) {
Query filter = alias.filter();
String filterJson = filter != null ? toJson(filter, jsonpMapper) : null;
var filterQuery = filterJson != null ? StringQuery.builder(filterJson).build() : null;
return AliasData.of(aliasName, filterQuery, alias.indexRouting(), alias.searchRouting(), alias.isWriteIndex(),
Document filterDocument = filterJson != null ? Document.parse(filterJson) : null;
return AliasData.of(aliasName, filterDocument, alias.indexRouting(), alias.searchRouting(), alias.isWriteIndex(),
alias.isHidden());
}
private AliasData indicesGetAliasData(String aliasName, AliasDefinition alias) {
Query filter = alias.filter();
String filterJson = filter != null ? toJson(filter, jsonpMapper) : null;
var filterQuery = filterJson != null ? StringQuery.builder(filterJson).build() : null;
return AliasData.of(aliasName, filterQuery, alias.indexRouting(), alias.searchRouting(), alias.isWriteIndex(),
Document filterDocument = filterJson != null ? Document.parse(filterJson) : null;
return AliasData.of(aliasName, filterDocument, alias.indexRouting(), alias.searchRouting(), alias.isWriteIndex(),
null);
}
@@ -302,59 +252,6 @@ class ResponseConverter {
return null;
}
public List<TemplateResponse> getIndexTemplates(GetIndexTemplateResponse getIndexTemplateResponse) {
Assert.notNull(getIndexTemplateResponse, "getIndexTemplateResponse must not be null");
var componentTemplates = new ArrayList<TemplateResponse>();
getIndexTemplateResponse.indexTemplates().forEach(indexTemplateItem -> {
componentTemplates.add(indexGetComponentTemplate(indexTemplateItem));
});
return componentTemplates;
}
private TemplateResponse indexGetComponentTemplate(IndexTemplateItem indexTemplateItem) {
var indexTemplate = indexTemplateItem.indexTemplate();
var composedOf = indexTemplate.composedOf();
var indexTemplateSummary = indexTemplate.template();
return TemplateResponse.builder() //
.withName(indexTemplateItem.name()) //
.withVersion(indexTemplate.version()) //
.withTemplateData(indexGetComponentTemplateData(indexTemplateSummary, composedOf)) //
.build();
}
private TemplateResponseData indexGetComponentTemplateData(IndexTemplateSummary indexTemplateSummary,
List<String> composedOf) {
var mapping = typeMapping(indexTemplateSummary.mappings());
Function<IndexSettings, Settings> indexSettingsToSettings = indexSettings -> {
if (indexSettings == null) {
return null;
}
Settings parsedSettings = Settings.parse(toJson(indexSettings, jsonpMapper));
return (indexSettings.index() != null) ? parsedSettings : new Settings().append("index", parsedSettings);
};
var settings = indexSettingsToSettings.apply(indexTemplateSummary.settings());
Function<? super Map.Entry<String, Alias>, String> keyMapper = Map.Entry::getKey;
Function<? super Map.Entry<String, Alias>, AliasData> valueMapper = entry -> indicesGetAliasData(entry.getKey(),
entry.getValue());
Map<String, Alias> aliases1 = indexTemplateSummary.aliases();
Map<String, AliasData> aliases = aliases1.entrySet().stream().collect(Collectors.toMap(keyMapper, valueMapper));
return TemplateResponseData.builder() //
.withMapping(mapping) //
.withSettings(settings) //
.withAliases(aliases) //
.withComposedOf(composedOf) //
.build();
}
// endregion
// region document operations
@@ -383,7 +280,7 @@ class ResponseConverter {
.withThrottledMillis(reindexResponse.throttledMillis()) //
.withRequestsPerSecond(reindexResponse.requestsPerSecond()) //
.withThrottledUntilMillis(reindexResponse.throttledUntilMillis()) //
.withFailures(failures) //
.withFailures(failures) //
.build();
}
@@ -513,22 +410,6 @@ class ResponseConverter {
}
// endregion
// region script API
@Nullable
public Script scriptResponse(GetScriptResponse response) {
Assert.notNull(response, "response must not be null");
return response.found() //
? Script.builder() //
.withId(response.id()) //
.withLanguage(response.script().lang()) //
.withSource(response.script().source()).build() //
: null;
}
// endregion
// region helper functions
private long timeToLong(Time time) {
@@ -555,5 +436,6 @@ class ResponseConverter {
return null;
}
}
// endregion
}
@@ -17,7 +17,6 @@ package org.springframework.data.elasticsearch.client.elc;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.SearchTemplateResponse;
import co.elastic.clients.elasticsearch.core.search.CompletionSuggest;
import co.elastic.clients.elasticsearch.core.search.CompletionSuggestOption;
import co.elastic.clients.elasticsearch.core.search.Hit;
@@ -71,7 +70,6 @@ class SearchDocumentResponseBuilder {
Assert.notNull(responseBody, "responseBody must not be null");
Assert.notNull(entityCreator, "entityCreator must not be null");
Assert.notNull(jsonpMapper, "jsonpMapper must not be null");
HitsMetadata<EntityAsMap> hitsMetadata = responseBody.hits();
String scrollId = responseBody.scrollId();
@@ -82,31 +80,6 @@ class SearchDocumentResponseBuilder {
return from(hitsMetadata, scrollId, pointInTimeId, aggregations, suggest, entityCreator, jsonpMapper);
}
/**
* creates a SearchDocumentResponse from the {@link SearchTemplateResponse}
*
* @param response the Elasticsearch response body
* @param entityCreator function to create an entity from a {@link SearchDocument}
* @param jsonpMapper to map JsonData objects
* @return the SearchDocumentResponse
* @since 5.1
*/
public static <T> SearchDocumentResponse from(SearchTemplateResponse<EntityAsMap> response,
SearchDocumentResponse.EntityCreator<T> entityCreator, JsonpMapper jsonpMapper) {
Assert.notNull(response, "response must not be null");
Assert.notNull(entityCreator, "entityCreator must not be null");
Assert.notNull(jsonpMapper, "jsonpMapper must not be null");
var hitsMetadata = response.hits();
var scrollId = response.scrollId();
var aggregations = response.aggregations();
var suggest = response.suggest();
var pointInTimeId = response.pitId();
return from(hitsMetadata, scrollId, pointInTimeId, aggregations, suggest, entityCreator, jsonpMapper);
}
/**
* creates a {@link SearchDocumentResponseBuilder} from {@link HitsMetadata} with the given scrollId aggregations and
* suggestES
@@ -17,22 +17,23 @@ package org.springframework.data.elasticsearch.client.elc;
import co.elastic.clients.elasticsearch._types.*;
import co.elastic.clients.elasticsearch._types.mapping.FieldType;
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
import co.elastic.clients.elasticsearch.core.search.*;
import co.elastic.clients.elasticsearch.indices.IndexSettings;
import co.elastic.clients.elasticsearch.core.search.BoundaryScanner;
import co.elastic.clients.elasticsearch.core.search.HighlighterEncoder;
import co.elastic.clients.elasticsearch.core.search.HighlighterFragmenter;
import co.elastic.clients.elasticsearch.core.search.HighlighterOrder;
import co.elastic.clients.elasticsearch.core.search.HighlighterTagsSchema;
import co.elastic.clients.elasticsearch.core.search.HighlighterType;
import co.elastic.clients.elasticsearch.core.search.ScoreMode;
import java.io.StringReader;
import java.time.Duration;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.RefreshPolicy;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.data.elasticsearch.core.query.IndicesOptions;
import org.springframework.data.elasticsearch.core.query.GeoDistanceOrder;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.Order;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.query.RescorerQuery;
import org.springframework.data.elasticsearch.core.query.UpdateResponse;
import org.springframework.data.elasticsearch.core.reindex.ReindexRequest;
import org.springframework.lang.Nullable;
@@ -125,37 +126,6 @@ final class TypeUtils {
}
}
@Nullable
static Object toObject(@Nullable FieldValue fieldValue) {
if (fieldValue == null) {
return null;
}
switch (fieldValue._kind()) {
case Double -> {
return Double.valueOf(fieldValue.doubleValue());
}
case Long -> {
return Long.valueOf(fieldValue.longValue());
}
case Boolean -> {
return Boolean.valueOf(fieldValue.booleanValue());
}
case String -> {
return fieldValue.stringValue();
}
case Null -> {
return null;
}
case Any -> {
return fieldValue.anyValue().toString();
}
default -> throw new IllegalStateException("Unexpected value: " + fieldValue._kind());
}
}
@Nullable
static GeoDistanceType geoDistanceType(GeoDistanceOrder.DistanceType distanceType) {
@@ -166,20 +136,6 @@ final class TypeUtils {
}
@Nullable
static SortOrder sortOrder(@Nullable Sort.Direction direction) {
if (direction == null) {
return null;
}
return switch (direction) {
case ASC -> SortOrder.Asc;
case DESC -> SortOrder.Desc;
};
}
@Nullable
static HighlighterFragmenter highlighterFragmenter(@Nullable String value) {
@@ -405,37 +361,4 @@ final class TypeUtils {
static Float toFloat(@Nullable Long value) {
return value != null ? Float.valueOf(value) : null;
}
/**
* @sice 5.1
*/
@Nullable
public static List<ExpandWildcard> expandWildcards(@Nullable EnumSet<IndicesOptions.WildcardStates> wildcardStates) {
return (wildcardStates != null && !wildcardStates.isEmpty()) ? wildcardStates.stream()
.map(wildcardState -> ExpandWildcard.valueOf(wildcardState.name().toLowerCase())).collect(Collectors.toList())
: null;
}
@Nullable
static TypeMapping typeMapping(@Nullable Document mapping) {
if (mapping != null) {
return TypeMapping.of(b -> b.withJson(new StringReader(mapping.toJson())));
}
return null;
}
@Nullable
static Document typeMapping(@Nullable TypeMapping typeMapping) {
return (typeMapping != null) ? Document.parse(removePrefixFromJson(typeMapping.toString())) : null;
}
public static String removePrefixFromJson(String jsonWithPrefix) {
return jsonWithPrefix.substring(jsonWithPrefix.indexOf("{"));
}
@Nullable
static IndexSettings indexSettings(@Nullable Map<String, Object> settings) {
return settings != null ? IndexSettings.of(b -> b.withJson(new StringReader(Document.from(settings).toJson())))
: null;
}
}
@@ -25,7 +25,7 @@ import org.springframework.lang.Nullable;
/**
* @author Peter-Josef Meisch
* @since 5.1
* @since 5.0.1
*/
public class ElasticsearchClientRuntimeHints implements RuntimeHintsRegistrar {
@@ -44,7 +44,6 @@ import org.springframework.util.Assert;
* @author Rasmus Faber-Espensen
* @author James Bodkin
* @author Peter-Josef Meisch
* @author Ezequiel Antúnez Camacho
* @deprecated since 5.0
*/
@Deprecated
@@ -249,9 +248,6 @@ class CriteriaQueryProcessor {
}
}
break;
case REGEXP:
query = regexpQuery(fieldName, value.toString());
break;
}
return query;
}
@@ -20,7 +20,6 @@ import reactor.core.publisher.Mono;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
import org.springframework.data.elasticsearch.core.cluster.ClusterHealth;
import org.springframework.data.elasticsearch.core.cluster.ReactiveClusterOperations;
/**
* Default implementation of {@link ReactiveClusterOperations} using the {@link ReactiveElasticsearchOperations}.
@@ -112,7 +112,6 @@ import org.springframework.util.Assert;
* @author Massimiliano Poggi
* @author Farid Faoudi
* @author Sijia Liu
* @author Hamid Rahimi
* @since 4.4
* @deprecated since 5.0
*/
@@ -195,12 +194,8 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
Object queryObject = query.getObject();
if (queryObject != null) {
query.setObject(updateIndexedObject(queryObject, new IndexedObjectInformation( //
indexResponse.getId(), //
indexResponse.getIndex(), //
indexResponse.getSeqNo(), //
indexResponse.getPrimaryTerm(), //
indexResponse.getVersion())));
query.setObject(updateIndexedObject(queryObject, IndexedObjectInformation.of(indexResponse.getId(),
indexResponse.getSeqNo(), indexResponse.getPrimaryTerm(), indexResponse.getVersion())));
}
return indexResponse.getId();
@@ -261,8 +256,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
@Override
public ByQueryResponse delete(Query query, Class<?> clazz, IndexCoordinates index) {
DeleteByQueryRequest deleteByQueryRequest = requestFactory.deleteByQueryRequest(query, routingResolver.getRouting(),
clazz, index);
DeleteByQueryRequest deleteByQueryRequest = requestFactory.deleteByQueryRequest(query, clazz, index);
return ResponseConverter
.byQueryResponseOf(execute(client -> client.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT)));
}
@@ -375,14 +369,10 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
return Stream.of(bulkResponse.getItems()).map(bulkItemResponse -> {
DocWriteResponse response = bulkItemResponse.getResponse();
if (response != null) {
return new IndexedObjectInformation( //
response.getId(), //
response.getIndex(), //
response.getSeqNo(), //
response.getPrimaryTerm(), //
return IndexedObjectInformation.of(response.getId(), response.getSeqNo(), response.getPrimaryTerm(),
response.getVersion());
} else {
return new IndexedObjectInformation(bulkItemResponse.getId(), bulkItemResponse.getIndex(), null, null, null);
return IndexedObjectInformation.of(bulkItemResponse.getId(), null, null, null);
}
}).collect(Collectors.toList());
@@ -399,7 +389,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
final Boolean trackTotalHits = query.getTrackTotalHits();
query.setTrackTotalHits(true);
SearchRequest searchRequest = requestFactory.searchRequest(query, routingResolver.getRouting(), clazz, index);
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
query.setTrackTotalHits(trackTotalHits);
searchRequest.source().size(0);
@@ -410,7 +400,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
@Override
public <T> SearchHits<T> search(Query query, Class<T> clazz, IndexCoordinates index) {
SearchRequest searchRequest = requestFactory.searchRequest(query, routingResolver.getRouting(), clazz, index);
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
SearchResponse response = execute(client -> client.search(searchRequest, RequestOptions.DEFAULT));
ReadDocumentCallback<T> documentCallback = new ReadDocumentCallback<>(elasticsearchConverter, clazz, index);
@@ -432,7 +422,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
Assert.notNull(query.getPageable(), "pageable of query must not be null.");
SearchRequest searchRequest = requestFactory.searchRequest(query, routingResolver.getRouting(), clazz, index);
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
searchRequest.scroll(TimeValue.timeValueMillis(scrollTimeInMillis));
SearchResponse response = execute(client -> client.search(searchRequest, RequestOptions.DEFAULT));
@@ -478,7 +468,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
public <T> List<SearchHits<T>> multiSearch(List<? extends Query> queries, Class<T> clazz, IndexCoordinates index) {
MultiSearchRequest request = new MultiSearchRequest();
for (Query query : queries) {
request.add(requestFactory.searchRequest(query, routingResolver.getRouting(), clazz, index));
request.add(requestFactory.searchRequest(query, clazz, index));
}
MultiSearchResponse.Item[] items = getMultiSearchResult(request);
@@ -505,8 +495,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
Iterator<Class<?>> it = classes.iterator();
for (Query query : queries) {
Class<?> clazz = it.next();
request
.add(requestFactory.searchRequest(query, routingResolver.getRouting(), clazz, getIndexCoordinatesFor(clazz)));
request.add(requestFactory.searchRequest(query, clazz, getIndexCoordinatesFor(clazz)));
}
MultiSearchResponse.Item[] items = getMultiSearchResult(request);
@@ -540,7 +529,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
MultiSearchRequest request = new MultiSearchRequest();
Iterator<Class<?>> it = classes.iterator();
for (Query query : queries) {
request.add(requestFactory.searchRequest(query, routingResolver.getRouting(), it.next(), index));
request.add(requestFactory.searchRequest(query, it.next(), index));
}
MultiSearchResponse.Item[] items = getMultiSearchResult(request);
@@ -560,42 +549,6 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
return res;
}
@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");
MultiSearchRequest request = new MultiSearchRequest();
Iterator<Class<?>> it = classes.iterator();
Iterator<IndexCoordinates> indexesIt = indexes.iterator();
for (Query query : queries) {
request.add(requestFactory.searchRequest(query, routingResolver.getRouting(), it.next(), indexesIt.next()));
}
MultiSearchResponse.Item[] items = getMultiSearchResult(request);
List<SearchHits<?>> res = new ArrayList<>(queries.size());
Iterator<Class<?>> it1 = classes.iterator();
Iterator<IndexCoordinates> indexesIt1 = indexes.iterator();
for (int i = 0; i < queries.size(); i++) {
Class entityClass = it1.next();
IndexCoordinates index = indexesIt1.next();
ReadDocumentCallback<?> documentCallback = new ReadDocumentCallback<>(elasticsearchConverter, entityClass, index);
SearchDocumentResponseCallback<SearchHits<?>> callback = new ReadSearchDocumentResponseCallback<>(entityClass,
index);
SearchResponse response = items[i].getResponse();
res.add(callback.doWith(SearchDocumentResponseBuilder.from(response, getEntityCreator(documentCallback))));
}
return res;
}
protected MultiSearchResponse.Item[] getMultiSearchResult(MultiSearchRequest request) {
MultiSearchResponse response = execute(client -> client.msearch(request, RequestOptions.DEFAULT));
MultiSearchResponse.Item[] items = response.getResponses();
@@ -228,6 +228,11 @@ public class NativeSearchQueryBuilder extends BaseQueryBuilder<NativeSearchQuery
return this;
}
public NativeSearchQueryBuilder withIndicesOptions(IndicesOptions indicesOptions) {
this.indicesOptions = indicesOptions;
return this;
}
/**
* @since 4.2
*/
@@ -301,8 +306,8 @@ public class NativeSearchQueryBuilder extends BaseQueryBuilder<NativeSearchQuery
nativeSearchQuery.setSearchType(Query.SearchType.valueOf(searchType.name()));
}
if (getIndicesOptions() != null) {
nativeSearchQuery.setIndicesOptions(getIndicesOptions());
if (indicesOptions != null) {
nativeSearchQuery.setIndicesOptions(indicesOptions);
}
nativeSearchQuery.setTrackTotalHits(trackTotalHits);
@@ -13,16 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.cluster;
package org.springframework.data.elasticsearch.client.erhlc;
import reactor.core.publisher.Mono;
import org.springframework.data.elasticsearch.core.cluster.ClusterHealth;
/**
* Reactive Elasticsearch operations on cluster level.
*
* @author Peter-Josef Meisch
* @since 4.2
* @deprecated since 5.0
*/
@Deprecated
public interface ReactiveClusterOperations {
/**
@@ -47,13 +47,24 @@ import org.reactivestreams.Publisher;
import org.springframework.data.elasticsearch.BulkFailureException;
import org.springframework.data.elasticsearch.NoSuchIndexException;
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.cluster.ReactiveClusterOperations;
import org.springframework.data.elasticsearch.core.AbstractReactiveElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.AggregationContainer;
import org.springframework.data.elasticsearch.core.IndexedObjectInformation;
import org.springframework.data.elasticsearch.core.MultiGetItem;
import org.springframework.data.elasticsearch.core.ReactiveIndexOperations;
import org.springframework.data.elasticsearch.core.RefreshPolicy;
import org.springframework.data.elasticsearch.core.SearchHitMapping;
import org.springframework.data.elasticsearch.core.SearchHitSupport;
import org.springframework.data.elasticsearch.core.SearchPage;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.document.SearchDocument;
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.data.elasticsearch.core.query.BulkOptions;
import org.springframework.data.elasticsearch.core.query.ByQueryResponse;
import org.springframework.data.elasticsearch.core.query.Query;
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.http.HttpStatus;
@@ -144,8 +155,8 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
BulkItemResponse bulkItemResponse = indexAndResponse.getT2();
DocWriteResponse response = bulkItemResponse.getResponse();
updateIndexedObject(savedEntity, new IndexedObjectInformation(response.getId(), response.getIndex(),
response.getSeqNo(), response.getPrimaryTerm(), response.getVersion()));
updateIndexedObject(savedEntity, IndexedObjectInformation.of(response.getId(), response.getSeqNo(),
response.getPrimaryTerm(), response.getVersion()));
return maybeCallbackAfterSave(savedEntity, index);
});
@@ -244,11 +255,10 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
return Mono.just(entity).zipWith(doIndex(request) //
.map(indexResponse -> new IndexResponseMetaData( //
indexResponse.getId(), //
indexResponse.getIndex(), //
indexResponse.getSeqNo(), //
indexResponse.getPrimaryTerm(), //
indexResponse.getVersion() //
)));
))); //
}
@Override
@@ -363,8 +373,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
protected Mono<BulkByScrollResponse> doDeleteBy(Query query, Class<?> entityType, IndexCoordinates index) {
return Mono.defer(() -> {
DeleteByQueryRequest request = requestFactory.deleteByQueryRequest(query, routingResolver.getRouting(),
entityType, index);
DeleteByQueryRequest request = requestFactory.deleteByQueryRequest(query, entityType, index);
return doDeleteBy(prepareDeleteByRequest(request));
});
}
@@ -495,7 +504,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
return Flux.defer(() -> {
SearchRequest request = requestFactory.searchRequest(query, routingResolver.getRouting(), clazz, index);
SearchRequest request = requestFactory.searchRequest(query, clazz, index);
boolean useScroll = !(query.getPageable().isPaged() || query.isLimiting());
request = prepareSearchRequest(request, useScroll);
@@ -510,7 +519,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
protected <T> Mono<SearchDocumentResponse> doFindForResponse(Query query, Class<?> clazz, IndexCoordinates index) {
return Mono.defer(() -> {
SearchRequest request = requestFactory.searchRequest(query, routingResolver.getRouting(), clazz, index);
SearchRequest request = requestFactory.searchRequest(query, clazz, index);
request = prepareSearchRequest(request, false);
SearchDocumentCallback<?> documentCallback = new ReadSearchDocumentCallback<>(clazz, index);
@@ -530,7 +539,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
Assert.notNull(index, "index must not be null");
return Flux.defer(() -> {
SearchRequest request = requestFactory.searchRequest(query, routingResolver.getRouting(), entityType, index);
SearchRequest request = requestFactory.searchRequest(query, entityType, index);
request = prepareSearchRequest(request, false);
return doAggregate(request);
});
@@ -555,7 +564,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
protected Mono<Long> doCount(Query query, Class<?> entityType, IndexCoordinates index) {
return Mono.defer(() -> {
SearchRequest request = requestFactory.searchRequest(query, routingResolver.getRouting(), entityType, index);
SearchRequest request = requestFactory.searchRequest(query, entityType, index);
request = prepareSearchRequest(request, false);
return doCount(request);
});
@@ -15,9 +15,13 @@
*/
package org.springframework.data.elasticsearch.client.erhlc;
import static org.elasticsearch.client.Requests.refreshRequest;
import static org.springframework.util.StringUtils.hasText;
import static org.elasticsearch.client.Requests.*;
import static org.springframework.util.StringUtils.*;
import org.springframework.data.elasticsearch.core.IndexInformation;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
import org.springframework.data.elasticsearch.core.ReactiveIndexOperations;
import org.springframework.data.elasticsearch.core.ReactiveResourceUtil;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -32,21 +36,27 @@ import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest;
import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateRequest;
import org.elasticsearch.client.GetAliasesResponse;
import org.elasticsearch.client.indices.*;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
import org.elasticsearch.client.indices.GetMappingsRequest;
import org.elasticsearch.client.indices.IndexTemplatesExistRequest;
import org.elasticsearch.client.indices.PutIndexTemplateRequest;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.elasticsearch.NoSuchIndexException;
import org.springframework.data.elasticsearch.annotations.Mapping;
import org.springframework.data.elasticsearch.core.IndexInformation;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
import org.springframework.data.elasticsearch.core.ReactiveIndexOperations;
import org.springframework.data.elasticsearch.core.ReactiveResourceUtil;
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.DeleteComponentTemplateRequest;
import org.springframework.data.elasticsearch.core.index.PutComponentTemplateRequest;
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.ExistsTemplateRequest;
import org.springframework.data.elasticsearch.core.index.GetTemplateRequest;
import org.springframework.data.elasticsearch.core.index.PutTemplateRequest;
import org.springframework.data.elasticsearch.core.index.ReactiveMappingBuilder;
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;
@@ -280,48 +290,6 @@ class ReactiveIndexTemplate implements ReactiveIndexOperations {
return Mono.from(operations.executeWithIndicesClient(client -> client.putTemplate(putIndexTemplateRequest)));
}
@Override
public Mono<Boolean> putComponentTemplate(PutComponentTemplateRequest putComponentTemplateRequest) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public Flux<TemplateResponse> getComponentTemplate(GetComponentTemplateRequest request) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public Mono<Boolean> existsComponentTemplate(ExistsComponentTemplateRequest existsComponentTemplateRequest) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public Mono<Boolean> deleteComponentTemplate(DeleteComponentTemplateRequest deleteComponentTemplateRequest) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public Mono<Boolean> putIndexTemplate(
org.springframework.data.elasticsearch.core.index.PutIndexTemplateRequest putIndexTemplateRequest) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public Mono<Boolean> existsIndexTemplate(ExistsIndexTemplateRequest existsIndexTemplateRequest) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public Flux<TemplateResponse> getIndexTemplate(GetIndexTemplateRequest getIndexTemplateRequest) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public Mono<Boolean> deleteIndexTemplate(
org.springframework.data.elasticsearch.core.index.DeleteIndexTemplateRequest deleteIndexTemplateRequest) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public Mono<TemplateData> getTemplate(GetTemplateRequest getTemplateRequest) {
@@ -348,7 +348,6 @@ class RequestFactory {
for (String aliasName : parametersAliases) {
Alias alias = new Alias(aliasName);
// noinspection DuplicatedCode
if (parameters.getRouting() != null) {
alias.routing(parameters.getRouting());
}
@@ -526,9 +525,8 @@ class RequestFactory {
// endregion
// region delete
public DeleteByQueryRequest deleteByQueryRequest(Query query, @Nullable String routing, Class<?> clazz,
IndexCoordinates index) {
SearchRequest searchRequest = searchRequest(query, routing, clazz, index);
public DeleteByQueryRequest deleteByQueryRequest(Query query, Class<?> clazz, IndexCoordinates index) {
SearchRequest searchRequest = searchRequest(query, clazz, index);
DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(index.getIndexNames()) //
.setQuery(searchRequest.source().query()) //
.setAbortOnVersionConflict(false) //
@@ -546,8 +544,6 @@ class RequestFactory {
if (query.getRoute() != null) {
deleteByQueryRequest.setRouting(query.getRoute());
} else if (StringUtils.hasText(routing)) {
deleteByQueryRequest.setRouting(routing);
}
return deleteByQueryRequest;
@@ -755,11 +751,10 @@ class RequestFactory {
return searchRequest;
}
public SearchRequest searchRequest(Query query, @Nullable String routing, @Nullable Class<?> clazz,
IndexCoordinates index) {
public SearchRequest searchRequest(Query query, @Nullable Class<?> clazz, IndexCoordinates index) {
elasticsearchConverter.updateQuery(query, clazz);
SearchRequest searchRequest = prepareSearchRequest(query, routing, clazz, index);
SearchRequest searchRequest = prepareSearchRequest(query, clazz, index);
QueryBuilder elasticsearchQuery = getQuery(query);
QueryBuilder elasticsearchFilter = getFilter(query);
@@ -773,8 +768,7 @@ class RequestFactory {
}
private SearchRequest prepareSearchRequest(Query query, @Nullable String routing, @Nullable Class<?> clazz,
IndexCoordinates indexCoordinates) {
private SearchRequest prepareSearchRequest(Query query, @Nullable Class<?> clazz, IndexCoordinates indexCoordinates) {
String[] indexNames = indexCoordinates.getIndexNames();
Assert.notNull(indexNames, "No index defined for Query");
@@ -849,8 +843,6 @@ class RequestFactory {
if (StringUtils.hasLength(query.getRoute())) {
request.routing(query.getRoute());
} else if (StringUtils.hasText(routing)) {
request.routing(routing);
}
Duration timeout = query.getTimeout();
@@ -971,8 +963,6 @@ class RequestFactory {
sort.ignoreUnmapped(geoDistanceOrder.getIgnoreUnmapped());
}
sort.order(order.isAscending() ? SortOrder.ASC : SortOrder.DESC);
return sort;
} else {
FieldSortBuilder sort = SortBuilders //
@@ -48,8 +48,6 @@ import org.springframework.data.elasticsearch.core.index.AliasData;
import org.springframework.data.elasticsearch.core.index.Settings;
import org.springframework.data.elasticsearch.core.index.TemplateData;
import org.springframework.data.elasticsearch.core.query.ByQueryResponse;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.query.StringQuery;
import org.springframework.data.elasticsearch.core.reindex.ReindexResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -80,12 +78,14 @@ public class ResponseConverter {
}
public static AliasData toAliasData(AliasMetadata aliasMetaData) {
Document filter = null;
CompressedXContent aliasMetaDataFilter = aliasMetaData.getFilter();
Query filterQuery = (aliasMetaDataFilter != null) ? StringQuery.builder(aliasMetaDataFilter.string()).build()
: null;
return AliasData.of(aliasMetaData.alias(), filterQuery, aliasMetaData.indexRouting(),
aliasMetaData.getSearchRouting(), aliasMetaData.writeIndex(), aliasMetaData.isHidden());
if (aliasMetaDataFilter != null) {
filter = Document.parse(aliasMetaDataFilter.string());
}
return AliasData.of(aliasMetaData.alias(), filter, aliasMetaData.indexRouting(), aliasMetaData.getSearchRouting(),
aliasMetaData.writeIndex(), aliasMetaData.isHidden());
}
// endregion
@@ -44,7 +44,14 @@ import org.springframework.data.elasticsearch.core.AbstractIndexTemplate;
import org.springframework.data.elasticsearch.core.IndexInformation;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.index.*;
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.ExistsTemplateRequest;
import org.springframework.data.elasticsearch.core.index.GetTemplateRequest;
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.IndexCoordinates;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -224,48 +231,6 @@ class RestIndexTemplate extends AbstractIndexTemplate implements IndexOperations
client -> client.indices().deleteTemplate(deleteIndexTemplateRequest, RequestOptions.DEFAULT).isAcknowledged());
}
@Override
public boolean putIndexTemplate(
org.springframework.data.elasticsearch.core.index.PutIndexTemplateRequest putIndexTemplateRequest) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public boolean existsIndexTemplate(ExistsIndexTemplateRequest existsTemplateRequest) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public List<TemplateResponse> getIndexTemplate(GetIndexTemplateRequest getIndexTemplateRequest) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public boolean deleteIndexTemplate(
org.springframework.data.elasticsearch.core.index.DeleteIndexTemplateRequest deleteIndexTemplateRequest) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public boolean putComponentTemplate(PutComponentTemplateRequest putComponentTemplateRequest) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public boolean existsComponentTemplate(ExistsComponentTemplateRequest existsComponentTemplateRequest) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public List<TemplateResponse> getComponentTemplate(GetComponentTemplateRequest getComponentTemplateRequest) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public boolean deleteComponentTemplate(DeleteComponentTemplateRequest deleteComponentTemplateRequest) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public List<IndexInformation> getInformation(IndexCoordinates index) {
@@ -52,7 +52,6 @@ import org.springframework.data.elasticsearch.core.query.UpdateQuery;
import org.springframework.data.elasticsearch.core.query.UpdateResponse;
import org.springframework.data.elasticsearch.core.routing.DefaultRoutingResolver;
import org.springframework.data.elasticsearch.core.routing.RoutingResolver;
import org.springframework.data.elasticsearch.core.script.Script;
import org.springframework.data.elasticsearch.support.VersionInfo;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.callback.EntityCallbacks;
@@ -66,7 +65,7 @@ import org.springframework.util.StringUtils;
/**
* This class contains methods that are common to different implementations of the {@link ElasticsearchOperations}
* interface that use different clients, like RestHighLevelClient and the next Java client from Elasticsearch or some
* external implementation that might use a different client. This class must not contain imports or use classes that
* future implementation that might use an Opensearch client. This class must not contain imports or use classes that
* are specific to one of these implementations.
* <p>
* <strong>Note:</strong> Although this class is public, it is not considered to be part of the official Spring Data
@@ -368,16 +367,7 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
Assert.notNull(entity, "entity must not be null");
return update(entity, getIndexCoordinatesFor(entity.getClass()));
}
@Override
public <T> UpdateResponse update(T entity, IndexCoordinates index) {
Assert.notNull(entity, "entity must not be null");
Assert.notNull(index, "index must not be null");
return update(buildUpdateQueryByEntity(entity), index);
return update(buildUpdateQueryByEntity(entity), getIndexCoordinatesFor(entity.getClass()));
}
protected <T> UpdateQuery buildUpdateQueryByEntity(T entity) {
@@ -408,29 +398,23 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
ElasticsearchPersistentProperty idProperty = persistentEntity.getIdProperty();
// Only deal with text because ES generated Ids are strings!
if (indexedObjectInformation.id() != null && idProperty != null && idProperty.isReadable()
if (indexedObjectInformation.getId() != null && idProperty != null && idProperty.isReadable()
&& idProperty.getType().isAssignableFrom(String.class)) {
propertyAccessor.setProperty(idProperty, indexedObjectInformation.id());
propertyAccessor.setProperty(idProperty, indexedObjectInformation.getId());
}
if (indexedObjectInformation.seqNo() != null && indexedObjectInformation.primaryTerm() != null
if (indexedObjectInformation.getSeqNo() != null && indexedObjectInformation.getPrimaryTerm() != null
&& persistentEntity.hasSeqNoPrimaryTermProperty()) {
ElasticsearchPersistentProperty seqNoPrimaryTermProperty = persistentEntity.getSeqNoPrimaryTermProperty();
// noinspection ConstantConditions
propertyAccessor.setProperty(seqNoPrimaryTermProperty,
new SeqNoPrimaryTerm(indexedObjectInformation.seqNo(),
indexedObjectInformation.primaryTerm()));
new SeqNoPrimaryTerm(indexedObjectInformation.getSeqNo(), indexedObjectInformation.getPrimaryTerm()));
}
if (indexedObjectInformation.version() != null && persistentEntity.hasVersionProperty()) {
if (indexedObjectInformation.getVersion() != null && persistentEntity.hasVersionProperty()) {
ElasticsearchPersistentProperty versionProperty = persistentEntity.getVersionProperty();
// noinspection ConstantConditions
propertyAccessor.setProperty(versionProperty, indexedObjectInformation.version());
}
var indexedIndexNameProperty = persistentEntity.getIndexedIndexNameProperty();
if (indexedIndexNameProperty != null) {
propertyAccessor.setProperty(indexedIndexNameProperty, indexedObjectInformation.index());
propertyAccessor.setProperty(versionProperty, indexedObjectInformation.getVersion());
}
// noinspection unchecked
@@ -743,29 +727,6 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
}
}
// region script operations
@Override
public boolean putScript(Script script) {
throw new UnsupportedOperationException(
"putScript() operation not implemented by " + getClass().getCanonicalName());
}
@Nullable
@Override
public Script getScript(String name) {
throw new UnsupportedOperationException(
"getScript() operation not implemented by " + getClass().getCanonicalName());
}
@Override
public boolean deleteScript(String name) {
throw new UnsupportedOperationException(
"deleteScript() operation not implemented by " + getClass().getCanonicalName());
}
// endregion
// region Document callbacks
protected interface DocumentCallback<T> {
@Nullable
@@ -797,9 +758,8 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
T entity = reader.read(type, documentAfterLoad);
IndexedObjectInformation indexedObjectInformation = new IndexedObjectInformation( //
IndexedObjectInformation indexedObjectInformation = IndexedObjectInformation.of( //
documentAfterLoad.hasId() ? documentAfterLoad.getId() : null, //
documentAfterLoad.getIndex(), //
documentAfterLoad.hasSeqNo() ? documentAfterLoad.getSeqNo() : null, //
documentAfterLoad.hasPrimaryTerm() ? documentAfterLoad.getPrimaryTerm() : null, //
documentAfterLoad.hasVersion() ? documentAfterLoad.getVersion() : null); //
@@ -17,17 +17,13 @@ package org.springframework.data.elasticsearch.core;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.publisher.Sinks;
import reactor.util.function.Tuple2;
import java.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
@@ -54,7 +50,6 @@ import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm;
import org.springframework.data.elasticsearch.core.routing.DefaultRoutingResolver;
import org.springframework.data.elasticsearch.core.routing.RoutingResolver;
import org.springframework.data.elasticsearch.core.script.Script;
import org.springframework.data.elasticsearch.core.suggest.response.Suggest;
import org.springframework.data.elasticsearch.support.VersionInfo;
import org.springframework.data.mapping.PersistentPropertyAccessor;
@@ -211,61 +206,6 @@ abstract public class AbstractReactiveElasticsearchTemplate
return save(entity, getIndexCoordinatesFor(entity.getClass()));
}
@Override
public <T> Flux<T> save(Flux<T> entities, Class<?> clazz, int bulkSize) {
return save(entities, getIndexCoordinatesFor(clazz), bulkSize);
}
@Override
public <T> Flux<T> save(Flux<T> entities, IndexCoordinates index, int bulkSize) {
Assert.notNull(entities, "entities must not be null");
Assert.notNull(index, "index must not be null");
Assert.isTrue(bulkSize > 0, "bulkSize must be greater than 0");
return Flux.defer(() -> {
Sinks.Many<T> sink = Sinks.many().unicast().onBackpressureBuffer();
entities.window(bulkSize) //
.concatMap(flux -> flux.collectList()) //
.subscribe(new Subscriber<List<T>>() {
private Subscription subscription;
private AtomicBoolean upstreamComplete = new AtomicBoolean(false);
@Override
public void onSubscribe(Subscription subscription) {
this.subscription = subscription;
subscription.request(1);
}
@Override
public void onNext(List<T> entityList) {
saveAll(entityList, index) //
.map(sink::tryEmitNext) //
.doOnComplete(() -> {
if (!upstreamComplete.get()) {
subscription.request(1);
} else {
sink.tryEmitComplete();
}
}).subscribe();
}
@Override
public void onError(Throwable throwable) {
subscription.cancel();
sink.tryEmitError(throwable);
}
@Override
public void onComplete() {
upstreamComplete.set(true);
}
});
return sink.asFlux();
});
}
@Override
public <T> Flux<T> saveAll(Mono<? extends Collection<? extends T>> entities, Class<T> clazz) {
return saveAll(entities, getIndexCoordinatesFor(clazz));
@@ -320,28 +260,23 @@ abstract public class AbstractReactiveElasticsearchTemplate
ElasticsearchPersistentProperty idProperty = persistentEntity.getIdProperty();
// Only deal with text because ES generated Ids are strings!
if (indexedObjectInformation.id() != null && idProperty != null && idProperty.isReadable()
if (indexedObjectInformation.getId() != null && idProperty != null && idProperty.isReadable()
&& idProperty.getType().isAssignableFrom(String.class)) {
propertyAccessor.setProperty(idProperty, indexedObjectInformation.id());
propertyAccessor.setProperty(idProperty, indexedObjectInformation.getId());
}
if (indexedObjectInformation.seqNo() != null && indexedObjectInformation.primaryTerm() != null
if (indexedObjectInformation.getSeqNo() != null && indexedObjectInformation.getPrimaryTerm() != null
&& persistentEntity.hasSeqNoPrimaryTermProperty()) {
ElasticsearchPersistentProperty seqNoPrimaryTermProperty = persistentEntity.getSeqNoPrimaryTermProperty();
// noinspection ConstantConditions
propertyAccessor.setProperty(seqNoPrimaryTermProperty,
new SeqNoPrimaryTerm(indexedObjectInformation.seqNo(), indexedObjectInformation.primaryTerm()));
new SeqNoPrimaryTerm(indexedObjectInformation.getSeqNo(), indexedObjectInformation.getPrimaryTerm()));
}
if (indexedObjectInformation.version() != null && persistentEntity.hasVersionProperty()) {
if (indexedObjectInformation.getVersion() != null && persistentEntity.hasVersionProperty()) {
ElasticsearchPersistentProperty versionProperty = persistentEntity.getVersionProperty();
// noinspection ConstantConditions
propertyAccessor.setProperty(versionProperty, indexedObjectInformation.version());
}
var indexedIndexNameProperty = persistentEntity.getIndexedIndexNameProperty();
if (indexedIndexNameProperty != null) {
propertyAccessor.setProperty(indexedIndexNameProperty, indexedObjectInformation.index());
propertyAccessor.setProperty(versionProperty, indexedObjectInformation.getVersion());
}
// noinspection unchecked
@@ -350,7 +285,7 @@ abstract public class AbstractReactiveElasticsearchTemplate
} else {
EntityOperations.AdaptableEntity<T> adaptableEntity = entityOperations.forEntity(entity,
converter.getConversionService(), routingResolver);
adaptableEntity.populateIdIfNecessary(indexedObjectInformation.id());
adaptableEntity.populateIdIfNecessary(indexedObjectInformation.getId());
}
return entity;
}
@@ -381,9 +316,8 @@ abstract public class AbstractReactiveElasticsearchTemplate
.map(it -> {
T savedEntity = it.getT1();
IndexResponseMetaData indexResponseMetaData = it.getT2();
return updateIndexedObject(savedEntity, new IndexedObjectInformation( //
return updateIndexedObject(savedEntity, IndexedObjectInformation.of( //
indexResponseMetaData.id(), //
indexResponseMetaData.index(), //
indexResponseMetaData.seqNo(), //
indexResponseMetaData.primaryTerm(), //
indexResponseMetaData.version()));
@@ -636,9 +570,8 @@ abstract public class AbstractReactiveElasticsearchTemplate
T entity = reader.read(type, documentAfterLoad);
IndexedObjectInformation indexedObjectInformation = new IndexedObjectInformation( //
IndexedObjectInformation indexedObjectInformation = IndexedObjectInformation.of( //
documentAfterLoad.hasId() ? documentAfterLoad.getId() : null, //
documentAfterLoad.getIndex(), //
documentAfterLoad.hasSeqNo() ? documentAfterLoad.getSeqNo() : null, //
documentAfterLoad.hasPrimaryTerm() ? documentAfterLoad.getPrimaryTerm() : null, //
documentAfterLoad.hasVersion() ? documentAfterLoad.getVersion() : null); //
@@ -651,14 +584,12 @@ abstract public class AbstractReactiveElasticsearchTemplate
/**
* Callback to convert a {@link SearchDocument} into different other classes
*
* @param <T> the entity type
*/
protected interface SearchDocumentCallback<T> {
/**
* converts a {@link SearchDocument} to an entity
*
* @param searchDocument
* @return the entity in a MOno
*/
@@ -666,7 +597,6 @@ abstract public class AbstractReactiveElasticsearchTemplate
/**
* converts a {@link SearchDocument} into a SearchHit
*
* @param searchDocument
* @return
*/
@@ -697,26 +627,6 @@ abstract public class AbstractReactiveElasticsearchTemplate
// endregion
// region script operations
@Override
public Mono<Boolean> putScript(Script script) {
throw new UnsupportedOperationException(
"putScript() operation not implemented by " + getClass().getCanonicalName());
}
@Override
public Mono<Script> getScript(String name) {
throw new UnsupportedOperationException(
"getScript() operation not implemented by " + getClass().getCanonicalName());
}
@Override
public Mono<Boolean> deleteScript(String name) {
throw new UnsupportedOperationException(
"deleteScript() operation not implemented by " + getClass().getCanonicalName());
}
// endregion
// region Helper methods
@Override
public IndexCoordinates getIndexCoordinatesFor(Class<?> clazz) {
@@ -751,7 +661,7 @@ abstract public class AbstractReactiveElasticsearchTemplate
/**
* Value class to capture client independent information from a response to an index request.
*/
public record IndexResponseMetaData(String id, String index, long seqNo, long primaryTerm, long version) {
public record IndexResponseMetaData(String id, long seqNo, long primaryTerm, long version) {
}
// endregion
@@ -303,17 +303,6 @@ public interface DocumentOperations {
*/
<T> UpdateResponse update(T entity);
/**
* Partially update a document by the given entity.
*
* @param entity the entity to update partially, must not be {@literal null}.
* @param index the index to use for the update instead of the one defined by the entity, must not be null
* @return the update response
* @param <T> the entity type
* @since 5.1
*/
<T> UpdateResponse update(T entity, IndexCoordinates index);
/**
* Partial update of the document.
*
@@ -21,7 +21,6 @@ import org.springframework.data.elasticsearch.core.cluster.ClusterOperations;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.routing.RoutingResolver;
import org.springframework.data.elasticsearch.core.script.ScriptOperations;
import org.springframework.lang.Nullable;
/**
@@ -37,7 +36,7 @@ import org.springframework.lang.Nullable;
* @author Dmitriy Yakovlev
* @author Peter-Josef Meisch
*/
public interface ElasticsearchOperations extends DocumentOperations, SearchOperations, ScriptOperations {
public interface ElasticsearchOperations extends DocumentOperations, SearchOperations {
/**
* get an {@link IndexOperations} that is bound to the given class
@@ -20,7 +20,14 @@ import java.util.Map;
import java.util.Set;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.index.*;
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.ExistsTemplateRequest;
import org.springframework.data.elasticsearch.core.index.GetTemplateRequest;
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.IndexCoordinates;
import org.springframework.lang.Nullable;
@@ -217,65 +224,16 @@ public interface IndexOperations {
* @param putTemplateRequest template request parameters
* @return true if successful
* @since 4.1
* @deprecated since 5.1, as the underlying Elasticsearch API is deprecated.
*/
@Deprecated
boolean putTemplate(PutTemplateRequest putTemplateRequest);
/**
* Creates an index template
*
* @param putIndexTemplateRequest template request parameters
* @return {@literal true} if successful
* @since 5.1
*/
boolean putIndexTemplate(PutIndexTemplateRequest putIndexTemplateRequest);
/**
* Writes a component index template that can be used in a composable index template.
*
* @param putComponentTemplateRequest index template request parameters
* @return {@literal true} if successful
* @since 5.1
*/
boolean putComponentTemplate(PutComponentTemplateRequest putComponentTemplateRequest);
/**
* Checks wether a component index template exists.
*
* @param existsComponentTemplateRequest the parameters for the request
* @return {@literal true} if the componentTemplate exists.
* @since 5.1
*/
boolean existsComponentTemplate(ExistsComponentTemplateRequest existsComponentTemplateRequest);
/**
* Get a component template.
*
* @param getComponentTemplateRequest parameters for the request, may contain wildcard names
* @return the found {@link TemplateResponse}s, may be empty
* @since 5.1
*/
List<TemplateResponse> getComponentTemplate(GetComponentTemplateRequest getComponentTemplateRequest);
/**
* Deletes the given component index template
*
* @param deleteComponentTemplateRequest request parameters
* @return {@literal true} if successful.
* @since 5.1
*/
boolean deleteComponentTemplate(DeleteComponentTemplateRequest deleteComponentTemplateRequest);
/**
* gets an index template using the legacy Elasticsearch interface.
*
* @param templateName the template name
* @return TemplateData, {@literal null} if no template with the given name exists.
* @since 4.1
* @deprecated since 5.1, as the underlying Elasticsearch API is deprecated.
*/
@Deprecated
@Nullable
default TemplateData getTemplate(String templateName) {
return getTemplate(new GetTemplateRequest(templateName));
@@ -287,9 +245,7 @@ public interface IndexOperations {
* @param getTemplateRequest the request parameters
* @return TemplateData, {@literal null} if no template with the given name exists.
* @since 4.1
* @deprecated since 5.1, as the underlying Elasticsearch API is deprecated.
*/
@Deprecated
@Nullable
TemplateData getTemplate(GetTemplateRequest getTemplateRequest);
@@ -299,9 +255,7 @@ public interface IndexOperations {
* @param templateName the template name
* @return {@literal true} if the index exists
* @since 4.1
* @deprecated since 5.1, as the underlying Elasticsearch API is deprecated.
*/
@Deprecated
default boolean existsTemplate(String templateName) {
return existsTemplate(new ExistsTemplateRequest(templateName));
}
@@ -312,69 +266,9 @@ public interface IndexOperations {
* @param existsTemplateRequest the request parameters
* @return {@literal true} if the index exists
* @since 4.1
* @deprecated since 5.1, as the underlying Elasticsearch API is deprecated.
*/
@Deprecated
boolean existsTemplate(ExistsTemplateRequest existsTemplateRequest);
/**
* check if an index template exists.
*
* @param templateName the template name
* @return true if the index template exists
* @since 5.1
*/
default boolean existsIndexTemplate(String templateName) {
return existsIndexTemplate(new ExistsIndexTemplateRequest(templateName));
}
/**
* check if an index template exists.
*
* @param existsTemplateRequest the request parameters
* @return true if the index template exists
* @since 5.1
*/
boolean existsIndexTemplate(ExistsIndexTemplateRequest existsTemplateRequest);
/**
* Gets an index template.
*
* @param templateName template name
* @since 5.1
*/
default List<TemplateResponse> getIndexTemplate(String templateName) {
return getIndexTemplate(new GetIndexTemplateRequest(templateName));
}
/**
* Gets an index template.
*
* @param getIndexTemplateRequest the request parameters
* @since 5.1
*/
List<TemplateResponse> getIndexTemplate(GetIndexTemplateRequest getIndexTemplateRequest);
/**
* Deletes an index template.
*
* @param templateName template name
* @return true if successful
* @since 5.1
*/
default boolean deleteIndexTemplate(String templateName) {
return deleteIndexTemplate(new DeleteIndexTemplateRequest(templateName));
}
/**
* Deletes an index template.
*
* @param deleteIndexTemplateRequest template request parameters
* @return true if successful
* @since 5.1
*/
boolean deleteIndexTemplate(DeleteIndexTemplateRequest deleteIndexTemplateRequest);
/**
* Deletes an index template using the legacy Elasticsearch interface (@see
* https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates-v1.html).
@@ -382,9 +276,7 @@ public interface IndexOperations {
* @param templateName the template name
* @return true if successful
* @since 4.1
* @deprecated since 5.1, as the underlying Elasticsearch API is deprecated.
*/
@Deprecated
default boolean deleteTemplate(String templateName) {
return deleteTemplate(new DeleteTemplateRequest(templateName));
}
@@ -396,9 +288,7 @@ public interface IndexOperations {
* @param deleteTemplateRequest template request parameters
* @return true if successful
* @since 4.1
* @deprecated since 5.1, as the underlying Elasticsearch API is deprecated.
*/
@Deprecated
boolean deleteTemplate(DeleteTemplateRequest deleteTemplateRequest);
// endregion
@@ -24,12 +24,42 @@ import org.springframework.lang.Nullable;
* @author Roman Puchkovskiy
* @since 4.1
*/
public record IndexedObjectInformation( //
@Nullable String id, //
/** @since 5.1 */ //
@Nullable String index, //
@Nullable Long seqNo, //
@Nullable Long primaryTerm, //
@Nullable Long version //
) {
public class IndexedObjectInformation {
@Nullable private final String id;
@Nullable private final Long seqNo;
@Nullable private final Long primaryTerm;
@Nullable private final Long version;
private IndexedObjectInformation(@Nullable String id, @Nullable Long seqNo, @Nullable Long primaryTerm,
@Nullable Long version) {
this.id = id;
this.seqNo = seqNo;
this.primaryTerm = primaryTerm;
this.version = version;
}
public static IndexedObjectInformation of(@Nullable String id, @Nullable Long seqNo, @Nullable Long primaryTerm,
@Nullable Long version) {
return new IndexedObjectInformation(id, seqNo, primaryTerm, version);
}
@Nullable
public String getId() {
return id;
}
@Nullable
public Long getSeqNo() {
return seqNo;
}
@Nullable
public Long getPrimaryTerm() {
return primaryTerm;
}
@Nullable
public Long getVersion() {
return version;
}
}
@@ -44,9 +44,6 @@ import org.springframework.util.Assert;
* @since 4.0
*/
public interface ReactiveDocumentOperations {
int FLUX_SAVE_BULK_SIZE = 500;
/**
* Index the given entity, once available, extracting index from entity metadata.
*
@@ -96,61 +93,6 @@ public interface ReactiveDocumentOperations {
*/
<T> Mono<T> save(T entity, IndexCoordinates index);
/**
* Indexes the entities into the index extracted from entity metadata.
*
* @param entities
* @param clazz the class to get the index name from
* @param <T> entity type
* @return a Flux emitting the saved entities
* @since 5.1
*/
default <T> Flux<T> save(Flux<T> entities, Class<?> clazz) {
return save(entities, clazz, FLUX_SAVE_BULK_SIZE);
}
/**
* Indexes the entities into the index extracted from entity metadata. The entities are collected into batches of
* {bulkSize} with a maximal timeout of 200 ms, see
* {@link reactor.core.publisher.Flux#bufferTimeout(int, java.time .Duration)} and then sent in a bulk operation to
* Elasticsearch.
*
* @param entities
* @param clazz the class to get the index name from
* @param bulkSize number of entities to put in a bulk request
* @param <T> entity type
* @return a Flux emitting the saved entities
* @since 5.1
*/
<T> Flux<T> save(Flux<T> entities, Class<?> clazz, int bulkSize);
/**
* Indexes the entities into the given index.
*
* @param entities the entities to save
* @param index the index to save to
* @param <T> entity type
* @return a Flux emitting the saved entities
* @since 5.1
*/
default <T> Flux<T> save(Flux<T> entities, IndexCoordinates index) {
return save(entities, index, FLUX_SAVE_BULK_SIZE);
}
/**
* Indexes the entities into the given index. The entities are collected into batches of {bulkSize} with a maximal
* timeout of 200 ms, see {@link reactor.core.publisher.Flux#bufferTimeout(int, java.time * .Duration)} and then sent
* in a bulk operation to Elasticsearch.
*
* @param entities the entities to save
* @param index the index to save to
* @param bulkSize number of entities to put in a bulk request
* @param <T> entity type
* @return a Flux emitting the saved entities
* @since 5.1
*/
<T> Flux<T> save(Flux<T> entities, IndexCoordinates index, int bulkSize);
/**
* Index entities the index extracted from entity metadata.
*
@@ -16,14 +16,13 @@
package org.springframework.data.elasticsearch.core;
import org.reactivestreams.Publisher;
import org.springframework.data.elasticsearch.client.erhlc.ReactiveClusterOperations;
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.cluster.ReactiveClusterOperations;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.routing.RoutingResolver;
import org.springframework.data.elasticsearch.core.script.ReactiveScriptOperations;
import org.springframework.lang.Nullable;
/**
@@ -38,8 +37,7 @@ import org.springframework.lang.Nullable;
* @author Peter-Josef Meisch
* @since 3.2
*/
public interface ReactiveElasticsearchOperations
extends ReactiveDocumentOperations, ReactiveSearchOperations, ReactiveScriptOperations {
public interface ReactiveElasticsearchOperations extends ReactiveDocumentOperations, ReactiveSearchOperations {
/**
* Execute within a {@link ClientCallback} managing resources and translating errors.
@@ -22,7 +22,14 @@ import java.util.Map;
import java.util.Set;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.index.*;
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.ExistsTemplateRequest;
import org.springframework.data.elasticsearch.core.index.GetTemplateRequest;
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.IndexCoordinates;
/**
@@ -219,125 +226,16 @@ public interface ReactiveIndexOperations {
* @param putTemplateRequest template request parameters
* @return Mono of {@literal true} if the template could be stored
* @since 4.1
* @deprecated since 5.1, as the underlying Elasticsearch API is deprecated.
*/
@Deprecated
Mono<Boolean> putTemplate(PutTemplateRequest putTemplateRequest);
/**
* Writes a component index template that can be used in a composable index template.
*
* @param putComponentTemplateRequest index template request parameters
* @return {@literal true} if successful
* @since 5.1
*/
Mono<Boolean> putComponentTemplate(PutComponentTemplateRequest putComponentTemplateRequest);
/**
* Get component template(s).
*
* @param getComponentTemplateRequest the getComponentTemplateRequest parameters
* @return a {@link Flux} of {@link TemplateResponse}
* @since 5.1
*/
Flux<TemplateResponse> getComponentTemplate(GetComponentTemplateRequest getComponentTemplateRequest);
/**
* Checks wether a component index template exists.
*
* @param existsComponentTemplateRequest the parameters for the request
* @return Mono with the value if the componentTemplate exists.
* @since 5.1
*/
Mono<Boolean> existsComponentTemplate(ExistsComponentTemplateRequest existsComponentTemplateRequest);
/**
* Deletes a component index template.
*
* @param deleteComponentTemplateRequest the parameters for the request
* @return Mono with the value if the request was acknowledged.
* @since 5.1
*/
Mono<Boolean> deleteComponentTemplate(DeleteComponentTemplateRequest deleteComponentTemplateRequest);
/**
* Creates an index template.
*
* @param putIndexTemplateRequest template request parameters
* @return {@literal true} if successful
* @since 5.1
*/
Mono<Boolean> putIndexTemplate(PutIndexTemplateRequest putIndexTemplateRequest);
/**
* Checks if an index template exists.
*
* @param indexTemplateName the name of the index template
* @return Mono with the value if the index template exists.
* @since 5.1
*/
default Mono<Boolean> existsIndexTemplate(String indexTemplateName) {
return existsIndexTemplate(new ExistsIndexTemplateRequest(indexTemplateName));
}
/**
* Checks if an index template exists.
*
* @param existsIndexTemplateRequest the parameters for the request
* @return Mono with the value if the index template exists.
* @since 5.1
*/
Mono<Boolean> existsIndexTemplate(ExistsIndexTemplateRequest existsIndexTemplateRequest);
/**
* Get index template(s).
*
* @param indexTemplateName the name of the index template
* @return a {@link Flux} of {@link TemplateResponse}
* @since 5.1
*/
default Flux<TemplateResponse> getIndexTemplate(String indexTemplateName) {
return getIndexTemplate(new GetIndexTemplateRequest(indexTemplateName));
}
/**
* Get index template(s).
*
* @param getIndexTemplateRequest
* @return a {@link Flux} of {@link TemplateResponse}
* @since 5.1
*/
Flux<TemplateResponse> getIndexTemplate(GetIndexTemplateRequest getIndexTemplateRequest);
/**
* Deletes an index template.
*
* @param indexTemplateName the name of the index template
* @return Mono with the value if the request was acknowledged.
* @since 5.1
*/
default Mono<Boolean> deleteIndexTemplate(String indexTemplateName) {
return deleteIndexTemplate(new DeleteIndexTemplateRequest(indexTemplateName));
}
/**
* Deletes an index template.
*
* @param deleteIndexTemplateRequest the parameters for the request
* @return Mono with the value if the request was acknowledged.
* @since 5.1
*/
Mono<Boolean> deleteIndexTemplate(DeleteIndexTemplateRequest deleteIndexTemplateRequest);
/**
* gets an index template using the legacy Elasticsearch interface.
*
* @param templateName the template name
* @return Mono of TemplateData, {@literal Mono.empty()} if no template with the given name exists.
* @since 4.1
* @deprecated since 5.1, as the underlying Elasticsearch API is deprecated.
*/
@Deprecated
default Mono<TemplateData> getTemplate(String templateName) {
return getTemplate(new GetTemplateRequest(templateName));
}
@@ -348,9 +246,7 @@ public interface ReactiveIndexOperations {
* @param getTemplateRequest the request parameters
* @return Mono of TemplateData, {@literal Mono.empty()} if no template with the given name exists.
* @since 4.1
* @deprecated since 5.1, as the underlying Elasticsearch API is deprecated.
*/
@Deprecated
Mono<TemplateData> getTemplate(GetTemplateRequest getTemplateRequest);
/**
@@ -360,9 +256,7 @@ public interface ReactiveIndexOperations {
* @param templateName the template name
* @return Mono of {@literal true} if the template exists
* @since 4.1
* @deprecated since 5.1, as the underlying Elasticsearch API is deprecated.
*/
@Deprecated
default Mono<Boolean> existsTemplate(String templateName) {
return existsTemplate(new ExistsTemplateRequest(templateName));
}
@@ -374,9 +268,7 @@ public interface ReactiveIndexOperations {
* @param existsTemplateRequest template request parameters
* @return Mono of {@literal true} if the template exists
* @since 4.1
* @deprecated since 5.1, as the underlying Elasticsearch API is deprecated.
*/
@Deprecated
Mono<Boolean> existsTemplate(ExistsTemplateRequest existsTemplateRequest);
/**
@@ -386,9 +278,7 @@ public interface ReactiveIndexOperations {
* @param templateName the template name
* @return Mono of {@literal true} if the template could be deleted
* @since 4.1
* @deprecated since 5.1, as the underlying Elasticsearch API is deprecated.
*/
@Deprecated
default Mono<Boolean> deleteTemplate(String templateName) {
return deleteTemplate(new DeleteTemplateRequest(templateName));
}
@@ -400,9 +290,7 @@ public interface ReactiveIndexOperations {
* @param deleteTemplateRequest template request parameters
* @return Mono of {@literal true} if the template could be deleted
* @since 4.1
* @deprecated since 5.1, as the underlying Elasticsearch API is deprecated.
*/
@Deprecated
Mono<Boolean> deleteTemplate(DeleteTemplateRequest deleteTemplateRequest);
// endregion
@@ -45,7 +45,6 @@ import org.springframework.util.Assert;
* @author Roman Puchkovskiy
* @author Matt Gilene
* @author Sascha Woo
* @author Jakob Hoeper
* @since 4.0
*/
public class SearchHitMapping<T> {
@@ -200,10 +199,9 @@ public class SearchHitMapping<T> {
}
try {
ElasticsearchPersistentEntity<?> persistentEntityForType = mappingContext.getPersistentEntity(type);
NestedMetaData nestedMetaData = searchHits.getSearchHit(0).getContent().getNestedMetaData();
ElasticsearchPersistentEntityWithNestedMetaData persistentEntityWithNestedMetaData = getPersistentEntity(
persistentEntityForType, nestedMetaData);
mappingContext.getPersistentEntity(type), nestedMetaData);
if (persistentEntityWithNestedMetaData.entity != null) {
List<SearchHit<Object>> convertedSearchHits = new ArrayList<>();
@@ -221,8 +219,7 @@ public class SearchHitMapping<T> {
searchDocument.getSortValues(), //
searchDocument.getHighlightFields(), //
searchHit.getInnerHits(), //
getPersistentEntity(persistentEntityForType, //
searchHit.getContent().getNestedMetaData()).nestedMetaData, //
persistentEntityWithNestedMetaData.nestedMetaData, //
searchHit.getExplanation(), //
searchHit.getMatchedQueries(), //
targetObject));
@@ -30,7 +30,6 @@ import org.springframework.lang.Nullable;
*
* @author Peter-Josef Meisch
* @author Sascha Woo
* @author Hamid Rahimi
* @since 4.0
*/
public interface SearchOperations {
@@ -128,23 +127,11 @@ public interface SearchOperations {
*
* @param queries the queries to execute
* @param classes the entity classes used for property mapping
* @param index the index to run the queries against
* @param index the index to run the query against
* @return list of SearchHits
*/
List<SearchHits<?>> multiSearch(List<? extends Query> queries, List<Class<?>> classes, IndexCoordinates index);
/**
* Execute the multi search query against elasticsearch and return result as {@link List} of {@link SearchHits}.
*
* @param queries the queries to execute
* @param classes the entity classes used for property mapping
* @param indexes the indexes to run the queries against
* @return list of SearchHits
* @since 5.1
*/
List<SearchHits<?>> multiSearch(List<? extends Query> queries, List<Class<?>> classes,
List<IndexCoordinates> indexes);
/**
* Execute the criteria query against elasticsearch and return result as {@link SearchHits}
*
@@ -234,20 +221,19 @@ public interface SearchOperations {
/**
* Opens a point in time (pit) in Elasticsearch.
*
* @param index the index name(s) to use
* @param keepAlive the duration the pit shoult be kept alive
* @param index the index name(s) to use
* @param keepAlive the duration the pit shoult be kept alive
* @return the pit identifier
* @since 5.0
*/
default String openPointInTime(IndexCoordinates index, Duration keepAlive) {
return openPointInTime(index, keepAlive, false);
}
/**
* Opens a point in time (pit) in Elasticsearch.
*
* @param index the index name(s) to use
* @param keepAlive the duration the pit shoult be kept alive
* @param index the index name(s) to use
* @param keepAlive the duration the pit shoult be kept alive
* @param ignoreUnavailable if {$literal true} the call will fail if any of the indices is missing or closed
* @return the pit identifier
* @since 5.0
@@ -409,15 +409,15 @@ public class MappingElasticsearchConverter
PersistentPropertyAccessor<R> accessor = new ConvertingPropertyAccessor<>(entity.getPropertyAccessor(instance),
conversionService);
for (ElasticsearchPersistentProperty property : entity) {
for (ElasticsearchPersistentProperty prop : entity) {
if (entity.isCreatorArgument(property) || !property.isReadable() || property.isIndexedIndexNameProperty()) {
if (entity.isCreatorArgument(prop) || !prop.isReadable()) {
continue;
}
Object value = valueProvider.getPropertyValue(property);
Object value = valueProvider.getPropertyValue(prop);
if (value != null) {
accessor.setProperty(property, value);
accessor.setProperty(prop, value);
}
}
@@ -939,14 +939,7 @@ public class MappingElasticsearchConverter
for (ElasticsearchPersistentProperty property : entity) {
if (!property.isWritable() //
|| property.isIndexedIndexNameProperty() //
|| (property.isIdProperty() && !entity.storeIdInSource()) //
|| (property.isVersionProperty() && !entity.storeVersionInSource())) {
continue;
}
if (property.isIdProperty() && !entity.storeIdInSource()) {
if (!property.isWritable()) {
continue;
}
@@ -961,10 +954,6 @@ public class MappingElasticsearchConverter
continue;
}
if (!property.storeEmptyValue() && hasEmptyValue(value)) {
continue;
}
if (property.hasPropertyValueConverter()) {
value = propertyConverterWrite(property, value);
sink.set(property, value);
@@ -993,16 +982,6 @@ public class MappingElasticsearchConverter
}
}
private static boolean hasEmptyValue(Object value) {
if (value instanceof String s && s.isEmpty() || value instanceof Collection<?> c && c.isEmpty()
|| value instanceof Map<?, ?> m && m.isEmpty()) {
return true;
}
return false;
}
@SuppressWarnings("unchecked")
protected void writeProperty(ElasticsearchPersistentProperty property, Object value, MapValueAccessor sink) {
@@ -1419,7 +1398,7 @@ public class MappingElasticsearchConverter
}
if (property.hasExplicitFieldName() || !fieldName.contains(".")) {
if (!fieldName.contains(".")) {
return target.get(fieldName);
}
@@ -107,7 +107,7 @@ public interface Document extends StringObjectMap<Document> {
}
/**
* @return the index if this document was retrieved from an index or was just stored.
* @return the index if this document was retrieved from an index
* @since 4.1
*/
@Nullable
@@ -15,7 +15,7 @@
*/
package org.springframework.data.elasticsearch.core.index;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.lang.Nullable;
/**
@@ -24,35 +24,34 @@ import org.springframework.lang.Nullable;
* @author Peter-Josef Meisch
*/
public class AliasData {
private final String alias;
@Nullable private final Query filterQuery;
@Nullable private final String indexRouting;
@Nullable private final String searchRouting;
@Nullable private final Boolean isWriteIndex;
@Nullable private final Boolean isHidden;
private String alias;
@Nullable Document filter;
@Nullable private String indexRouting;
@Nullable private String searchRouting;
@Nullable private Boolean isWriteIndex;
@Nullable private Boolean isHidden;
private AliasData(String alias, @Nullable Query filterQuery, @Nullable String indexRouting,
@Nullable String searchRouting, @Nullable Boolean isWriteIndex, @Nullable Boolean isHidden) {
private AliasData(String alias, @Nullable Document filter, @Nullable String indexRouting,
@Nullable String searchRouting, Boolean isWriteIndex, Boolean isHidden) {
this.alias = alias;
this.filterQuery = filterQuery;
this.filter = filter;
this.indexRouting = indexRouting;
this.searchRouting = searchRouting;
this.isWriteIndex = isWriteIndex;
this.isHidden = isHidden;
}
public static AliasData of(String alias, @Nullable Query filterQuery, @Nullable String indexRouting,
public static AliasData of(String alias, @Nullable Document filter, @Nullable String indexRouting,
@Nullable String searchRouting, @Nullable Boolean isWriteIndex, @Nullable Boolean isHidden) {
return new AliasData(alias, filterQuery, indexRouting, searchRouting, isWriteIndex, isHidden);
return new AliasData(alias, filter, indexRouting, searchRouting, isWriteIndex, isHidden);
}
public String getAlias() {
return alias;
}
@Nullable
public Query getFilterQuery() {
return filterQuery;
public Document getFilter() {
return filter;
}
@Nullable
@@ -1,71 +0,0 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.index;
import java.util.Map;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* A component template to be used in a component template request.
*
* @author Peter-Josef Meisch
* @since 5.1
*/
public record ComponentTemplateRequestData(@Nullable Settings settings, @Nullable Document mapping,
@Nullable AliasActions aliasActions, @Nullable Boolean allowAutoCreate) {
public static Builder builder() {
return new Builder();
}
public static final class Builder {
@Nullable private Settings settings;
@Nullable private Document mapping;
@Nullable private AliasActions aliasActions;
@Nullable private Boolean allowAutoCreate;
public Builder withSettings(Map<String, Object> settings) {
this.settings = new Settings(settings);
return this;
}
public Builder withMapping(Document mapping) {
this.mapping = mapping;
return this;
}
public Builder withAliasActions(AliasActions aliasActions) {
aliasActions.getActions().forEach(action -> Assert.isTrue(action instanceof AliasAction.Add,
"only alias add actions are allowed in templates"));
this.aliasActions = aliasActions;
return this;
}
public Builder withAllowAutoCreate(@Nullable Boolean allowAutoCreate) {
this.allowAutoCreate = allowAutoCreate;
return this;
}
public ComponentTemplateRequestData build() {
return new ComponentTemplateRequestData(settings, mapping, aliasActions, allowAutoCreate);
}
}
}
@@ -1,28 +0,0 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.index;
import org.springframework.util.Assert;
/**
* @author Peter-Josef Meisch
* @since 5.1
*/
public record DeleteComponentTemplateRequest(String templateName) {
public DeleteComponentTemplateRequest {
Assert.notNull(templateName, "templateName must not be null");
}
}
@@ -1,28 +0,0 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.index;
import org.springframework.util.Assert;
/**
* @author Peter-Josef Meisch
* @since 5.1
*/
public record DeleteIndexTemplateRequest(String templateName) {
public DeleteIndexTemplateRequest {
Assert.notNull(templateName, "templateName must not be null");
}
}
@@ -1,28 +0,0 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.index;
import org.springframework.util.Assert;
/**
* @author Peter-Josef Meisch
* @since 5.1
*/
public record ExistsComponentTemplateRequest(String templateName) {
public ExistsComponentTemplateRequest {
Assert.notNull(templateName, "templateName must not be null");
}
}
@@ -1,28 +0,0 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.index;
import org.springframework.util.Assert;
/**
* @author Peter-Josef Meisch
* @since 5.1
*/
public record ExistsIndexTemplateRequest(String templateName) {
public ExistsIndexTemplateRequest {
Assert.notNull(templateName, "templateName must not be null");
}
}
@@ -1,28 +0,0 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.index;
import org.springframework.util.Assert;
/**
* @author Peter-Josef Meisch
* @since 5.1
*/
public record GetComponentTemplateRequest(String templateName) {
public GetComponentTemplateRequest {
Assert.notNull(templateName, "templateName must not be null");
}
}
@@ -1,28 +0,0 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.index;
import org.springframework.util.Assert;
/**
* @author Peter-Josef Meisch
* @since 5.1
*/
public record GetIndexTemplateRequest(String templateName) {
public GetIndexTemplateRequest {
Assert.notNull(templateName, "templateName must not be null");
}
}
@@ -110,7 +110,7 @@ public final class MappingParameters {
private final Integer dims;
private final String searchAnalyzer;
private final double scalingFactor;
private final String similarity;
private final Similarity similarity;
private final boolean store;
private final TermVector termVector;
private final FieldType type;
@@ -330,8 +330,8 @@ public final class MappingParameters {
objectNode.put(FIELD_PARAM_POSITION_INCREMENT_GAP, positionIncrementGap);
}
if (!Similarity.Default.equals(similarity)) {
objectNode.put(FIELD_PARAM_SIMILARITY, similarity);
if (similarity != Similarity.Default) {
objectNode.put(FIELD_PARAM_SIMILARITY, similarity.toString());
}
if (termVector != TermVector.none) {
@@ -1,78 +0,0 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.index;
import java.time.Duration;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* @author Peter-Josef Meisch
* @since 5.1
*/
public record PutComponentTemplateRequest(String name, @Nullable Long version, @Nullable Boolean create,
@Nullable Duration masterTimeout, ComponentTemplateRequestData template) {
public PutComponentTemplateRequest {
Assert.notNull(name, "name must not be null");
Assert.notNull(template, "template must not be null");
}
public static Builder builder() {
return new Builder();
}
public static final class Builder {
@Nullable private String name;
@Nullable private Long version;
@Nullable private Boolean create;
@Nullable private Duration masterTimeout;
@Nullable private ComponentTemplateRequestData template;
public Builder withName(String name) {
this.name = name;
return this;
}
public Builder withVersion(Long version) {
this.version = version;
return this;
}
public Builder withCreate(Boolean create) {
this.create = create;
return this;
}
public Builder withMasterTimeout(Duration masterTimeout) {
this.masterTimeout = masterTimeout;
return this;
}
public Builder withTemplateData(ComponentTemplateRequestData template) {
this.template = template;
return this;
}
public PutComponentTemplateRequest build() {
Assert.notNull(name, "name must not be null");
Assert.notNull(template, "template must not be null");
return new PutComponentTemplateRequest(name, version, create, masterTimeout, template);
}
}
}
@@ -1,85 +0,0 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.index;
import java.util.List;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* @author Peter-Josef Meisch
* @since 5.1
*/
public record PutIndexTemplateRequest(String name, String[] indexPatterns, @Nullable Settings settings,
@Nullable Document mapping, @Nullable AliasActions aliasActions, List<String> composedOf) {
public static Builder builder() {
return new Builder();
}
public static class Builder {
@Nullable private String name;
@Nullable private String[] indexPatterns;
@Nullable private Settings settings;
@Nullable private Document mapping;
@Nullable AliasActions aliasActions;
@Nullable List<String> composedOf;
public Builder withName(String name) {
this.name = name;
return this;
}
public Builder withIndexPatterns(String... indexPatterns) {
this.indexPatterns = indexPatterns;
return this;
}
public Builder withSettings(Settings settings) {
this.settings = settings;
return this;
}
public Builder withMapping(Document mapping) {
this.mapping = mapping;
return this;
}
public Builder withAliasActions(AliasActions aliasActions) {
this.aliasActions = aliasActions;
return this;
}
public Builder withComposedOf(List<String> composedOf) {
this.composedOf = composedOf;
return this;
}
public PutIndexTemplateRequest build() {
Assert.notNull(name, "name must not be null");
Assert.notNull(indexPatterns, "indexPatterns must not be null");
Assert.isTrue(indexPatterns.length > 0, "indexPatterns must not be empty");
return new PutIndexTemplateRequest(name, indexPatterns, settings, mapping, aliasActions,
composedOf != null ? composedOf : List.of());
}
}
}
@@ -1,59 +0,0 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.index;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* @author Peter-Josef Meisch
* @since 5.1
*/
public record TemplateResponse(String name, @Nullable Long version, @Nullable TemplateResponseData templateData) {
public TemplateResponse {
Assert.notNull(name, "name must not be null");
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
@Nullable private String name;
@Nullable private Long version;
@Nullable private TemplateResponseData templateData;
public Builder withName(String name) {
this.name = name;
return this;
}
public Builder withVersion(Long version) {
this.version = version;
return this;
}
public Builder withTemplateData(TemplateResponseData templateData) {
this.templateData = templateData;
return this;
}
public TemplateResponse build() {
return new TemplateResponse(name, version, templateData);
}
}
}
@@ -1,72 +0,0 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.index;
import java.util.List;
import java.util.Map;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* @author Peter-Josef Meisch
* @since 5.1
*/
public record TemplateResponseData(@Nullable Document mapping, @Nullable Settings settings,
Map<String, AliasData> aliases, List<String> composedOf) {
public TemplateResponseData {
Assert.notNull(aliases, "aliases must not be null");
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
@Nullable private Document mapping;
@Nullable private Settings settings;
@Nullable private Map<String, AliasData> aliases;
@Nullable private List<String> composedOf;
public Builder withMapping(@Nullable Document mapping) {
this.mapping = mapping;
return this;
}
public Builder withSettings(@Nullable Settings settings) {
this.settings = settings;
return this;
}
public Builder withAliases(@Nullable Map<String, AliasData> aliases) {
this.aliases = aliases;
return this;
}
public Builder withComposedOf(@Nullable List<String> composedOf) {
this.composedOf = composedOf;
return this;
}
public TemplateResponseData build() {
return new TemplateResponseData(mapping, settings, aliases != null ? aliases : Map.of(),
composedOf != null ? composedOf : List.of());
}
}
}
@@ -133,14 +133,6 @@ public interface ElasticsearchPersistentEntity<T> extends PersistentEntity<T, El
}
}
/**
* @return the property annotated with {@link org.springframework.data.elasticsearch.annotations.IndexedIndexName} if
* it exists, otherwise null
* @since 5.1
*/
@Nullable
ElasticsearchPersistentProperty getIndexedIndexNameProperty();
/**
* returns the default settings for an index.
*
@@ -175,16 +167,4 @@ public interface ElasticsearchPersistentEntity<T> extends PersistentEntity<T, El
* @since 4.3
*/
Dynamic dynamic();
/**
* @return the storeIdInSource value from the document annotation
* @since 5.1
*/
boolean storeIdInSource();
/**
* @return the storeVersionInSource value from the document annotation.
* @since 5.1
*/
boolean storeVersionInSource();
}
@@ -39,12 +39,6 @@ public interface ElasticsearchPersistentProperty extends PersistentProperty<Elas
*/
String getFieldName();
/**
* @return {@literal true} if the field name comes from an explicit value in the field annotation
* @since 5.1
*/
boolean hasExplicitFieldName();
/**
* Returns whether the current property is a {@link SeqNoPrimaryTerm} property.
*
@@ -80,13 +74,6 @@ public interface ElasticsearchPersistentProperty extends PersistentProperty<Elas
*/
boolean storeNullValue();
/**
* @return true if empty values ({{@link String}}, or {{@link java.util.Collection}} or {{@link java.util.Map}})
* should be store in Elasticsearch.
* @since 5.1
*/
boolean storeEmptyValue();
/**
* @return {@literal true} if this is a GeoPoint property
* @since 4.1
@@ -111,13 +98,6 @@ public interface ElasticsearchPersistentProperty extends PersistentProperty<Elas
*/
boolean isCompletionProperty();
/**
* @return {@literal true} if this is a property annotated with
* {@link org.springframework.data.elasticsearch.annotations.IndexedIndexName}.
* @since 5.1
*/
boolean isIndexedIndexNameProperty();
/**
* calls {@link #getActualType()} but returns null when an exception is thrown
*
@@ -71,7 +71,6 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
private final Lazy<SettingsParameter> settingsParameter;
private @Nullable ElasticsearchPersistentProperty seqNoPrimaryTermProperty;
private @Nullable ElasticsearchPersistentProperty joinFieldProperty;
private @Nullable ElasticsearchPersistentProperty indexedIndexNameProperty;
private @Nullable Document.VersionType versionType;
private boolean createIndexAndMapping;
private final Dynamic dynamic;
@@ -83,9 +82,6 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
private final ConcurrentHashMap<String, Expression> indexNameExpressions = new ConcurrentHashMap<>();
private final Lazy<EvaluationContext> indexNameEvaluationContext = Lazy.of(this::getIndexNameEvaluationContext);
private final boolean storeIdInSource;
private final boolean storeVersionInSource;
public SimpleElasticsearchPersistentEntity(TypeInformation<T> typeInformation,
ContextConfiguration contextConfiguration) {
@@ -108,12 +104,8 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
this.versionType = document.versionType();
this.createIndexAndMapping = document.createIndex();
this.dynamic = document.dynamic();
this.storeIdInSource = document.storeIdInSource();
this.storeVersionInSource = document.storeVersionInSource();
} else {
this.dynamic = Dynamic.INHERIT;
this.storeIdInSource = true;
this.storeVersionInSource = true;
}
Routing routingAnnotation = AnnotatedElementUtils.findMergedAnnotation(clazz, Routing.class);
@@ -198,16 +190,6 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
return writeTypeHints;
}
@Override
public boolean storeIdInSource() {
return storeIdInSource;
}
@Override
public boolean storeVersionInSource() {
return storeVersionInSource;
}
@Override
public void addPersistentProperty(ElasticsearchPersistentProperty property) {
super.addPersistentProperty(property);
@@ -236,20 +218,6 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
}
}
if (property.isIndexedIndexNameProperty()) {
if (!property.getActualType().isAssignableFrom(String.class)) {
throw new MappingException(String.format("@IndexedIndexName annotation must be put on String property"));
}
if (indexedIndexNameProperty != null) {
throw new MappingException(
String.format("@IndexedIndexName annotation can only be put on one property in an entity"));
}
this.indexedIndexNameProperty = property;
}
Class<?> actualType = property.getActualTypeOrNull();
if (actualType == JoinField.class) {
ElasticsearchPersistentProperty joinProperty = this.joinFieldProperty;
@@ -312,12 +280,6 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
return joinFieldProperty;
}
@Nullable
@Override
public ElasticsearchPersistentProperty getIndexedIndexNameProperty() {
return indexedIndexNameProperty;
}
// region SpEL handling
/**
* resolves all the names in the IndexCoordinates object. If a name cannot be resolved, the original name is returned.
@@ -31,11 +31,9 @@ import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.GeoPointField;
import org.springframework.data.elasticsearch.annotations.GeoShapeField;
import org.springframework.data.elasticsearch.annotations.IndexedIndexName;
import org.springframework.data.elasticsearch.annotations.MultiField;
import org.springframework.data.elasticsearch.annotations.ValueConverter;
import org.springframework.data.elasticsearch.annotations.WriteOnlyProperty;
import org.springframework.data.elasticsearch.core.convert.AbstractPropertyValueConverter;
import org.springframework.data.elasticsearch.core.convert.DatePropertyValueConverter;
import org.springframework.data.elasticsearch.core.convert.DateRangePropertyValueConverter;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchDateConverter;
@@ -83,7 +81,6 @@ public class SimpleElasticsearchPersistentProperty extends
private final @Nullable String annotatedFieldName;
@Nullable private PropertyValueConverter propertyValueConverter;
private final boolean storeNullValue;
private final boolean storeEmptyValue;
public SimpleElasticsearchPersistentProperty(Property property,
PersistentEntity<?, ElasticsearchPersistentProperty> owner, SimpleTypeHolder simpleTypeHolder) {
@@ -108,7 +105,6 @@ public class SimpleElasticsearchPersistentProperty extends
initPropertyValueConverter();
storeNullValue = isField && getRequiredAnnotation(Field.class).storeNullValue();
storeEmptyValue = isField ? getRequiredAnnotation(Field.class).storeEmptyValue() : true;
}
@Override
@@ -137,13 +133,7 @@ public class SimpleElasticsearchPersistentProperty extends
return storeNullValue;
}
@Override
public boolean storeEmptyValue() {
return storeEmptyValue;
}
@Override
public boolean hasExplicitFieldName() {
protected boolean hasExplicitFieldName() {
return StringUtils.hasText(getAnnotatedFieldName());
}
@@ -252,11 +242,7 @@ public class SimpleElasticsearchPersistentProperty extends
}
propertyValueConverter = enumConstants[0];
} else {
if (AbstractPropertyValueConverter.class.isAssignableFrom(clazz)) {
propertyValueConverter = BeanUtils.instantiateClass(BeanUtils.getResolvableConstructor(clazz), this);
} else {
propertyValueConverter = BeanUtils.instantiateClass(clazz);
}
propertyValueConverter = BeanUtils.instantiateClass(clazz);
}
}
}
@@ -372,8 +358,4 @@ public class SimpleElasticsearchPersistentProperty extends
return getActualType() == Completion.class;
}
@Override
public boolean isIndexedIndexNameProperty() {
return isAnnotationPresent(IndexedIndexName.class);
}
}
@@ -22,7 +22,6 @@ import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -48,8 +47,6 @@ import org.springframework.util.Assert;
*/
public class BaseQuery implements Query {
private static final int DEFAULT_REACTIVE_BATCH_SIZE = 500;
@Nullable protected Sort sort;
protected Pageable pageable = DEFAULT_PAGE;
protected List<String> fields = new ArrayList<>();
@@ -74,14 +71,10 @@ public class BaseQuery implements Query {
protected List<RescorerQuery> rescorerQueries = new ArrayList<>();
@Nullable protected Boolean requestCache;
protected List<IdWithRouting> idsWithRouting = Collections.emptyList();
protected List<RuntimeField> runtimeFields = new ArrayList<>();
protected final List<RuntimeField> runtimeFields = new ArrayList<>();
@Nullable protected PointInTime pointInTime;
private boolean queryIsUpdatedByConverter = false;
@Nullable private Integer reactiveBatchSize = null;
@Nullable private Boolean allowNoIndices = null;
private EnumSet<IndicesOptions.WildcardStates> expandWildcards;
private List<DocValueField> docValueFields = new ArrayList<>();
private List<ScriptedField> scriptedFields = new ArrayList<>();
public BaseQuery() {}
@@ -112,19 +105,6 @@ public class BaseQuery implements Query {
this.requestCache = builder.getRequestCache();
this.idsWithRouting = builder.getIdsWithRouting();
this.pointInTime = builder.getPointInTime();
this.reactiveBatchSize = builder.getReactiveBatchSize();
this.allowNoIndices = builder.getAllowNoIndices();
this.expandWildcards = builder.getExpandWildcards();
this.docValueFields = builder.getDocValueFields();
this.scriptedFields = builder.getScriptedFields();
this.runtimeFields = builder.getRuntimeFields();
}
/**
* @since 5.1
*/
public void setSort(@Nullable Sort sort) {
this.sort = sort;
}
@Override
@@ -227,7 +207,7 @@ public class BaseQuery implements Query {
}
/**
* Set Ids for a multi-get request run with this query. Not used in any other searches.
* Set Ids for a multi-get request with on this query.
*
* @param ids list of id values
*/
@@ -256,7 +236,7 @@ public class BaseQuery implements Query {
}
/**
* Set Ids with routing values for a multi-get request run with this query. Not used in any other searches.
* Set Ids with routing values for a multi-get request set on this query.
*
* @param idsWithRouting list of id values, must not be {@literal null}
* @since 4.3
@@ -491,7 +471,6 @@ public class BaseQuery implements Query {
/**
* used internally. Not considered part of the API.
*
* @since 5.0
*/
public boolean queryIsUpdatedByConverter() {
@@ -500,55 +479,9 @@ public class BaseQuery implements Query {
/**
* used internally. Not considered part of the API.
*
* @since 5.0
*/
public void setQueryIsUpdatedByConverter(boolean queryIsUpdatedByConverter) {
this.queryIsUpdatedByConverter = queryIsUpdatedByConverter;
}
@Override
public Integer getReactiveBatchSize() {
return reactiveBatchSize != null ? reactiveBatchSize : DEFAULT_REACTIVE_BATCH_SIZE;
}
/**
* @since 5.1
*/
public void setReactiveBatchSize(Integer reactiveBatchSize) {
this.reactiveBatchSize = reactiveBatchSize;
}
@Nullable
public Boolean getAllowNoIndices() {
return allowNoIndices;
}
@Override
public EnumSet<IndicesOptions.WildcardStates> getExpandWildcards() {
return expandWildcards;
}
/**
* @since 5.1
*/
@Override
public List<DocValueField> getDocValueFields() {
return docValueFields;
}
/**
* @since 5.1
*/
public void setDocValueFields(List<DocValueField> docValueFields) {
Assert.notNull(docValueFields, "getDocValueFields must not be null");
this.docValueFields = docValueFields;
}
@Override
public List<ScriptedField> getScriptedFields() {
return scriptedFields;
}
}
@@ -20,7 +20,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import org.springframework.data.domain.Pageable;
@@ -46,32 +45,26 @@ public abstract class BaseQueryBuilder<Q extends BaseQuery, SELF extends BaseQue
private float minScore;
private final Collection<String> ids = new ArrayList<>();
@Nullable private String route;
private Query.SearchType searchType = Query.SearchType.QUERY_THEN_FETCH;
@Nullable private IndicesOptions indicesOptions;
protected Query.SearchType searchType = Query.SearchType.QUERY_THEN_FETCH;
@Nullable protected IndicesOptions indicesOptions;
private boolean trackScores;
@Nullable private String preference;
@Nullable private Integer maxResults;
@Nullable private HighlightQuery highlightQuery;
@Nullable protected HighlightQuery highlightQuery;
@Nullable private Boolean trackTotalHits;
@Nullable private Integer trackTotalHitsUpTo;
@Nullable private Duration scrollTime;
@Nullable private Duration timeout;
@Nullable protected Integer trackTotalHitsUpTo;
@Nullable protected Duration scrollTime;
@Nullable protected Duration timeout;
boolean explain = false;
@Nullable private List<Object> searchAfter;
@Nullable protected List<Object> searchAfter;
@Nullable private List<IndexBoost> indicesBoost;
protected final List<RescorerQuery> rescorerQueries = new ArrayList<>();
@Nullable private Boolean requestCache;
private final List<Query.IdWithRouting> idsWithRouting = new ArrayList<>();
private final List<RuntimeField> runtimeFields = new ArrayList<>();
@Nullable private Query.PointInTime pointInTime;
@Nullable private Boolean allowNoIndices;
private EnumSet<IndicesOptions.WildcardStates> expandWildcards = EnumSet.noneOf(IndicesOptions.WildcardStates.class);
@Nullable Integer reactiveBatchSize;
private final List<DocValueField> docValueFields = new ArrayList<>();
private final List<ScriptedField> scriptedFields = new ArrayList<>();
@Nullable protected Boolean requestCache;
protected final List<Query.IdWithRouting> idsWithRouting = new ArrayList<>();
protected final List<RuntimeField> runtimeFields = new ArrayList<>();
@Nullable protected Query.PointInTime pointInTime;
@Nullable
public Sort getSort() {
@@ -198,39 +191,6 @@ public abstract class BaseQueryBuilder<Q extends BaseQuery, SELF extends BaseQue
return pointInTime;
}
/**
* @since 5.1
*/
public Integer getReactiveBatchSize() {
return reactiveBatchSize;
}
/**
* @since 5.1
*/
@Nullable
public Boolean getAllowNoIndices() {
return allowNoIndices;
}
/**
* @since 5.1
*/
public EnumSet<IndicesOptions.WildcardStates> getExpandWildcards() {
return expandWildcards;
}
/**
* @since 5.1
*/
public List<DocValueField> getDocValueFields() {
return docValueFields;
}
public List<ScriptedField> getScriptedFields() {
return scriptedFields;
}
public SELF withPageable(Pageable pageable) {
this.pageable = pageable;
return self();
@@ -250,11 +210,6 @@ public abstract class BaseQueryBuilder<Q extends BaseQuery, SELF extends BaseQue
return self();
}
/**
* Set Ids for a multi-get request run with this query. Not used in any other searches.
*
* @param ids list of id values
*/
public SELF withIds(String... ids) {
this.ids.clear();
@@ -262,11 +217,6 @@ public abstract class BaseQueryBuilder<Q extends BaseQuery, SELF extends BaseQue
return self();
}
/**
* Set Ids for a multi-get request run with this query. Not used in any other searches.
*
* @param ids list of id values
*/
public SELF withIds(Collection<String> ids) {
Assert.notNull(ids, "ids must not be null");
@@ -382,12 +332,6 @@ public abstract class BaseQueryBuilder<Q extends BaseQuery, SELF extends BaseQue
return self();
}
/**
* Set Ids with routing values for a multi-get request run with this query. Not used in any other searches.
*
* @param idsWithRouting list of id values, must not be {@literal null}
* @since 4.3
*/
public SELF withIdsWithRouting(List<Query.IdWithRouting> idsWithRouting) {
Assert.notNull(idsWithRouting, "idsWithRouting must not be null");
@@ -431,47 +375,6 @@ public abstract class BaseQueryBuilder<Q extends BaseQuery, SELF extends BaseQue
return self();
}
/**
* @since 5.1
*/
public SELF withReactiveBatchSize(@Nullable Integer reactiveBatchSize) {
this.reactiveBatchSize = reactiveBatchSize;
return self();
}
public SELF witAllowNoIndices(@Nullable Boolean allowNoIndices) {
this.allowNoIndices = allowNoIndices;
return self();
}
public SELF withExpandWildcards(EnumSet<IndicesOptions.WildcardStates> expandWildcards) {
Assert.notNull(expandWildcards, "expandWildcards must not be null");
this.expandWildcards = expandWildcards;
return self();
}
/**
* @since 5.1
*/
public SELF withDocValueFields(List<DocValueField> docValueFields) {
Assert.notNull(docValueFields, "docValueFields must not be null");
this.docValueFields.clear();
this.docValueFields.addAll(docValueFields);
return self();
}
public SELF withScriptedField(ScriptedField scriptedField) {
Assert.notNull(scriptedField, "scriptedField must not be null");
this.scriptedFields.add(scriptedField);
return self();
}
public abstract Q build();
private SELF self() {
@@ -50,7 +50,6 @@ import org.springframework.util.StringUtils;
* @author Mohsin Husen
* @author Franck Marchand
* @author Peter-Josef Meisch
* @author Ezequiel Antúnez Camacho
*/
public class Criteria {
@@ -612,21 +611,6 @@ public class Criteria {
return this;
}
/**
* Add a {@link OperationKey#REGEXP} entry to the {@link #queryCriteriaEntries}.
*
* @param value the regexp value to match
* @return this object
* @since 5.1
*/
public Criteria regexp(String value) {
Assert.notNull(value, "value must not be null");
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.REGEXP, value));
return this;
}
// endregion
// region criteria entries - filter
@@ -970,11 +954,7 @@ public class Criteria {
/**
* @since 4.3
*/
NOT_EMPTY, //
/**
* @since 5.1
*/
REGEXP;
NOT_EMPTY;
/**
* @return true if this key does not have an associated value
@@ -1,35 +0,0 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.query;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Record defining a docvalue_field to be used in a query.
*
* @author Peter-Josef Meisch
* @since 5.1
*/
public record DocValueField(String field, @Nullable String format) {
public DocValueField {
Assert.notNull(field, "field must not be null");
}
public DocValueField(String field) {
this(field, null);
}
}
@@ -80,7 +80,7 @@ public class IndicesOptions {
}
public enum WildcardStates {
OPEN, CLOSED, HIDDEN, ALL, NONE;
OPEN, CLOSED, HIDDEN;
}
public enum Option {
@@ -18,7 +18,6 @@ package org.springframework.data.elasticsearch.core.query;
import java.time.Duration;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
@@ -449,40 +448,6 @@ public interface Query {
return null;
};
/**
* returns the number of documents that are requested when the reactive code does a batched search operation. This is
* the case when a query has no limit and no Pageable set.
*
* @return the batch size, defaults to 500 in {@link BaseQuery}
* @since 5.1
*/
default Integer getReactiveBatchSize() {
return 500;
}
/**
* @since 5.1
*/
@Nullable
Boolean getAllowNoIndices();
/**
* @since 5.1
*/
EnumSet<IndicesOptions.WildcardStates> getExpandWildcards();
/**
* @return a possible empty list of docvalue_field values to be set on the query.
* @since 5.1
*/
List<DocValueField> getDocValueFields();
/**
* @return the list of scripted fields for the query
* @since 5.1
*/
List<ScriptedField> getScriptedFields();
/**
* @since 4.3
*/
@@ -1,62 +0,0 @@
/*
* 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.
* 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.core.query;
import java.util.Map;
import org.springframework.lang.Nullable;
/**
* @author Peter-Josef Meisch
* @since 5.1
*/
public class SearchTemplateQuery extends BaseQuery {
@Nullable final private String id;
@Nullable final String source;
@Nullable final Map<String, Object> params;
public static SearchTemplateQueryBuilder builder() {
return new SearchTemplateQueryBuilder();
}
public SearchTemplateQuery(SearchTemplateQueryBuilder builder) {
super(builder);
this.id = builder.getId();
this.source = builder.getSource();
this.params = builder.getParams();
if (id == null && source == null) {
throw new IllegalArgumentException("Either id or source must be set");
}
}
@Nullable
public String getId() {
return id;
}
@Nullable
public String getSource() {
return source;
}
@Nullable
public Map<String, Object> getParams() {
return params;
}
}
@@ -1,69 +0,0 @@
/*
* 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.
* 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.core.query;
import org.springframework.lang.Nullable;
import java.util.Map;
/**
* @author Peter-Josef Meisch
* @since 5.1
*/
public class SearchTemplateQueryBuilder extends BaseQueryBuilder<SearchTemplateQuery, SearchTemplateQueryBuilder> {
@Nullable
private String id;
@Nullable String source;
@Nullable
Map<String, Object> params;
@Nullable
public String getId() {
return id;
}
@Nullable
public String getSource() {
return source;
}
@Nullable
public Map<String, Object> getParams() {
return params;
}
public SearchTemplateQueryBuilder withId(@Nullable String id) {
this.id = id;
return this;
}
public SearchTemplateQueryBuilder withSource(@Nullable String source) {
this.source = source;
return this;
}
public SearchTemplateQueryBuilder withParams(@Nullable Map<String, Object> params) {
this.params = params;
return this;
}
@Override
public SearchTemplateQuery build() {
return new SearchTemplateQuery(this);
}
}
@@ -1,50 +0,0 @@
/*
* 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.
* 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.core.script;
import reactor.core.publisher.Mono;
/**
* This interfaces defines the operations to access the
* <a href="https://www.elastic.co/guide/en/elasticsearch/reference/8.5/script-apis.html">Elasticsearch script API</a>.
*
* @author Peter-Josef Meisch
* @since 5.1
*/
public interface ReactiveScriptOperations {
/**
* Stores the given script in the Elasticsearch cluster.
*
* @return {{@literal true} if successful
*/
Mono<Boolean> putScript(Script script);
/**
* Gest the script with the given name.
*
* @param name the name of the script
* @return Script or null when a script with this name does not exist.
*/
Mono<Script> getScript(String name);
/**
* Deletes the script with the given name
*
* @param name the name of the script.
* @return true if the request was acknowledged by the cluster.
*/
Mono<Boolean> deleteScript(String name);
}
@@ -1,74 +0,0 @@
/*
* 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.
* 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.core.script;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* @author Peter-Josef Meisch
* @since 5.1
*/
public record Script(String id, String language, String source) {
public Script {
Assert.notNull(id, "id must not be null");
Assert.notNull(language, "language must not be null");
Assert.notNull(source, "source must not be null");
}
public static ScriptBuilder builder() {
return new ScriptBuilder();
}
public static final class ScriptBuilder {
@Nullable private String id;
@Nullable private String language;
@Nullable private String source;
private ScriptBuilder() {}
public ScriptBuilder withId(String id) {
Assert.notNull(id, "id must not be null");
this.id = id;
return this;
}
public ScriptBuilder withLanguage(String language) {
Assert.notNull(language, "language must not be null");
this.language = language;
return this;
}
public ScriptBuilder withSource(String source) {
Assert.notNull(source, "source must not be null");
this.source = source;
return this;
}
public Script build() {
return new Script(id, language, source);
}
}
}
@@ -1,51 +0,0 @@
/*
* 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.
* 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.core.script;
import org.springframework.lang.Nullable;
/**
* This interfaces defines the operations to access the
* <a href="https://www.elastic.co/guide/en/elasticsearch/reference/8.5/script-apis.html">Elasticsearch script API</a>.
*
* @author Peter-Josef Meisch
* @since 5.1
*/
public interface ScriptOperations {
/**
* Stores the given script in the Elasticsearch cluster.
*
* @return {{@literal true} if successful
*/
boolean putScript(Script script);
/**
* Gest the script with the given name.
*
* @param name the name of the script
* @return Script or null when a script with this name does not exist.
*/
@Nullable
Script getScript(String name);
/**
* Deletes the script with the given name
*
* @param name the name of the script.
* @return true if the request was acknowledged by the cluster.
*/
boolean deleteScript(String name);
}

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