Compare commits
161 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f4505c4778 | |||
| 9edae2725e | |||
| d4052c4951 | |||
| ce00928454 | |||
| 0f19400efe | |||
| c441503a56 | |||
| 7c364551db | |||
| 53a66c3f7c | |||
| 6cde9f9e78 | |||
| c03c790d46 | |||
| 41d91237d7 | |||
| fbcaeb10fd | |||
| 457a6e778e | |||
| 16f66e4c17 | |||
| bca4ba3fab | |||
| 88924903e8 | |||
| 7192d29095 | |||
| e0ca73b9b1 | |||
| 8285dd0cd0 | |||
| 6f73ac952b | |||
| 336b290e18 | |||
| e0286aa59a | |||
| 247be2b002 | |||
| e2ac3194b0 | |||
| 0c81b4b368 | |||
| 5fd35cb4c7 | |||
| af31cce875 | |||
| 23126ff3da | |||
| 0b3ecf6b23 | |||
| b96b5c2322 | |||
| 2a646e583d | |||
| 09c76b4694 | |||
| 1b59b31a72 | |||
| 2aba7a57fb | |||
| 15ca49a92e | |||
| b7088f8002 | |||
| 76f7ed5196 | |||
| e5445cf56f | |||
| 09a4e59e8d | |||
| 1e33e0f498 | |||
| e4df537382 | |||
| c1ab4d66e0 | |||
| 42cbab7ef6 | |||
| 9eed498fab | |||
| f16f70ff0f | |||
| 7494d344c5 | |||
| ca61901c1c | |||
| 323ccc9729 | |||
| d2960d764f | |||
| 8bb0a60450 | |||
| e33fe4d9fd | |||
| 0fd1b96ef3 | |||
| 30bc91c753 | |||
| 92806d2e11 | |||
| 2dd0a6771f | |||
| 79e0260f48 | |||
| 8d79a3efcf | |||
| d785c6c33c | |||
| c89368ce42 | |||
| c0781efbaa | |||
| d371404f90 | |||
| cc5b4fa635 | |||
| deae205fd4 | |||
| 796a5ebe34 | |||
| 2c63ba4097 | |||
| fe255c1bdc | |||
| 6f89e17451 | |||
| 0ad4fcb2eb | |||
| 4c3281f1eb | |||
| 303438ae63 | |||
| 254948d1c9 | |||
| 0bb239a674 | |||
| 3336ceade8 | |||
| e7398df948 | |||
| a7ed13db83 | |||
| 7db3dc1a37 | |||
| 0cabc3372e | |||
| ab2fba6581 | |||
| 45a0e2213f | |||
| 8c8c0eba4f | |||
| 90b366cf5f | |||
| c5d93c5cd2 | |||
| 2ac1085d03 | |||
| e0760e8567 | |||
| f8860c890a | |||
| 3a00ef4375 | |||
| ad6022f64c | |||
| da384e5eda | |||
| 8ab1a4f098 | |||
| 40972b21e0 | |||
| 85af54635d | |||
| 105607f6d6 | |||
| d0ee4efd87 | |||
| 9c900eca21 | |||
| 8cfe165754 | |||
| 30bfee24f0 | |||
| f339fda512 | |||
| b2a480df83 | |||
| f765ecac69 | |||
| 8bc06c9f41 | |||
| 03da6535cd | |||
| 4e6df37e2a | |||
| 58f1012874 | |||
| 84391ae62a | |||
| 010c0cb6ad | |||
| d561c91678 | |||
| 58bca88386 | |||
| 4782414596 | |||
| ab73c68ca9 | |||
| 2bd4ef75cf | |||
| 4ad002746e | |||
| d66f8a0650 | |||
| dfc68cd33b | |||
| cb08adc0c9 | |||
| 2a016f1aea | |||
| f9e4ac4d42 | |||
| 76d979cbba | |||
| 0c4f0d8af9 | |||
| 19ecf89455 | |||
| 2e9bef0edb | |||
| 13ab2b9e95 | |||
| 3500dad2bc | |||
| 2e5d2e0fd0 | |||
| a3e87a8525 | |||
| 843fd4db85 | |||
| ebac4c097c | |||
| 31b488d08f | |||
| db39b9e27c | |||
| ff5a6043f1 | |||
| 399820680d | |||
| a89fd89d12 | |||
| 28fe9ee25b | |||
| 6e3579d1fe | |||
| 83314880e4 | |||
| 98a8d1a5ac | |||
| 005d6a4d6f | |||
| 120eed02ee | |||
| b289d5f974 | |||
| eb816cce87 | |||
| 4dc8b2589a | |||
| 3f39f5d5b7 | |||
| 2f5773a5ff | |||
| e4c7b968e1 | |||
| 6634d0075a | |||
| f08c34ec5d | |||
| dd3d01eab6 | |||
| 3f2ab4b06a | |||
| 8da718e41a | |||
| 17a25cb0ad | |||
| 3bc01a4e5f | |||
| 1c549b739b | |||
| 863ac2f3f5 | |||
| 929d97f255 | |||
| 43b3035ab7 | |||
| 0367246512 | |||
| 36b3d0965e | |||
| 89125ae628 | |||
| 2f2ab7cd89 | |||
| 9b55afc64b | |||
| 6193f075a5 | |||
| a4bc815c68 |
+117
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2007-present 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.
|
||||
*/
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Properties;
|
||||
|
||||
public class MavenWrapperDownloader {
|
||||
|
||||
private static final String WRAPPER_VERSION = "0.5.6";
|
||||
/**
|
||||
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
|
||||
*/
|
||||
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
|
||||
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
|
||||
|
||||
/**
|
||||
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
|
||||
* use instead of the default one.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
|
||||
".mvn/wrapper/maven-wrapper.properties";
|
||||
|
||||
/**
|
||||
* Path where the maven-wrapper.jar will be saved to.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_JAR_PATH =
|
||||
".mvn/wrapper/maven-wrapper.jar";
|
||||
|
||||
/**
|
||||
* Name of the property which should be used to override the default download url for the wrapper.
|
||||
*/
|
||||
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("- Downloader started");
|
||||
File baseDirectory = new File(args[0]);
|
||||
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
|
||||
|
||||
// If the maven-wrapper.properties exists, read it and check if it contains a custom
|
||||
// wrapperUrl parameter.
|
||||
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
|
||||
String url = DEFAULT_DOWNLOAD_URL;
|
||||
if(mavenWrapperPropertyFile.exists()) {
|
||||
FileInputStream mavenWrapperPropertyFileInputStream = null;
|
||||
try {
|
||||
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
|
||||
Properties mavenWrapperProperties = new Properties();
|
||||
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
|
||||
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
|
||||
} finally {
|
||||
try {
|
||||
if(mavenWrapperPropertyFileInputStream != null) {
|
||||
mavenWrapperPropertyFileInputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore ...
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading from: " + url);
|
||||
|
||||
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
|
||||
if(!outputFile.getParentFile().exists()) {
|
||||
if(!outputFile.getParentFile().mkdirs()) {
|
||||
System.out.println(
|
||||
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
|
||||
try {
|
||||
downloadFileFromURL(url, outputFile);
|
||||
System.out.println("Done");
|
||||
System.exit(0);
|
||||
} catch (Throwable e) {
|
||||
System.out.println("- Error downloading");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
|
||||
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
|
||||
String username = System.getenv("MVNW_USERNAME");
|
||||
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(username, password);
|
||||
}
|
||||
});
|
||||
}
|
||||
URL website = new URL(urlString);
|
||||
ReadableByteChannel rbc;
|
||||
rbc = Channels.newChannel(website.openStream());
|
||||
FileOutputStream fos = new FileOutputStream(destination);
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
fos.close();
|
||||
rbc.close();
|
||||
}
|
||||
|
||||
}
|
||||
BIN
Binary file not shown.
+3
-1
@@ -1 +1,3 @@
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip
|
||||
#Tue Feb 22 13:55:13 CET 2022
|
||||
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.8.4/apache-maven-3.8.4-bin.zip
|
||||
|
||||
Vendored
+31
-50
@@ -1,9 +1,15 @@
|
||||
def p = [:]
|
||||
node {
|
||||
checkout scm
|
||||
p = readProperties interpolate: true, file: 'ci/pipeline.properties'
|
||||
}
|
||||
|
||||
pipeline {
|
||||
agent none
|
||||
|
||||
triggers {
|
||||
pollSCM 'H/10 * * * *'
|
||||
upstream(upstreamProjects: "spring-data-commons/master", threshold: hudson.model.Result.SUCCESS)
|
||||
upstream(upstreamProjects: "spring-data-commons/2.5.x", threshold: hudson.model.Result.SUCCESS)
|
||||
}
|
||||
|
||||
options {
|
||||
@@ -12,10 +18,10 @@ pipeline {
|
||||
}
|
||||
|
||||
stages {
|
||||
stage("test: baseline (jdk8)") {
|
||||
stage("test: baseline (main)") {
|
||||
when {
|
||||
anyOf {
|
||||
branch 'master'
|
||||
branch '4.2.x'
|
||||
not { triggeredBy 'UpstreamCause' }
|
||||
}
|
||||
}
|
||||
@@ -25,13 +31,14 @@ pipeline {
|
||||
options { timeout(time: 30, unit: 'MINUTES') }
|
||||
|
||||
environment {
|
||||
DOCKER_HUB = credentials('hub.docker.com-springbuildmaster')
|
||||
DOCKER_HUB = credentials("${p['docker.credentials']}")
|
||||
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
|
||||
}
|
||||
|
||||
steps {
|
||||
script {
|
||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
||||
docker.image('adoptopenjdk/openjdk8:latest').inside('-u root -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/tmp/jenkins-home') {
|
||||
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"
|
||||
@@ -44,27 +51,28 @@ pipeline {
|
||||
stage("Test other configurations") {
|
||||
when {
|
||||
allOf {
|
||||
branch 'master'
|
||||
branch '4.2.x'
|
||||
not { triggeredBy 'UpstreamCause' }
|
||||
}
|
||||
}
|
||||
parallel {
|
||||
stage("test: baseline (jdk11)") {
|
||||
stage("test: baseline (next)") {
|
||||
agent {
|
||||
label 'data'
|
||||
}
|
||||
options { timeout(time: 30, unit: 'MINUTES') }
|
||||
|
||||
environment {
|
||||
DOCKER_HUB = credentials('hub.docker.com-springbuildmaster')
|
||||
DOCKER_HUB = credentials("${p['docker.credentials']}")
|
||||
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
|
||||
}
|
||||
|
||||
steps {
|
||||
script {
|
||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
||||
docker.image('adoptopenjdk/openjdk11:latest').inside('-u root -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/tmp/jenkins-home') {
|
||||
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
|
||||
docker.image(p['docker.java.11.image']).inside(p['docker.java.inside.docker']) {
|
||||
sh "docker login --username ${DOCKER_HUB_USR} --password ${DOCKER_HUB_PSW}"
|
||||
sh 'PROFILE=java11 ci/verify.sh'
|
||||
sh 'PROFILE=none ci/verify.sh'
|
||||
sh "ci/clean.sh"
|
||||
}
|
||||
}
|
||||
@@ -72,22 +80,23 @@ pipeline {
|
||||
}
|
||||
}
|
||||
|
||||
stage("test: baseline (jdk15)") {
|
||||
stage("test: baseline (LTS)") {
|
||||
agent {
|
||||
label 'data'
|
||||
}
|
||||
options { timeout(time: 30, unit: 'MINUTES') }
|
||||
|
||||
environment {
|
||||
DOCKER_HUB = credentials('hub.docker.com-springbuildmaster')
|
||||
DOCKER_HUB = credentials("${p['docker.credentials']}")
|
||||
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
|
||||
}
|
||||
|
||||
steps {
|
||||
script {
|
||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
||||
docker.image('adoptopenjdk/openjdk15:latest').inside('-u root -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/tmp/jenkins-home') {
|
||||
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
|
||||
docker.image(p['docker.java.lts.image']).inside(p['docker.java.inside.docker']) {
|
||||
sh "docker login --username ${DOCKER_HUB_USR} --password ${DOCKER_HUB_PSW}"
|
||||
sh 'PROFILE=java11 ci/verify.sh'
|
||||
sh 'PROFILE=none ci/verify.sh'
|
||||
sh "ci/clean.sh"
|
||||
}
|
||||
}
|
||||
@@ -100,7 +109,7 @@ pipeline {
|
||||
stage('Release to artifactory') {
|
||||
when {
|
||||
anyOf {
|
||||
branch 'master'
|
||||
branch '4.2.x'
|
||||
not { triggeredBy 'UpstreamCause' }
|
||||
}
|
||||
}
|
||||
@@ -110,14 +119,14 @@ pipeline {
|
||||
options { timeout(time: 20, unit: 'MINUTES') }
|
||||
|
||||
environment {
|
||||
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
|
||||
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
|
||||
}
|
||||
|
||||
steps {
|
||||
script {
|
||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
||||
docker.image('adoptopenjdk/openjdk8:latest').inside('-v $HOME:/tmp/jenkins-home') {
|
||||
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -Pci,artifactory -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch-non-root ' +
|
||||
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} " +
|
||||
@@ -130,34 +139,6 @@ pipeline {
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Publish documentation') {
|
||||
when {
|
||||
branch 'master'
|
||||
}
|
||||
agent {
|
||||
label 'data'
|
||||
}
|
||||
options { timeout(time: 20, unit: 'MINUTES') }
|
||||
|
||||
environment {
|
||||
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
|
||||
}
|
||||
|
||||
steps {
|
||||
script {
|
||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
||||
docker.image('adoptopenjdk/openjdk8:latest').inside('-v $HOME:/tmp/jenkins-home') {
|
||||
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -Pci,distribute -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.distribution-repository=temp-private-local " +
|
||||
'-Dmaven.test.skip=true clean deploy -U -B'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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.
|
||||
+2
-2
@@ -114,7 +114,7 @@ Add the Maven dependency:
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>${version}.RELEASE</version>
|
||||
<version>${version}</version>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
@@ -149,7 +149,7 @@ If you'd rather like the latest snapshots of the upcoming major version, use our
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>${version}.BUILD-SNAPSHOT</version>
|
||||
<version>${version}-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<repository>
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@
|
||||
set -euo pipefail
|
||||
|
||||
MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" \
|
||||
./mvnw clean -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch
|
||||
./mvnw -s settings.xml clean -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Java versions
|
||||
java.main.tag=8u332-b09-jdk
|
||||
java.11.tag=11.0.15_10-jdk
|
||||
java.15.tag=15.0.2_7-jdk-hotspot
|
||||
java.lts.tag=17.0.3_7-jdk
|
||||
|
||||
# Docker container images - standard
|
||||
docker.java.main.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.main.tag}
|
||||
docker.java.11.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.11.tag}
|
||||
docker.java.15.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/adoptopenjdk:${java.15.tag}
|
||||
docker.java.lts.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.lts.tag}
|
||||
|
||||
# Supported versions of MongoDB
|
||||
docker.mongodb.4.0.version=4.0.28
|
||||
docker.mongodb.4.4.version=4.4.12
|
||||
docker.mongodb.5.0.version=5.0.6
|
||||
|
||||
# Supported versions of Redis
|
||||
docker.redis.6.version=6.2.6
|
||||
|
||||
# Supported versions of Cassandra
|
||||
docker.cassandra.3.version=3.11.12
|
||||
|
||||
# Docker environment settings
|
||||
docker.java.inside.basic=-v $HOME:/tmp/jenkins-home
|
||||
docker.java.inside.docker=-u root -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/tmp/jenkins-home
|
||||
|
||||
# Credentials
|
||||
docker.registry=
|
||||
docker.credentials=hub.docker.com-springbuildmaster
|
||||
artifactory.credentials=02bd1690-b54f-4c9f-819d-a77cb7a9822c
|
||||
+1
-1
@@ -6,5 +6,5 @@ mkdir -p /tmp/jenkins-home/.m2/spring-data-elasticsearch
|
||||
chown -R 1001:1001 .
|
||||
|
||||
MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" \
|
||||
./mvnw \
|
||||
./mvnw -s settings.xml \
|
||||
-P${PROFILE} clean dependency:list verify -Dsort -U -B -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch
|
||||
@@ -8,7 +8,7 @@
|
||||
# "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
|
||||
# http://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
|
||||
@@ -19,7 +19,7 @@
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven2 Start Up Batch script
|
||||
# Maven Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
@@ -114,7 +114,6 @@ if $mingw ; then
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
# TODO classpath?
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
@@ -212,7 +211,11 @@ else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||
fi
|
||||
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||
else
|
||||
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||
fi
|
||||
while IFS="=" read key value; do
|
||||
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
||||
esac
|
||||
@@ -221,22 +224,38 @@ else
|
||||
echo "Downloading from: $jarUrl"
|
||||
fi
|
||||
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if $cygwin; then
|
||||
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
|
||||
fi
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found wget ... using wget"
|
||||
fi
|
||||
wget "$jarUrl" -O "$wrapperJarPath"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget "$jarUrl" -O "$wrapperJarPath"
|
||||
else
|
||||
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
|
||||
fi
|
||||
elif command -v curl > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found curl ... using curl"
|
||||
fi
|
||||
curl -o "$wrapperJarPath" "$jarUrl"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl -o "$wrapperJarPath" "$jarUrl" -f
|
||||
else
|
||||
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
|
||||
fi
|
||||
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Falling back to using Java to download"
|
||||
fi
|
||||
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaClass=`cygpath --path --windows "$javaClass"`
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
@@ -277,6 +296,11 @@ if $cygwin; then
|
||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||
fi
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
exec "$JAVACMD" \
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM https://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@@ -18,7 +18,7 @@
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven2 Start Up Batch script
|
||||
@REM Maven Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@@ -26,7 +26,7 @@
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@@ -37,7 +37,7 @@
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
|
||||
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
@@ -120,23 +120,44 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
|
||||
FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
|
||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||
|
||||
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
echo Found %WRAPPER_JAR%
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Found %WRAPPER_JAR%
|
||||
)
|
||||
) else (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %DOWNLOAD_URL%
|
||||
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
if not "%MVNW_REPOURL%" == "" (
|
||||
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||
)
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %DOWNLOAD_URL%
|
||||
)
|
||||
|
||||
powershell -Command "&{"^
|
||||
"$webclient = new-object System.Net.WebClient;"^
|
||||
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||
"}"^
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
|
||||
"}"
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||
@REM work with both Windows and non-Windows executions.
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>4.2.0-M3</version>
|
||||
<version>4.2.12</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>2.5.0-M3</version>
|
||||
<version>2.5.12</version>
|
||||
</parent>
|
||||
|
||||
<name>Spring Data Elasticsearch</name>
|
||||
@@ -19,10 +19,10 @@
|
||||
|
||||
<properties>
|
||||
<commonslang>2.6</commonslang>
|
||||
<elasticsearch>7.10.2</elasticsearch>
|
||||
<log4j>2.13.3</log4j>
|
||||
<elasticsearch>7.12.1</elasticsearch>
|
||||
<log4j>2.17.0</log4j>
|
||||
<netty>4.1.52.Final</netty>
|
||||
<springdata.commons>2.5.0-M3</springdata.commons>
|
||||
<springdata.commons>2.5.12</springdata.commons>
|
||||
<testcontainers>1.15.1</testcontainers>
|
||||
<java-module-name>spring.data.elasticsearch</java-module-name>
|
||||
</properties>
|
||||
@@ -152,6 +152,12 @@
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>transport</artifactId>
|
||||
<version>${elasticsearch}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -159,6 +165,12 @@
|
||||
<groupId>org.elasticsearch.plugin</groupId>
|
||||
<artifactId>transport-netty4-client</artifactId>
|
||||
<version>${elasticsearch}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -173,6 +185,7 @@
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>log4j-over-slf4j</artifactId>
|
||||
@@ -198,6 +211,21 @@
|
||||
</dependency>
|
||||
|
||||
<!-- CDI -->
|
||||
<!-- Dependency order required to build against CDI 1.0 and test with CDI 2.0 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jcdi_2.0_spec</artifactId>
|
||||
<version>1.0.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.interceptor</groupId>
|
||||
<artifactId>javax.interceptor-api</artifactId>
|
||||
<version>1.2.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.enterprise</groupId>
|
||||
<artifactId>cdi-api</artifactId>
|
||||
@@ -206,6 +234,20 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
<version>${javax-annotation-api}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.openwebbeans</groupId>
|
||||
<artifactId>openwebbeans-se</artifactId>
|
||||
<version>${webbeans}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
@@ -226,23 +268,41 @@
|
||||
<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.apache.openwebbeans.test</groupId>
|
||||
<artifactId>cditest-owb</artifactId>
|
||||
<version>1.2.8</version>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>999999</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jcdi_1.0_spec</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-atinject_1.0_spec</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>org.apache.openwebbeans.test</groupId>
|
||||
<artifactId>cditest-owb</artifactId>
|
||||
<version>1.2.8</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jcdi_1.0_spec</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-atinject_1.0_spec</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.skyscreamer</groupId>
|
||||
<artifactId>jsonassert</artifactId>
|
||||
@@ -419,7 +479,9 @@
|
||||
</module>
|
||||
</checkstyleRules>
|
||||
<includes>**/*</includes>
|
||||
<excludes>.git/**/*,target/**/*,**/target/**/*,.idea/**/*,**/spring.schemas,**/*.svg,mvnw,mvnw.cmd,**/*.policy</excludes>
|
||||
<excludes>
|
||||
.git/**/*,target/**/*,**/target/**/*,.idea/**/*,**/spring.schemas,**/*.svg,mvnw,mvnw.cmd,**/*.policy
|
||||
</excludes>
|
||||
<sourceDirectories>./</sourceDirectories>
|
||||
</configuration>
|
||||
</plugin>
|
||||
@@ -432,8 +494,13 @@
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-libs-milestone</id>
|
||||
<url>https://repo.spring.io/libs-milestone</url>
|
||||
<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>
|
||||
|
||||
@@ -442,11 +509,6 @@
|
||||
<id>spring-plugins-release</id>
|
||||
<url>https://repo.spring.io/plugins-release</url>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>bintray-plugins</id>
|
||||
<name>bintray-plugins</name>
|
||||
<url>https://jcenter.bintray.com</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
|
||||
https://maven.apache.org/xsd/settings-1.0.0.xsd">
|
||||
|
||||
<servers>
|
||||
<server>
|
||||
<id>spring-plugins-release</id>
|
||||
<username>${env.ARTIFACTORY_USR}</username>
|
||||
<password>${env.ARTIFACTORY_PSW}</password>
|
||||
</server>
|
||||
<server>
|
||||
<id>spring-libs-snapshot</id>
|
||||
<username>${env.ARTIFACTORY_USR}</username>
|
||||
<password>${env.ARTIFACTORY_PSW}</password>
|
||||
</server>
|
||||
<server>
|
||||
<id>spring-libs-milestone</id>
|
||||
<username>${env.ARTIFACTORY_USR}</username>
|
||||
<password>${env.ARTIFACTORY_PSW}</password>
|
||||
</server>
|
||||
<server>
|
||||
<id>spring-libs-release</id>
|
||||
<username>${env.ARTIFACTORY_USR}</username>
|
||||
<password>${env.ARTIFACTORY_PSW}</password>
|
||||
</server>
|
||||
</servers>
|
||||
|
||||
</settings>
|
||||
@@ -34,7 +34,7 @@ The following table shows the Elasticsearch versions that are used by Spring Dat
|
||||
[cols="^,^,^,^,^",options="header"]
|
||||
|===
|
||||
| Spring Data Release Train | Spring Data Elasticsearch | Elasticsearch | Spring Framework | Spring Boot
|
||||
| 2021.0 (Pascal)footnote:cdv[Currently in development] | 4.2.xfootnote:cdv[] | 7.10.2 | 5.3.xfootnote:cdv[] | 2.4.xfootnote:cdv[]
|
||||
| 2021.0 (Pascal) | 4.2.1 | 7.12.1 | 5.3.7 | 2.5.x
|
||||
| 2020.0 (Ockham) | 4.1.x | 7.9.3 | 5.3.2 | 2.4.x
|
||||
| Neumann | 4.0.x | 7.6.2 | 5.2.12 |2.3.x
|
||||
| Moore | 3.2.x |6.8.12 | 5.2.12| 2.2.x
|
||||
|
||||
@@ -30,11 +30,15 @@ public class Person implements Persistable<Long> {
|
||||
@Id private Long id;
|
||||
private String lastName;
|
||||
private String firstName;
|
||||
@CreatedDate
|
||||
@Field(type = FieldType.Date, format = DateFormat.basic_date_time)
|
||||
private Instant createdDate;
|
||||
@CreatedBy
|
||||
private String createdBy
|
||||
@Field(type = FieldType.Date, format = DateFormat.basic_date_time)
|
||||
@LastModifiedDate
|
||||
private Instant lastModifiedDate;
|
||||
@LastModifiedBy
|
||||
private String lastModifiedBy;
|
||||
|
||||
public Long getId() { // <.>
|
||||
|
||||
@@ -8,7 +8,7 @@ Spring Data Elasticsearch operates upon an Elasticsearch client that is connecte
|
||||
[[elasticsearch.clients.transport]]
|
||||
== Transport Client
|
||||
|
||||
WARNING: The well known `TransportClient` is deprecated as of Elasticsearch 7 and will be removed in Elasticsearch 8. (https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/transport-client.html[see the Elasticsearch documentation]). Spring Data Elasticsearch will support the `TransportClient` as long as it is available in the used
|
||||
WARNING: The `TransportClient` is deprecated as of Elasticsearch 7 and will be removed in Elasticsearch 8. (https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/transport-client.html[see the Elasticsearch documentation]). Spring Data Elasticsearch will support the `TransportClient` as long as it is available in the used
|
||||
Elasticsearch <<elasticsearch.versions,version>> but has deprecated the classes using it since version 4.0.
|
||||
|
||||
We strongly recommend to use the <<elasticsearch.clients.rest>> instead of the `TransportClient`.
|
||||
@@ -40,7 +40,8 @@ public class TransportClientConfig extends ElasticsearchConfigurationSupport {
|
||||
|
||||
// ...
|
||||
|
||||
IndexRequest request = new IndexRequest("spring-data", "elasticsearch", randomID())
|
||||
IndexRequest request = new IndexRequest("spring-data")
|
||||
.id(randomID())
|
||||
.source(someObject);
|
||||
|
||||
IndexResponse response = client.index(request);
|
||||
@@ -85,11 +86,12 @@ public class RestClientConfig extends AbstractElasticsearchConfiguration {
|
||||
|
||||
// ...
|
||||
|
||||
IndexRequest request = new IndexRequest("spring-data", "elasticsearch", randomID())
|
||||
IndexRequest request = new IndexRequest("spring-data")
|
||||
.id(randomID())
|
||||
.source(singletonMap("feature", "high-level-rest-client"))
|
||||
.setRefreshPolicy(IMMEDIATE);
|
||||
|
||||
IndexResponse response = highLevelClient.index(request);
|
||||
IndexResponse response = highLevelClient.index(request,RequestOptions.DEFAULT);
|
||||
----
|
||||
<1> Use the builder to provide cluster addresses, set default `HttpHeaders` or enable SSL.
|
||||
<2> Create the RestHighLevelClient.
|
||||
@@ -188,6 +190,29 @@ ClientConfiguration clientConfiguration = ClientConfiguration.builder()
|
||||
|
||||
IMPORTANT: Adding a Header supplier as shown in above example allows to inject headers that may change over the time, like authentication JWT tokens. If this is used in the reactive setup, the supplier function *must not* block!
|
||||
|
||||
=== Elasticsearch 7 compatibility headers
|
||||
|
||||
When using Spring Data Elasticsearch 4 - which uses the Elasticsearch 7 client libraries - and accessing an Elasticsearch cluster that is running on version 8, it is necessary to set the compatibility headers
|
||||
https://www.elastic.co/guide/en/elasticsearch/reference/8.0/rest-api-compatibility.html[see Elasticserach documentation].
|
||||
This should be done using a header supplier like shown above:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
ClientConfigurationBuilder configurationBuilder = new ClientConfigurationBuilder();
|
||||
configurationBuilder //
|
||||
// ...
|
||||
.withHeaders(() -> {
|
||||
HttpHeaders defaultCompatibilityHeaders = new HttpHeaders();
|
||||
defaultCompatibilityHeaders.add("Accept",
|
||||
"application/vnd.elasticsearch+json;compatible-with=7");
|
||||
defaultCompatibilityHeaders.add("Content-Type",
|
||||
"application/vnd.elasticsearch+json;compatible-with=7");
|
||||
return defaultCompatibilityHeaders;
|
||||
});
|
||||
----
|
||||
====
|
||||
|
||||
[[elasticsearch.clients.logging]]
|
||||
== Client Logging
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@ This section describes breaking changes from version 4.1.x to 4.2.x and how remo
|
||||
[[elasticsearch-migration-guide-4.1-4.2.deprecations]]
|
||||
== Deprecations
|
||||
|
||||
=== @Document parameters
|
||||
|
||||
The parameters of the `@Document` annotation that are relevant for the index settings (`useServerConfiguration`, `shards`. `replicas`, `refreshIntervall` and `indexStoretype`) have been moved to the `@Setting` annotation. Use in `@Document` is still possible but deprecated.
|
||||
|
||||
[[elasticsearch-migration-guide-4.1-4.2.removal]]
|
||||
== Removals
|
||||
|
||||
@@ -53,3 +57,10 @@ Previously the reactive code initialized this to `IMMEDIATE`, now reactive and n
|
||||
==== delete methods that take a Query
|
||||
|
||||
The reactive methods previously returned a `Mono<Long>` with the number of deleted documents, the non reactive versions were void. They now return a `Mono<ByQueryResponse>` which contains much more detailed information about the deleted documents and errors that might have occurred.
|
||||
|
||||
==== multiget methods
|
||||
|
||||
The implementations of _multiget_ previousl only returned the found entities in a `List<T>` for non-reactive implementations and in a `Flux<T>` for reactive implementations. If the request contained ids that were not found, the information that these are missing was not available. The user needed to compare the returned ids to the requested ones to find
|
||||
which ones were missing.
|
||||
|
||||
Now the `multiget` methods return a `MultiGetItem` for every requested id. This contains information about failures (like non existing indices) and the information if the item existed (then it is contained in the `MultiGetItem) or not.
|
||||
|
||||
@@ -4,6 +4,48 @@
|
||||
This chapter covers additional support for Elasticsearch operations that cannot be directly accessed via the repository interface.
|
||||
It is recommended to add those operations as custom implementation as described in <<repositories.custom-implementations>> .
|
||||
|
||||
[[elasticsearc.misc.index.settings]]
|
||||
== Index settings
|
||||
|
||||
When creating Elasticsearch indices with Spring Data Elasticsearch different index settings can be defined by using the `@Setting` annotation. The following arguments are available:
|
||||
|
||||
* `useServerConfiguration` does not send any settings parameters, so the Elasticsearch server configuration determines them.
|
||||
* `settingPath` refers to a JSON file defining the settings that must be resolvable in the classpath
|
||||
* `shards` the number of shards to use, defaults to _1_
|
||||
* `replicas` the number of replicas, defaults to _1_
|
||||
* `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):
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@Document(indexName = "entities")
|
||||
@Setting(
|
||||
sortFields = { "secondField", "firstField" }, <.>
|
||||
sortModes = { Setting.SortMode.max, Setting.SortMode.min }, <.>
|
||||
sortOrders = { Setting.SortOrder.desc, Setting.SortOrder.asc },
|
||||
sortMissingValues = { Setting.SortMissing._last, Setting.SortMissing._first })
|
||||
class Entity {
|
||||
@Nullable
|
||||
@Id private String id;
|
||||
|
||||
@Nullable
|
||||
@Field(name = "first_field", type = FieldType.Keyword)
|
||||
private String firstField;
|
||||
|
||||
@Nullable @Field(name = "second_field", type = FieldType.Keyword)
|
||||
private String secondField;
|
||||
|
||||
// getter and setter...
|
||||
}
|
||||
----
|
||||
<.> when defining sort fields, use the name of the Java property (_firstField_), not the name that might be defined for Elasticsearch (_first_field_)
|
||||
<.> `sortModes`, `sortOrders` and `sortMissingValues` are optional, but if they are set, the number of entries must match the number of `sortFields` elements
|
||||
====
|
||||
|
||||
[[elasticsearch.misc.filter]]
|
||||
== Filter Builder
|
||||
|
||||
@@ -20,7 +62,7 @@ SearchQuery searchQuery = new NativeSearchQueryBuilder()
|
||||
.withQuery(matchAllQuery())
|
||||
.withFilter(boolFilter().must(termFilter("id", documentId)))
|
||||
.build();
|
||||
|
||||
|
||||
Page<SampleEntity> sampleEntities = operations.searchForPage(searchQuery, SampleEntity.class, index);
|
||||
----
|
||||
====
|
||||
@@ -31,6 +73,7 @@ Page<SampleEntity> sampleEntities = operations.searchForPage(searchQuery, Sample
|
||||
Elasticsearch has a scroll API for getting big result set in chunks.
|
||||
This is internally used by Spring Data Elasticsearch to provide the implementations of the `<T> SearchHitsIterator<T> SearchOperations.searchForStream(Query query, Class<T> clazz, IndexCoordinates index)` method.
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
IndexCoordinates index = IndexCoordinates.of("sample-index");
|
||||
@@ -50,9 +93,11 @@ while (stream.hasNext()) {
|
||||
|
||||
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 `ElasticsearchRestTemplate` can be used:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
|
||||
@@ -77,10 +122,12 @@ while (scroll.hasSearchHits()) {
|
||||
}
|
||||
template.searchScrollClear(scrollId);
|
||||
----
|
||||
====
|
||||
|
||||
To use the Scroll API with repository methods, the return type must defined as `Stream` in the Elasticsearch Repository.
|
||||
The implementation of the method will then use the scroll methods from the ElasticsearchTemplate.
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
interface SampleEntityRepository extends Repository<SampleEntity, String> {
|
||||
@@ -89,6 +136,7 @@ interface SampleEntityRepository extends Repository<SampleEntity, String> {
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
[[elasticsearch.misc.sorts]]
|
||||
== Sort options
|
||||
@@ -97,7 +145,9 @@ In addition to the default sort options described <<repositories.paging-and-sort
|
||||
|
||||
If the class to be retrieved has a `GeoPoint` property named _location_, the following `Sort` would sort the results by distance to the given point:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
Sort.by(new GeoDistanceOrder("location", new GeoPoint(48.137154, 11.5761247)))
|
||||
----
|
||||
====
|
||||
|
||||
@@ -36,14 +36,6 @@ The most important attributes are:
|
||||
This can contain a SpEL template expression like `"log-#{T(java.time.LocalDate).now().toString()}"`
|
||||
** `type`: [line-through]#the mapping type.
|
||||
If not set, the lowercased simple name of the class is used.# (deprecated since version 4.0)
|
||||
** `shards`: the number of shards for the index.
|
||||
** `replicas`: the number of replicas for the index.
|
||||
** `refreshIntervall`: Refresh interval for the index.
|
||||
Used for index creation.
|
||||
Default value is _"1s"_.
|
||||
** `indexStoreType`: Index storage type for the index.
|
||||
Used for index creation.
|
||||
Default value is _"fs"_.
|
||||
** `createIndex`: flag whether to create an index on repository bootstrapping.
|
||||
Default value is _true_.
|
||||
See <<elasticsearch.repositories.autocreation>>
|
||||
@@ -56,21 +48,60 @@ Default value is _EXTERNAL_.
|
||||
Constructor arguments are mapped by name to the key values in the retrieved Document.
|
||||
* `@Field`: Applied at the field level and defines properties of the field, most of the attributes map to the respective https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html[Elasticsearch Mapping] definitions (the following list is not complete, check the annotation Javadoc for a complete reference):
|
||||
** `name`: The name of the field as it will be represented in the Elasticsearch document, if not set, the Java field name is used.
|
||||
** `type`: the field type, can be one of _Text, Keyword, Long, Integer, Short, Byte, Double, Float, Half_Float, Scaled_Float, Date, Date_Nanos, Boolean, Binary, Integer_Range, Float_Range, Long_Range, Double_Range, Date_Range, Ip_Range, Object, Nested, Ip, TokenCount, Percolator, Flattened, Search_As_You_Type_.
|
||||
** `type`: The field type, can be one of _Text, Keyword, Long, Integer, Short, Byte, Double, Float, Half_Float, Scaled_Float, Date, Date_Nanos, Boolean, Binary, Integer_Range, Float_Range, Long_Range, Double_Range, Date_Range, Ip_Range, Object, Nested, Ip, TokenCount, Percolator, Flattened, Search_As_You_Type_.
|
||||
See https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html[Elasticsearch Mapping Types]
|
||||
** `format` and `pattern` definitions for the _Date_ type.
|
||||
** `format`: One or more built-in date formats, see the next section <<elasticsearch.mapping.meta-model.date-formats>>.
|
||||
** `pattern`: One or more custom date formats, see the next section <<elasticsearch.mapping.meta-model.date-formats>>.
|
||||
** `store`: Flag whether the original field value should be store in Elasticsearch, default value is _false_.
|
||||
** `analyzer`, `searchAnalyzer`, `normalizer` for specifying custom analyzers and normalizer.
|
||||
* `@GeoPoint`: marks a field as _geo_point_ datatype.
|
||||
* `@GeoPoint`: Marks a field as _geo_point_ datatype.
|
||||
Can be omitted if the field is an instance of the `GeoPoint` class.
|
||||
|
||||
NOTE: Properties that derive from `TemporalAccessor` or are of type `java.util.Date` must either have a `@Field` annotation of type `FieldType.Date` and a
|
||||
format different from `DateFormat.none` or a custom converter must be registered for this type. +
|
||||
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].
|
||||
|
||||
The mapping metadata infrastructure is defined in a separate spring-data-commons project that is technology agnostic.
|
||||
|
||||
[[elasticsearch.mapping.meta-model.date-formats]]
|
||||
==== Date format mapping
|
||||
|
||||
Properties that derive from `TemporalAccessor` or are of type `java.util.Date` must either have a `@Field` annotation
|
||||
of type `FieldType.Date` or a custom converter must be registered for this type. This paragraph describes the use of
|
||||
`FieldType.Date`.
|
||||
|
||||
There are two attributes of the `@Field` annotation that define which date format information is written to the
|
||||
mapping (also see https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-date-format.html#built-in-date-formats[Elasticsearch Built In Formats] and https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-date-format.html#custom-date-formats[Elasticsearch Custom Date Formats])
|
||||
|
||||
The `format` attributes is used to define at least one of the predefined formats. If it is not defined, then a
|
||||
default value of __date_optional_time_ and _epoch_millis_ is used.
|
||||
|
||||
The `pattern` attribute can be used to add additional custom format strings. If you want to use only custom date formats, you must set the `format` property to empty `{}`.
|
||||
|
||||
The following table shows the different attributes and the mapping created from their values:
|
||||
|
||||
|
||||
[cols=2*,options=header]
|
||||
|===
|
||||
| annotation
|
||||
| format string in Elasticsearch mapping
|
||||
|
||||
| @Field(type=FieldType.Date)
|
||||
| "date_optional_time\|\|epoch_millis",
|
||||
|
||||
| @Field(type=FieldType.Date, format=DateFormat.basic_date)
|
||||
| "basic_date"
|
||||
|
||||
| @Field(type=FieldType.Date, format={DateFormat.basic_date, DateFormat.basic_time})
|
||||
| "basic_date\|\|basic_time"
|
||||
|
||||
| @Field(type=FieldType.Date, pattern="dd.MM.uuuu")
|
||||
| "date_optional_time\|\|epoch_millis\|\|dd.MM.uuuu",
|
||||
|
||||
| @Field(type=FieldType.Date, format={}, pattern="dd.MM.uuuu")
|
||||
| "dd.MM.uuuu"
|
||||
|
||||
|===
|
||||
|
||||
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].
|
||||
|
||||
==== Mapped field names
|
||||
|
||||
Without further configuration, Spring Data Elasticsearch will use the property name of an object as field name in Elasticsearch. This can be changed for individual field by using the `@Field` annotation on that property.
|
||||
|
||||
@@ -21,7 +21,8 @@ The default implementations of the interfaces offer:
|
||||
====
|
||||
.Index management and automatic creation of indices and mappings.
|
||||
|
||||
The `IndexOperations` interface and the provided implementation which can be obtained from an `ElasticsearchOperations` instance - for example with a call to `operations.indexOps(clazz)`- give the user the ability to create indices, put mappings or store template and alias information in the Elasticsearch cluster.
|
||||
The `IndexOperations` interface and the provided implementation which can be obtained from an `ElasticsearchOperations` instance - for example with a call to `operations.indexOps(clazz)`- give the user the ability to create indices, put mappings or store template and alias information in the Elasticsearch cluster. Details of the index that will be created
|
||||
can be set by using the `@Setting` annotation, refer to <<elasticsearc.misc.index.settings>> for further information.
|
||||
|
||||
**None of these operations are done automatically** by the implementations of `IndexOperations` or `ElasticsearchOperations`. It is the user's responsibility to call the methods.
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ class Book {
|
||||
|
||||
The `@Document` annotation has an argument `createIndex`. If this argument is set to true - which is the default value - Spring Data Elasticsearch will during bootstrapping the repository support on application startup check if the index defined by the `@Document` annotation exists.
|
||||
|
||||
If it does not exist, the index will be created and the mappings derived from the entity's annotations (see <<elasticsearch.mapping>>) will be written to the newly created index.
|
||||
If it does not exist, the index will be created and the mappings derived from the entity's annotations (see <<elasticsearch.mapping>>) will be written to the newly created index. Details of the index that will be created can be set by using the `@Setting` annotation, refer to <<elasticsearc.misc.index.settings>> for further information.
|
||||
|
||||
include::elasticsearch-repository-queries.adoc[leveloffset=+1]
|
||||
|
||||
@@ -131,7 +131,7 @@ class ProductService {
|
||||
public void setRepository(ProductRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
<1> Create a component by using the same calls as are used in the <<elasticsearch.operations>> chapter.
|
||||
<2> Let the CDI framework inject the Repository into your class.
|
||||
|
||||
+13
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2021 the original author or authors.
|
||||
* Copyright 2021 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.
|
||||
@@ -13,12 +13,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.immutable;
|
||||
package org.springframework.data.elasticsearch;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
/**
|
||||
* @author Young Gu
|
||||
* @author Oliver Gierke
|
||||
* @author Peter-Josef Meisch
|
||||
*/
|
||||
public interface ImmutableElasticsearchRepository extends CrudRepository<ImmutableEntity, String> {}
|
||||
public class ResourceFailureException extends NestedRuntimeException {
|
||||
public ResourceFailureException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public ResourceFailureException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
}
|
||||
@@ -23,9 +23,21 @@ package org.springframework.data.elasticsearch.annotations;
|
||||
* @author Jakub Vavrik
|
||||
* @author Tim te Beek
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Sascha Woo
|
||||
*/
|
||||
public enum DateFormat {
|
||||
/**
|
||||
* @deprecated since 4.2, will be removed in a future version. Use <code>format = {}</code> to disable built-in date
|
||||
* formats in the @Field annotation.
|
||||
*/
|
||||
@Deprecated
|
||||
none(""), //
|
||||
/**
|
||||
* @deprecated since 4.2, will be removed in a future version.It is no longer required for using a custom date format
|
||||
* pattern. If you want to use only a custom date format pattern, you must set the <code>format</code>
|
||||
* property to empty <code>{}</code>.
|
||||
*/
|
||||
@Deprecated
|
||||
custom(""), //
|
||||
basic_date("uuuuMMdd"), //
|
||||
basic_date_time("uuuuMMdd'T'HHmmss.SSSXXX"), //
|
||||
|
||||
@@ -44,7 +44,7 @@ public @interface Document {
|
||||
* Name of the Elasticsearch index.
|
||||
* <ul>
|
||||
* <li>Lowercase only</li>
|
||||
* <li><Cannot include \, /, *, ?, ", <, >, |, ` ` (space character), ,, #/li>
|
||||
* <li>Cannot include \, /, *, ?, ", >, <, |, ` ` (space character), ,, #</li>
|
||||
* <li>Cannot start with -, _, +</li>
|
||||
* <li>Cannot be . or ..</li>
|
||||
* <li>Cannot be longer than 255 bytes (note it is bytes, so multi-byte characters will count towards the 255 limit
|
||||
@@ -55,29 +55,45 @@ public @interface Document {
|
||||
|
||||
/**
|
||||
* Use server-side settings when creating the index.
|
||||
*
|
||||
* @deprecated since 4.2, use the {@link Setting} annotation to configure settings
|
||||
*/
|
||||
@Deprecated
|
||||
boolean useServerConfiguration() default false;
|
||||
|
||||
/**
|
||||
* Number of shards for the index {@link #indexName()}. Used for index creation. <br/>
|
||||
* With version 4.0, the default value is changed from 5 to 1 to reflect the change in the default settings of
|
||||
* Elasticsearch which changed to 1 as well in Elasticsearch 7.0.
|
||||
* ComposableAnnotationsUnitTest.documentAnnotationShouldBeComposable:60
|
||||
*
|
||||
* @deprecated since 4.2, use the {@link Setting} annotation to configure settings
|
||||
*/
|
||||
@Deprecated
|
||||
short shards() default 1;
|
||||
|
||||
/**
|
||||
* Number of replicas for the index {@link #indexName()}. Used for index creation.
|
||||
*
|
||||
* @deprecated since 4.2, use the {@link Setting} annotation to configure settings
|
||||
*/
|
||||
@Deprecated
|
||||
short replicas() default 1;
|
||||
|
||||
/**
|
||||
* Refresh interval for the index {@link #indexName()}. Used for index creation.
|
||||
*
|
||||
* @deprecated since 4.2, use the {@link Setting} annotation to configure settings
|
||||
*/
|
||||
@Deprecated
|
||||
String refreshInterval() default "1s";
|
||||
|
||||
/**
|
||||
* Index storage type for the index {@link #indexName()}. Used for index creation.
|
||||
*
|
||||
* @deprecated since 4.2, use the {@link Setting} annotation to configure settings
|
||||
*/
|
||||
@Deprecated
|
||||
String indexStoreType() default "fs";
|
||||
|
||||
/**
|
||||
|
||||
+12
-2
@@ -17,10 +17,20 @@ package org.springframework.data.elasticsearch.annotations;
|
||||
|
||||
/**
|
||||
* values for the {@link DynamicMapping annotation}
|
||||
*
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.0
|
||||
*/
|
||||
public enum DynamicMappingValue {
|
||||
True, False, Strict
|
||||
True("true"), False("false"), Strict("strict");
|
||||
|
||||
private final String mappedName;
|
||||
|
||||
DynamicMappingValue(String mappedName) {
|
||||
this.mappedName = mappedName;
|
||||
}
|
||||
|
||||
public String getMappedName() {
|
||||
return mappedName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,9 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Xiao Yu
|
||||
* @author Aleksei Arsenev
|
||||
* @author Brian Kimmig
|
||||
* @author Morgan Lutz
|
||||
* @author Sascha Woo
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE })
|
||||
@@ -63,9 +66,9 @@ public @interface Field {
|
||||
|
||||
boolean index() default true;
|
||||
|
||||
DateFormat format() default DateFormat.none;
|
||||
DateFormat[] format() default { DateFormat.date_optional_time, DateFormat.epoch_millis };
|
||||
|
||||
String pattern() default "";
|
||||
String[] pattern() default {};
|
||||
|
||||
boolean store() default false;
|
||||
|
||||
@@ -157,14 +160,14 @@ public @interface Field {
|
||||
|
||||
/**
|
||||
* if true, the field will be stored in Elasticsearch even if it has a null value
|
||||
*
|
||||
*
|
||||
* @since 4.1
|
||||
*/
|
||||
boolean storeNullValue() default false;
|
||||
|
||||
/**
|
||||
* to be used in combination with {@link FieldType#Rank_Feature}
|
||||
*
|
||||
*
|
||||
* @since 4.1
|
||||
*/
|
||||
boolean positiveScoreImpact() default true;
|
||||
@@ -185,4 +188,11 @@ public @interface Field {
|
||||
* @since 4.1
|
||||
*/
|
||||
NullValueType nullValueType() default NullValueType.String;
|
||||
|
||||
/**
|
||||
* to be used in combination with {@link FieldType#Dense_Vector}
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
int dims() default -1;
|
||||
}
|
||||
|
||||
@@ -22,40 +22,55 @@ package org.springframework.data.elasticsearch.annotations;
|
||||
* @author Zeng Zetang
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Aleksei Arsenev
|
||||
* @author Brian Kimmig
|
||||
* @author Morgan Lutz
|
||||
*/
|
||||
public enum FieldType {
|
||||
Auto, //
|
||||
Text, //
|
||||
Keyword, //
|
||||
Long, //
|
||||
Integer, //
|
||||
Short, //
|
||||
Byte, //
|
||||
Double, //
|
||||
Float, //
|
||||
Half_Float, //
|
||||
Scaled_Float, //
|
||||
Date, //
|
||||
Date_Nanos, //
|
||||
Boolean, //
|
||||
Binary, //
|
||||
Integer_Range, //
|
||||
Float_Range, //
|
||||
Long_Range, //
|
||||
Double_Range, //
|
||||
Date_Range, //
|
||||
Ip_Range, //
|
||||
Object, //
|
||||
Nested, //
|
||||
Ip, //
|
||||
TokenCount, //
|
||||
Percolator, //
|
||||
Flattened, //
|
||||
Search_As_You_Type, //
|
||||
Auto("auto"), //
|
||||
Text("text"), //
|
||||
Keyword("keyword"), //
|
||||
Long("long"), //
|
||||
Integer("integer"), //
|
||||
Short("short"), //
|
||||
Byte("byte"), //
|
||||
Double("double"), //
|
||||
Float("float"), //
|
||||
Half_Float("half_float"), //
|
||||
Scaled_Float("scaled_float"), //
|
||||
Date("date"), //
|
||||
Date_Nanos("date_nanos"), //
|
||||
Boolean("boolean"), //
|
||||
Binary("binary"), //
|
||||
Integer_Range("integer_range"), //
|
||||
Float_Range("float_range"), //
|
||||
Long_Range("long_range"), //
|
||||
Double_Range("double_range"), //
|
||||
Date_Range("date_range"), //
|
||||
Ip_Range("ip_range"), //
|
||||
Object("object"), //
|
||||
Nested("nested"), //
|
||||
Ip("ip"), //
|
||||
TokenCount("token_count"), //
|
||||
Percolator("percolator"), //
|
||||
Flattened("flattened"), //
|
||||
Search_As_You_Type("search_as_you_type"), //
|
||||
/** @since 4.1 */
|
||||
Rank_Feature, //
|
||||
Rank_Feature("rank_feature"), //
|
||||
/** @since 4.1 */
|
||||
Rank_Features, //
|
||||
Rank_Features("rank_features"), //
|
||||
/** since 4.2 */
|
||||
Wildcard //
|
||||
Wildcard("wildcard"), //
|
||||
/** @since 4.2 */
|
||||
Dense_Vector("dense_vector") //
|
||||
;
|
||||
|
||||
private final String mappedName;
|
||||
|
||||
FieldType(String mappedName) {
|
||||
this.mappedName = mappedName;
|
||||
}
|
||||
|
||||
public String getMappedName() {
|
||||
return mappedName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ import java.lang.annotation.Target;
|
||||
* @author Xiao Yu
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Aleksei Arsenev
|
||||
* @author Brian Kimmig
|
||||
* @author Morgan Lutz
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.ANNOTATION_TYPE)
|
||||
@@ -38,9 +40,9 @@ public @interface InnerField {
|
||||
|
||||
boolean index() default true;
|
||||
|
||||
DateFormat format() default DateFormat.none;
|
||||
DateFormat[] format() default { DateFormat.date_optional_time, DateFormat.epoch_millis };
|
||||
|
||||
String pattern() default "";
|
||||
String[] pattern() default {};
|
||||
|
||||
boolean store() default false;
|
||||
|
||||
@@ -140,4 +142,11 @@ public @interface InnerField {
|
||||
* @since 4.1
|
||||
*/
|
||||
NullValueType nullValueType() default NullValueType.String;
|
||||
|
||||
/**
|
||||
* to be used in combination with {@link FieldType#Dense_Vector}
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
int dims() default -1;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.annotations;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
|
||||
@@ -23,14 +27,84 @@ import org.springframework.data.annotation.Persistent;
|
||||
* Elasticsearch Setting
|
||||
*
|
||||
* @author Mohsin Husen
|
||||
* @author Peter-Josef Meisch
|
||||
*/
|
||||
|
||||
@Persistent
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
@Target({ ElementType.TYPE })
|
||||
public @interface Setting {
|
||||
|
||||
/**
|
||||
* Resource path for a settings configuration
|
||||
*/
|
||||
String settingPath() default "";
|
||||
|
||||
/**
|
||||
* Use server-side settings when creating the index.
|
||||
*/
|
||||
boolean useServerConfiguration() default false;
|
||||
|
||||
/**
|
||||
* Number of shards for the index. Used for index creation. <br/>
|
||||
* With version 4.0, the default value is changed from 5 to 1 to reflect the change in the default settings of
|
||||
* Elasticsearch which changed to 1 as well in Elasticsearch 7.0.
|
||||
*/
|
||||
short shards() default 1;
|
||||
|
||||
/**
|
||||
* Number of replicas for the index. Used for index creation.
|
||||
*/
|
||||
short replicas() default 1;
|
||||
|
||||
/**
|
||||
* Refresh interval for the index. Used for index creation.
|
||||
*/
|
||||
String refreshInterval() default "1s";
|
||||
|
||||
/**
|
||||
* Index storage type for the index. Used for index creation.
|
||||
*/
|
||||
String indexStoreType() default "fs";
|
||||
|
||||
/**
|
||||
* fields to define an index sorting
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
String[] sortFields() default {};
|
||||
|
||||
/**
|
||||
* defines the order for {@link #sortFields()}. If present, it must have the same number of elements
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
SortOrder[] sortOrders() default {};
|
||||
|
||||
/**
|
||||
* defines the mode for {@link #sortFields()}. If present, it must have the same number of elements
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
SortMode[] sortModes() default {};
|
||||
|
||||
/**
|
||||
* defines the missing value for {@link #sortFields()}. If present, it must have the same number of elements
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
SortMissing[] sortMissingValues() default {};
|
||||
|
||||
enum SortOrder {
|
||||
asc, desc
|
||||
}
|
||||
|
||||
enum SortMode {
|
||||
min, max
|
||||
}
|
||||
|
||||
enum SortMissing {
|
||||
_last, _first
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ import org.springframework.util.Assert;
|
||||
* @author Huw Ayling-Miller
|
||||
* @author Henrique Amaral
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Nic Hines
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class RestClients {
|
||||
@@ -104,15 +105,14 @@ public final class RestClients {
|
||||
Duration connectTimeout = clientConfiguration.getConnectTimeout();
|
||||
|
||||
if (!connectTimeout.isNegative()) {
|
||||
|
||||
requestConfigBuilder.setConnectTimeout(Math.toIntExact(connectTimeout.toMillis()));
|
||||
requestConfigBuilder.setConnectionRequestTimeout(Math.toIntExact(connectTimeout.toMillis()));
|
||||
}
|
||||
|
||||
Duration timeout = clientConfiguration.getSocketTimeout();
|
||||
Duration socketTimeout = clientConfiguration.getSocketTimeout();
|
||||
|
||||
if (!timeout.isNegative()) {
|
||||
requestConfigBuilder.setSocketTimeout(Math.toIntExact(timeout.toMillis()));
|
||||
if (!socketTimeout.isNegative()) {
|
||||
requestConfigBuilder.setSocketTimeout(Math.toIntExact(socketTimeout.toMillis()));
|
||||
requestConfigBuilder.setConnectionRequestTimeout(Math.toIntExact(socketTimeout.toMillis()));
|
||||
}
|
||||
|
||||
clientBuilder.setDefaultRequestConfig(requestConfigBuilder.build());
|
||||
|
||||
+113
-95
@@ -45,17 +45,14 @@ import javax.net.ssl.SSLContext;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ElasticsearchStatusException;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
||||
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
|
||||
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
|
||||
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.flush.FlushRequest;
|
||||
import org.elasticsearch.action.admin.indices.flush.FlushResponse;
|
||||
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
|
||||
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
|
||||
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
|
||||
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
|
||||
import org.elasticsearch.action.admin.indices.refresh.RefreshResponse;
|
||||
@@ -68,6 +65,7 @@ import org.elasticsearch.action.delete.DeleteRequest;
|
||||
import org.elasticsearch.action.delete.DeleteResponse;
|
||||
import org.elasticsearch.action.get.GetRequest;
|
||||
import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.action.get.MultiGetItemResponse;
|
||||
import org.elasticsearch.action.get.MultiGetRequest;
|
||||
import org.elasticsearch.action.get.MultiGetResponse;
|
||||
import org.elasticsearch.action.index.IndexRequest;
|
||||
@@ -84,12 +82,7 @@ import org.elasticsearch.action.update.UpdateRequest;
|
||||
import org.elasticsearch.action.update.UpdateResponse;
|
||||
import org.elasticsearch.client.GetAliasesResponse;
|
||||
import org.elasticsearch.client.Request;
|
||||
import org.elasticsearch.client.indices.GetFieldMappingsRequest;
|
||||
import org.elasticsearch.client.indices.GetFieldMappingsResponse;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesResponse;
|
||||
import org.elasticsearch.client.indices.IndexTemplatesExistRequest;
|
||||
import org.elasticsearch.client.indices.PutIndexTemplateRequest;
|
||||
import org.elasticsearch.client.indices.*;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.DeprecationHandler;
|
||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||
@@ -101,6 +94,8 @@ import org.elasticsearch.index.reindex.DeleteByQueryRequest;
|
||||
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
|
||||
import org.elasticsearch.rest.BytesRestResponse;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.elasticsearch.script.mustache.SearchTemplateRequest;
|
||||
import org.elasticsearch.script.mustache.SearchTemplateResponse;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.search.SearchHits;
|
||||
import org.elasticsearch.search.aggregations.Aggregation;
|
||||
@@ -112,6 +107,7 @@ import org.springframework.data.elasticsearch.client.ClientLogger;
|
||||
import org.springframework.data.elasticsearch.client.ElasticsearchHost;
|
||||
import org.springframework.data.elasticsearch.client.NoReachableHostException;
|
||||
import org.springframework.data.elasticsearch.client.reactive.HostProvider.Verification;
|
||||
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient.Cluster;
|
||||
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient.Indices;
|
||||
import org.springframework.data.elasticsearch.client.util.NamedXContents;
|
||||
import org.springframework.data.elasticsearch.client.util.ScrollState;
|
||||
@@ -144,11 +140,12 @@ import org.springframework.web.reactive.function.client.WebClient.RequestBodySpe
|
||||
* @author Thomas Geese
|
||||
* @author Brian Clozel
|
||||
* @author Farid Faoudi
|
||||
* @author George Popides
|
||||
* @since 3.2
|
||||
* @see ClientConfiguration
|
||||
* @see ReactiveRestClients
|
||||
*/
|
||||
public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearchClient, Indices {
|
||||
public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearchClient, Indices, Cluster {
|
||||
|
||||
private final HostProvider<?> hostProvider;
|
||||
private final RequestCreator requestCreator;
|
||||
@@ -284,15 +281,23 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
scheme = "https";
|
||||
}
|
||||
|
||||
ReactorClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
|
||||
WebClientProvider provider = WebClientProvider.create(scheme, connector);
|
||||
WebClientProvider provider = WebClientProvider.create(scheme, new ReactorClientHttpConnector(httpClient));
|
||||
|
||||
if (clientConfiguration.getPathPrefix() != null) {
|
||||
provider = provider.withPathPrefix(clientConfiguration.getPathPrefix());
|
||||
}
|
||||
|
||||
provider = provider.withDefaultHeaders(clientConfiguration.getDefaultHeaders()) //
|
||||
.withWebClientConfigurer(clientConfiguration.getWebClientConfigurer());
|
||||
provider = provider //
|
||||
.withDefaultHeaders(clientConfiguration.getDefaultHeaders()) //
|
||||
.withWebClientConfigurer(clientConfiguration.getWebClientConfigurer()) //
|
||||
.withRequestConfigurer(requestHeadersSpec -> requestHeadersSpec.headers(httpHeaders -> {
|
||||
HttpHeaders suppliedHeaders = clientConfiguration.getHeadersSupplier().get();
|
||||
|
||||
if (suppliedHeaders != null && suppliedHeaders != HttpHeaders.EMPTY) {
|
||||
httpHeaders.addAll(suppliedHeaders);
|
||||
}
|
||||
}));
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
@@ -303,10 +308,6 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
this.headersSupplier = headersSupplier;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#ping(org.springframework.http.HttpHeaders)
|
||||
*/
|
||||
@Override
|
||||
public Mono<Boolean> ping(HttpHeaders headers) {
|
||||
|
||||
@@ -315,10 +316,6 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
.onErrorResume(NoReachableHostException.class, error -> Mono.just(false)).next();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#info(org.springframework.http.HttpHeaders)
|
||||
*/
|
||||
@Override
|
||||
public Mono<MainResponse> info(HttpHeaders headers) {
|
||||
|
||||
@@ -326,10 +323,6 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
.next();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#get(org.springframework.http.HttpHeaders, org.elasticsearch.action.get.GetRequest)
|
||||
*/
|
||||
@Override
|
||||
public Mono<GetResult> get(HttpHeaders headers, GetRequest getRequest) {
|
||||
|
||||
@@ -339,24 +332,14 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
.next();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#multiGet(org.springframework.http.HttpHeaders, org.elasticsearch.action.get.MultiGetRequest)
|
||||
*/
|
||||
@Override
|
||||
public Flux<GetResult> multiGet(HttpHeaders headers, MultiGetRequest multiGetRequest) {
|
||||
public Flux<MultiGetItemResponse> multiGet(HttpHeaders headers, MultiGetRequest multiGetRequest) {
|
||||
|
||||
return sendRequest(multiGetRequest, requestCreator.multiGet(), MultiGetResponse.class, headers)
|
||||
.map(MultiGetResponse::getResponses) //
|
||||
.flatMap(Flux::fromArray) //
|
||||
.filter(it -> !it.isFailed() && it.getResponse().isExists()) //
|
||||
.map(it -> DefaultReactiveElasticsearchClient.getResponseToGetResult(it.getResponse()));
|
||||
.flatMap(Flux::fromArray); //
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#exists(org.springframework.http.HttpHeaders, org.elasticsearch.action.get.GetRequest)
|
||||
*/
|
||||
@Override
|
||||
public Mono<Boolean> exists(HttpHeaders headers, GetRequest getRequest) {
|
||||
|
||||
@@ -365,37 +348,26 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
.next();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#ping(org.springframework.http.HttpHeaders, org.elasticsearch.action.index.IndexRequest)
|
||||
*/
|
||||
@Override
|
||||
public Mono<IndexResponse> index(HttpHeaders headers, IndexRequest indexRequest) {
|
||||
return sendRequest(indexRequest, requestCreator.index(), IndexResponse.class, headers).next();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#indices()
|
||||
*/
|
||||
@Override
|
||||
public Indices indices() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#ping(org.springframework.http.HttpHeaders, org.elasticsearch.action.update.UpdateRequest)
|
||||
*/
|
||||
@Override
|
||||
public Cluster cluster() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<UpdateResponse> update(HttpHeaders headers, UpdateRequest updateRequest) {
|
||||
return sendRequest(updateRequest, requestCreator.update(), UpdateResponse.class, headers).next();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#ping(org.springframework.http.HttpHeaders, org.elasticsearch.action.delete.DeleteRequest)
|
||||
*/
|
||||
@Override
|
||||
public Mono<DeleteResponse> delete(HttpHeaders headers, DeleteRequest deleteRequest) {
|
||||
|
||||
@@ -403,10 +375,6 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
.next();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#count(org.springframework.http.HttpHeaders, org.elasticsearch.action.search.SearchRequest)
|
||||
*/
|
||||
@Override
|
||||
public Mono<Long> count(HttpHeaders headers, SearchRequest searchRequest) {
|
||||
searchRequest.source().trackTotalHits(true);
|
||||
@@ -418,10 +386,12 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
.next();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#ping(org.springframework.http.HttpHeaders, org.elasticsearch.action.search.SearchRequest)
|
||||
*/
|
||||
@Override
|
||||
public Flux<SearchHit> searchTemplate(HttpHeaders headers, SearchTemplateRequest searchTemplateRequest) {
|
||||
return sendRequest(searchTemplateRequest, requestCreator.searchTemplate(), SearchTemplateResponse.class, headers)
|
||||
.map(response -> response.getResponse().getHits()).flatMap(Flux::fromIterable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<SearchHit> search(HttpHeaders headers, SearchRequest searchRequest) {
|
||||
|
||||
@@ -441,10 +411,6 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
.map(SearchResponse::getSuggest);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#aggregate(org.springframework.http.HttpHeaders, org.elasticsearch.action.search.SearchRequest)
|
||||
*/
|
||||
@Override
|
||||
public Flux<Aggregation> aggregate(HttpHeaders headers, SearchRequest searchRequest) {
|
||||
|
||||
@@ -459,10 +425,6 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
.flatMap(Flux::fromIterable);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#scroll(org.springframework.http.HttpHeaders, org.elasticsearch.action.search.SearchRequest)
|
||||
*/
|
||||
@Override
|
||||
public Flux<SearchHit> scroll(HttpHeaders headers, SearchRequest searchRequest) {
|
||||
|
||||
@@ -512,10 +474,6 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
return sendRequest(clearScrollRequest, requestCreator.clearScroll(), ClearScrollResponse.class, headers);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#ping(org.springframework.http.HttpHeaders, org.elasticsearch.index.reindex.DeleteByQueryRequest)
|
||||
*/
|
||||
@Override
|
||||
public Mono<BulkByScrollResponse> deleteBy(HttpHeaders headers, DeleteByQueryRequest deleteRequest) {
|
||||
|
||||
@@ -530,10 +488,6 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
.map(ByQueryResponse::of);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#bulk(org.springframework.http.HttpHeaders, org.elasticsearch.action.bulk.BulkRequest)
|
||||
*/
|
||||
@Override
|
||||
public Mono<BulkResponse> bulk(HttpHeaders headers, BulkRequest bulkRequest) {
|
||||
return sendRequest(bulkRequest, requestCreator.bulk(), BulkResponse.class, headers) //
|
||||
@@ -547,8 +501,7 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
.flatMap(callback::doWithClient) //
|
||||
.onErrorResume(throwable -> {
|
||||
|
||||
if (throwable instanceof ConnectException) {
|
||||
|
||||
if (isCausedByConnectionException(throwable)) {
|
||||
return hostProvider.getActive(Verification.ACTIVE) //
|
||||
.flatMap(callback::doWithClient);
|
||||
}
|
||||
@@ -557,6 +510,27 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if the given throwable is a {@link ConnectException} or has one in it's cause chain
|
||||
*
|
||||
* @param throwable the throwable to check
|
||||
* @return true if throwable is caused by a {@link ConnectException}
|
||||
*/
|
||||
private boolean isCausedByConnectionException(Throwable throwable) {
|
||||
|
||||
Throwable t = throwable;
|
||||
do {
|
||||
|
||||
if (t instanceof ConnectException) {
|
||||
return true;
|
||||
}
|
||||
|
||||
t = t.getCause();
|
||||
} while (t != null);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Status> status() {
|
||||
|
||||
@@ -618,12 +592,6 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
request.getOptions().getHeaders().forEach(it -> theHeaders.add(it.getName(), it.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
// plus the ones from the supplier
|
||||
HttpHeaders suppliedHeaders = headersSupplier.get();
|
||||
if (suppliedHeaders != null && suppliedHeaders != HttpHeaders.EMPTY) {
|
||||
theHeaders.addAll(suppliedHeaders);
|
||||
}
|
||||
});
|
||||
|
||||
if (request.getEntity() != null) {
|
||||
@@ -633,8 +601,8 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
ClientLogger.logRequest(logId, request.getMethod().toUpperCase(), request.getEndpoint(), request.getParameters(),
|
||||
body::get);
|
||||
|
||||
requestBodySpec.contentType(MediaType.valueOf(request.getEntity().getContentType().getValue()));
|
||||
requestBodySpec.body(Mono.fromSupplier(body), String.class);
|
||||
requestBodySpec.contentType(MediaType.valueOf(request.getEntity().getContentType().getValue()))
|
||||
.body(Mono.fromSupplier(body), String.class);
|
||||
} else {
|
||||
ClientLogger.logRequest(logId, request.getMethod().toUpperCase(), request.getEndpoint(), request.getParameters());
|
||||
}
|
||||
@@ -644,13 +612,22 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
|
||||
// region indices operations
|
||||
@Override
|
||||
public Mono<Boolean> createIndex(HttpHeaders headers, CreateIndexRequest createIndexRequest) {
|
||||
public Mono<Boolean> createIndex(HttpHeaders headers,
|
||||
org.elasticsearch.action.admin.indices.create.CreateIndexRequest createIndexRequest) {
|
||||
|
||||
return sendRequest(createIndexRequest, requestCreator.indexCreate(), AcknowledgedResponse.class, headers) //
|
||||
.map(AcknowledgedResponse::isAcknowledged) //
|
||||
.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> createIndex(HttpHeaders headers, CreateIndexRequest createIndexRequest) {
|
||||
|
||||
return sendRequest(createIndexRequest, requestCreator.createIndexRequest(), AcknowledgedResponse.class, headers) //
|
||||
.map(AcknowledgedResponse::isAcknowledged) //
|
||||
.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> closeIndex(HttpHeaders headers, CloseIndexRequest closeIndexRequest) {
|
||||
|
||||
@@ -659,13 +636,21 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> existsIndex(HttpHeaders headers, GetIndexRequest request) {
|
||||
public Mono<Boolean> existsIndex(HttpHeaders headers,
|
||||
org.elasticsearch.action.admin.indices.get.GetIndexRequest request) {
|
||||
|
||||
return sendRequest(request, requestCreator.indexExists(), RawActionResponse.class, headers) //
|
||||
.flatMap(response -> response.releaseBody().thenReturn(response.statusCode().is2xxSuccessful())) //
|
||||
.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> existsIndex(HttpHeaders headers, GetIndexRequest request) {
|
||||
return sendRequest(request, requestCreator.indexExistsRequest(), RawActionResponse.class, headers) //
|
||||
.flatMap(response -> response.releaseBody().thenReturn(response.statusCode().is2xxSuccessful())) //
|
||||
.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> deleteIndex(HttpHeaders headers, DeleteIndexRequest request) {
|
||||
|
||||
@@ -681,9 +666,18 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
.then();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public Mono<org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse> getMapping(HttpHeaders headers,
|
||||
org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest getMappingsRequest) {
|
||||
return sendRequest(getMappingsRequest, requestCreator.getMapping(),
|
||||
org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse.class, headers).next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<GetMappingsResponse> getMapping(HttpHeaders headers, GetMappingsRequest getMappingsRequest) {
|
||||
return sendRequest(getMappingsRequest, requestCreator.getMapping(), GetMappingsResponse.class, headers).next();
|
||||
return sendRequest(getMappingsRequest, requestCreator.getMappingRequest(), GetMappingsResponse.class, headers) //
|
||||
.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -699,13 +693,21 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> putMapping(HttpHeaders headers, PutMappingRequest putMappingRequest) {
|
||||
public Mono<Boolean> putMapping(HttpHeaders headers,
|
||||
org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest putMappingRequest) {
|
||||
|
||||
return sendRequest(putMappingRequest, requestCreator.putMapping(), AcknowledgedResponse.class, headers) //
|
||||
.map(AcknowledgedResponse::isAcknowledged) //
|
||||
.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> putMapping(HttpHeaders headers, PutMappingRequest putMappingRequest) {
|
||||
return sendRequest(putMappingRequest, requestCreator.putMappingRequest(), AcknowledgedResponse.class, headers) //
|
||||
.map(AcknowledgedResponse::isAcknowledged) //
|
||||
.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> openIndex(HttpHeaders headers, OpenIndexRequest request) {
|
||||
|
||||
@@ -757,6 +759,19 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
.map(AcknowledgedResponse::isAcknowledged).next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<GetIndexResponse> getIndex(HttpHeaders headers, GetIndexRequest getIndexRequest) {
|
||||
return sendRequest(getIndexRequest, requestCreator.getIndex(), GetIndexResponse.class, headers).next();
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region cluster operations
|
||||
@Override
|
||||
public Mono<ClusterHealthResponse> health(HttpHeaders headers, ClusterHealthRequest clusterHealthRequest) {
|
||||
return sendRequest(clusterHealthRequest, requestCreator.clusterHealth(), ClusterHealthResponse.class, headers)
|
||||
.next();
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region helper functions
|
||||
@@ -842,6 +857,9 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
String mediaType = response.headers().contentType().map(MediaType::toString).orElse(XContentType.JSON.mediaType());
|
||||
|
||||
return response.body(BodyExtractors.toMono(byte[].class)) //
|
||||
.switchIfEmpty(Mono.error(
|
||||
new ElasticsearchStatusException(String.format("%s request to %s returned error code %s and no body.",
|
||||
request.getMethod(), request.getEndpoint(), statusCode), status)))
|
||||
.map(bytes -> new String(bytes, StandardCharsets.UTF_8)) //
|
||||
.flatMap(content -> contentOrError(content, mediaType, status))
|
||||
.flatMap(unused -> Mono
|
||||
@@ -909,7 +927,7 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
|
||||
} while (token == XContentParser.Token.FIELD_NAME);
|
||||
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
} catch (Exception e) {
|
||||
return new ElasticsearchStatusException(content, status);
|
||||
}
|
||||
}
|
||||
|
||||
+28
-8
@@ -48,6 +48,7 @@ class DefaultWebClientProvider implements WebClientProvider {
|
||||
private final HttpHeaders headers;
|
||||
private final @Nullable String pathPrefix;
|
||||
private final Function<WebClient, WebClient> webClientConfigurer;
|
||||
private final Consumer<WebClient.RequestHeadersSpec<?>> requestConfigurer;
|
||||
|
||||
/**
|
||||
* Create new {@link DefaultWebClientProvider} with empty {@link HttpHeaders} and no-op {@literal error listener}.
|
||||
@@ -56,7 +57,7 @@ class DefaultWebClientProvider implements WebClientProvider {
|
||||
* @param connector can be {@literal null}.
|
||||
*/
|
||||
DefaultWebClientProvider(String scheme, @Nullable ClientHttpConnector connector) {
|
||||
this(scheme, connector, e -> {}, HttpHeaders.EMPTY, null, Function.identity());
|
||||
this(scheme, connector, e -> {}, HttpHeaders.EMPTY, null, Function.identity(), requestHeadersSpec -> {});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,18 +67,21 @@ class DefaultWebClientProvider implements WebClientProvider {
|
||||
* @param connector can be {@literal null}.
|
||||
* @param errorListener must not be {@literal null}.
|
||||
* @param headers must not be {@literal null}.
|
||||
* @param pathPrefix can be {@literal null}
|
||||
* @param pathPrefix can be {@literal null}.
|
||||
* @param webClientConfigurer must not be {@literal null}.
|
||||
* @param requestConfigurer must not be {@literal null}.
|
||||
*/
|
||||
private DefaultWebClientProvider(String scheme, @Nullable ClientHttpConnector connector,
|
||||
Consumer<Throwable> errorListener, HttpHeaders headers, @Nullable String pathPrefix,
|
||||
Function<WebClient, WebClient> webClientConfigurer) {
|
||||
Function<WebClient, WebClient> webClientConfigurer, Consumer<WebClient.RequestHeadersSpec<?>> requestConfigurer) {
|
||||
|
||||
Assert.notNull(scheme, "Scheme must not be null! A common scheme would be 'http'.");
|
||||
Assert.notNull(errorListener, "errorListener must not be null! You may want use a no-op one 'e -> {}' instead.");
|
||||
Assert.notNull(headers, "headers must not be null! Think about using 'HttpHeaders.EMPTY' as an alternative.");
|
||||
Assert.notNull(webClientConfigurer,
|
||||
"webClientConfigurer must not be null! You may want use a no-op one 'Function.identity()' instead.");
|
||||
Assert.notNull(requestConfigurer,
|
||||
"requestConfigurer must not be null! You may want use a no-op one 'r -> {}' instead.\"");
|
||||
|
||||
this.cachedClients = new ConcurrentHashMap<>();
|
||||
this.scheme = scheme;
|
||||
@@ -86,6 +90,7 @@ class DefaultWebClientProvider implements WebClientProvider {
|
||||
this.headers = headers;
|
||||
this.pathPrefix = pathPrefix;
|
||||
this.webClientConfigurer = webClientConfigurer;
|
||||
this.requestConfigurer = requestConfigurer;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,6 +111,7 @@ class DefaultWebClientProvider implements WebClientProvider {
|
||||
return this.errorListener;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getPathPrefix() {
|
||||
return pathPrefix;
|
||||
@@ -120,7 +126,17 @@ class DefaultWebClientProvider implements WebClientProvider {
|
||||
merged.addAll(this.headers);
|
||||
merged.addAll(headers);
|
||||
|
||||
return new DefaultWebClientProvider(scheme, connector, errorListener, merged, pathPrefix, webClientConfigurer);
|
||||
return new DefaultWebClientProvider(scheme, connector, errorListener, merged, pathPrefix, webClientConfigurer,
|
||||
requestConfigurer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebClientProvider withRequestConfigurer(Consumer<WebClient.RequestHeadersSpec<?>> requestConfigurer) {
|
||||
|
||||
Assert.notNull(requestConfigurer, "requestConfigurer must not be null.");
|
||||
|
||||
return new DefaultWebClientProvider(scheme, connector, errorListener, headers, pathPrefix, webClientConfigurer,
|
||||
requestConfigurer);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,7 +145,8 @@ class DefaultWebClientProvider implements WebClientProvider {
|
||||
Assert.notNull(errorListener, "Error listener must not be null.");
|
||||
|
||||
Consumer<Throwable> listener = this.errorListener.andThen(errorListener);
|
||||
return new DefaultWebClientProvider(scheme, this.connector, listener, headers, pathPrefix, webClientConfigurer);
|
||||
return new DefaultWebClientProvider(scheme, this.connector, listener, headers, pathPrefix, webClientConfigurer,
|
||||
requestConfigurer);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -137,18 +154,21 @@ class DefaultWebClientProvider implements WebClientProvider {
|
||||
Assert.notNull(pathPrefix, "pathPrefix must not be null.");
|
||||
|
||||
return new DefaultWebClientProvider(this.scheme, this.connector, this.errorListener, this.headers, pathPrefix,
|
||||
webClientConfigurer);
|
||||
webClientConfigurer, requestConfigurer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebClientProvider withWebClientConfigurer(Function<WebClient, WebClient> webClientConfigurer) {
|
||||
return new DefaultWebClientProvider(scheme, connector, errorListener, headers, pathPrefix, webClientConfigurer);
|
||||
return new DefaultWebClientProvider(scheme, connector, errorListener, headers, pathPrefix, webClientConfigurer,
|
||||
requestConfigurer);
|
||||
|
||||
}
|
||||
|
||||
protected WebClient createWebClientForSocketAddress(InetSocketAddress socketAddress) {
|
||||
|
||||
Builder builder = WebClient.builder().defaultHeaders(it -> it.addAll(getDefaultHeaders()));
|
||||
Builder builder = WebClient.builder() //
|
||||
.defaultHeaders(it -> it.addAll(getDefaultHeaders())) //
|
||||
.defaultRequest(requestConfigurer);
|
||||
|
||||
if (connector != null) {
|
||||
builder = builder.clientConnector(connector);
|
||||
|
||||
+2
-2
@@ -54,9 +54,9 @@ public interface HostProvider<T extends HostProvider<T>> {
|
||||
Assert.notEmpty(endpoints, "Please provide at least one endpoint to connect to.");
|
||||
|
||||
if (endpoints.length == 1) {
|
||||
return new SingleNodeHostProvider(clientProvider, headersSupplier, endpoints[0]);
|
||||
return new SingleNodeHostProvider(clientProvider, endpoints[0]);
|
||||
} else {
|
||||
return new MultiNodeHostProvider(clientProvider, headersSupplier, endpoints);
|
||||
return new MultiNodeHostProvider(clientProvider, endpoints);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+44
-20
@@ -20,6 +20,7 @@ import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -27,12 +28,12 @@ import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.elasticsearch.client.ElasticsearchHost;
|
||||
import org.springframework.data.elasticsearch.client.ElasticsearchHost.State;
|
||||
import org.springframework.data.elasticsearch.client.NoReachableHostException;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
@@ -47,19 +48,20 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
*/
|
||||
class MultiNodeHostProvider implements HostProvider<MultiNodeHostProvider> {
|
||||
|
||||
private final static Logger LOG = LoggerFactory.getLogger(MultiNodeHostProvider.class);
|
||||
|
||||
private final WebClientProvider clientProvider;
|
||||
private final Supplier<HttpHeaders> headersSupplier;
|
||||
private final Map<InetSocketAddress, ElasticsearchHost> hosts;
|
||||
|
||||
MultiNodeHostProvider(WebClientProvider clientProvider, Supplier<HttpHeaders> headersSupplier,
|
||||
InetSocketAddress... endpoints) {
|
||||
MultiNodeHostProvider(WebClientProvider clientProvider, InetSocketAddress... endpoints) {
|
||||
|
||||
this.clientProvider = clientProvider;
|
||||
this.headersSupplier = headersSupplier;
|
||||
this.hosts = new ConcurrentHashMap<>();
|
||||
for (InetSocketAddress endpoint : endpoints) {
|
||||
this.hosts.put(endpoint, new ElasticsearchHost(endpoint, State.UNKNOWN));
|
||||
}
|
||||
|
||||
LOG.debug("initialized with " + hosts);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -68,7 +70,7 @@ class MultiNodeHostProvider implements HostProvider<MultiNodeHostProvider> {
|
||||
*/
|
||||
@Override
|
||||
public Mono<ClusterInformation> clusterInfo() {
|
||||
return nodes(null).map(this::updateNodeState).buffer(hosts.size())
|
||||
return checkNodes(null).map(this::updateNodeState).buffer(hosts.size())
|
||||
.then(Mono.just(new ClusterInformation(new LinkedHashSet<>(this.hosts.values()))));
|
||||
}
|
||||
|
||||
@@ -88,14 +90,19 @@ class MultiNodeHostProvider implements HostProvider<MultiNodeHostProvider> {
|
||||
@Override
|
||||
public Mono<InetSocketAddress> lookupActiveHost(Verification verification) {
|
||||
|
||||
LOG.trace("lookupActiveHost " + verification + " from " + hosts());
|
||||
|
||||
if (Verification.LAZY.equals(verification)) {
|
||||
for (ElasticsearchHost entry : hosts()) {
|
||||
if (entry.isOnline()) {
|
||||
LOG.trace("lookupActiveHost returning " + entry);
|
||||
return Mono.just(entry.getEndpoint());
|
||||
}
|
||||
}
|
||||
LOG.trace("no online host found with LAZY");
|
||||
}
|
||||
|
||||
LOG.trace("searching for active host");
|
||||
return findActiveHostInKnownActives() //
|
||||
.switchIfEmpty(findActiveHostInUnresolved()) //
|
||||
.switchIfEmpty(findActiveHostInDead()) //
|
||||
@@ -107,20 +114,30 @@ class MultiNodeHostProvider implements HostProvider<MultiNodeHostProvider> {
|
||||
}
|
||||
|
||||
private Mono<InetSocketAddress> findActiveHostInKnownActives() {
|
||||
return findActiveForSate(State.ONLINE);
|
||||
return findActiveForState(State.ONLINE);
|
||||
}
|
||||
|
||||
private Mono<InetSocketAddress> findActiveHostInUnresolved() {
|
||||
return findActiveForSate(State.UNKNOWN);
|
||||
return findActiveForState(State.UNKNOWN);
|
||||
}
|
||||
|
||||
private Mono<InetSocketAddress> findActiveHostInDead() {
|
||||
return findActiveForSate(State.OFFLINE);
|
||||
return findActiveForState(State.OFFLINE);
|
||||
}
|
||||
|
||||
private Mono<InetSocketAddress> findActiveForSate(State state) {
|
||||
return nodes(state).map(this::updateNodeState).filter(ElasticsearchHost::isOnline)
|
||||
.map(ElasticsearchHost::getEndpoint).next();
|
||||
private Mono<InetSocketAddress> findActiveForState(State state) {
|
||||
|
||||
LOG.trace("findActiveForState state " + state + ", current hosts: " + hosts);
|
||||
|
||||
return checkNodes(state) //
|
||||
.map(this::updateNodeState) //
|
||||
.filter(ElasticsearchHost::isOnline) //
|
||||
.map(elasticsearchHost -> {
|
||||
LOG.trace("findActiveForState returning host " + elasticsearchHost);
|
||||
return elasticsearchHost;
|
||||
}).map(ElasticsearchHost::getEndpoint) //
|
||||
.takeLast(1) //
|
||||
.next();
|
||||
}
|
||||
|
||||
private ElasticsearchHost updateNodeState(Tuple2<InetSocketAddress, State> tuple2) {
|
||||
@@ -131,28 +148,35 @@ class MultiNodeHostProvider implements HostProvider<MultiNodeHostProvider> {
|
||||
return elasticsearchHost;
|
||||
}
|
||||
|
||||
private Flux<Tuple2<InetSocketAddress, State>> nodes(@Nullable State state) {
|
||||
private Flux<Tuple2<InetSocketAddress, State>> checkNodes(@Nullable State state) {
|
||||
|
||||
LOG.trace("checkNodes() with state " + state);
|
||||
|
||||
return Flux.fromIterable(hosts()) //
|
||||
.filter(entry -> state == null || entry.getState().equals(state)) //
|
||||
.map(ElasticsearchHost::getEndpoint) //
|
||||
.flatMap(host -> {
|
||||
.concatMap(host -> {
|
||||
|
||||
LOG.trace("checking host " + host);
|
||||
|
||||
Mono<ClientResponse> clientResponseMono = createWebClient(host) //
|
||||
.head().uri("/") //
|
||||
.headers(httpHeaders -> httpHeaders.addAll(headersSupplier.get())) //
|
||||
.exchangeToMono(Mono::just) //
|
||||
.timeout(Duration.ofSeconds(1)) //
|
||||
.doOnError(throwable -> {
|
||||
LOG.trace("error checking host " + host + ", " + throwable.getMessage());
|
||||
hosts.put(host, new ElasticsearchHost(host, State.OFFLINE));
|
||||
clientProvider.getErrorListener().accept(throwable);
|
||||
});
|
||||
|
||||
return Mono.just(host) //
|
||||
.zipWith( //
|
||||
clientResponseMono.flatMap(it -> it.releaseBody() //
|
||||
.thenReturn(it.statusCode().isError() ? State.OFFLINE : State.ONLINE)));
|
||||
.zipWith(clientResponseMono.flatMap(it -> it.releaseBody() //
|
||||
.thenReturn(it.statusCode().isError() ? State.OFFLINE : State.ONLINE)));
|
||||
}) //
|
||||
.onErrorContinue((throwable, o) -> clientProvider.getErrorListener().accept(throwable));
|
||||
.map(tuple -> {
|
||||
LOG.trace("check result " + tuple);
|
||||
return tuple;
|
||||
}).onErrorContinue((throwable, o) -> clientProvider.getErrorListener().accept(throwable));
|
||||
}
|
||||
|
||||
private List<ElasticsearchHost> hosts() {
|
||||
|
||||
+311
-39
@@ -22,16 +22,13 @@ import java.net.ConnectException;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
||||
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
|
||||
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
|
||||
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.flush.FlushRequest;
|
||||
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
|
||||
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
|
||||
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
|
||||
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
|
||||
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest;
|
||||
@@ -42,6 +39,7 @@ import org.elasticsearch.action.bulk.BulkResponse;
|
||||
import org.elasticsearch.action.delete.DeleteRequest;
|
||||
import org.elasticsearch.action.delete.DeleteResponse;
|
||||
import org.elasticsearch.action.get.GetRequest;
|
||||
import org.elasticsearch.action.get.MultiGetItemResponse;
|
||||
import org.elasticsearch.action.get.MultiGetRequest;
|
||||
import org.elasticsearch.action.index.IndexRequest;
|
||||
import org.elasticsearch.action.index.IndexResponse;
|
||||
@@ -51,16 +49,12 @@ import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.action.update.UpdateRequest;
|
||||
import org.elasticsearch.action.update.UpdateResponse;
|
||||
import org.elasticsearch.client.GetAliasesResponse;
|
||||
import org.elasticsearch.client.indices.GetFieldMappingsRequest;
|
||||
import org.elasticsearch.client.indices.GetFieldMappingsResponse;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesResponse;
|
||||
import org.elasticsearch.client.indices.IndexTemplatesExistRequest;
|
||||
import org.elasticsearch.client.indices.PutIndexTemplateRequest;
|
||||
import org.elasticsearch.client.indices.*;
|
||||
import org.elasticsearch.index.get.GetResult;
|
||||
import org.elasticsearch.index.reindex.BulkByScrollResponse;
|
||||
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
|
||||
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
|
||||
import org.elasticsearch.script.mustache.SearchTemplateRequest;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.search.aggregations.Aggregation;
|
||||
import org.elasticsearch.search.suggest.Suggest;
|
||||
@@ -166,9 +160,9 @@ public interface ReactiveElasticsearchClient {
|
||||
* @param consumer never {@literal null}.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-multi-get.html">Multi Get API on
|
||||
* elastic.co</a>
|
||||
* @return the {@link Flux} emitting the {@link GetResult result}.
|
||||
* @return the {@link Flux} emitting the {@link MultiGetItemResponse result}.
|
||||
*/
|
||||
default Flux<GetResult> multiGet(Consumer<MultiGetRequest> consumer) {
|
||||
default Flux<MultiGetItemResponse> multiGet(Consumer<MultiGetRequest> consumer) {
|
||||
|
||||
MultiGetRequest request = new MultiGetRequest();
|
||||
consumer.accept(request);
|
||||
@@ -182,9 +176,9 @@ public interface ReactiveElasticsearchClient {
|
||||
* @param multiGetRequest must not be {@literal null}.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-multi-get.html">Multi Get API on
|
||||
* elastic.co</a>
|
||||
* @return the {@link Flux} emitting the {@link GetResult result}.
|
||||
* @return the {@link Flux} emitting the {@link MultiGetItemResponse result}.
|
||||
*/
|
||||
default Flux<GetResult> multiGet(MultiGetRequest multiGetRequest) {
|
||||
default Flux<MultiGetItemResponse> multiGet(MultiGetRequest multiGetRequest) {
|
||||
return multiGet(HttpHeaders.EMPTY, multiGetRequest);
|
||||
}
|
||||
|
||||
@@ -196,9 +190,9 @@ public interface ReactiveElasticsearchClient {
|
||||
* @param multiGetRequest must not be {@literal null}.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-multi-get.html">Multi Get API on
|
||||
* elastic.co</a>
|
||||
* @return the {@link Flux} emitting the {@link GetResult result}.
|
||||
* @return the {@link Flux} emitting the {@link MultiGetItemResponse result}.
|
||||
*/
|
||||
Flux<GetResult> multiGet(HttpHeaders headers, MultiGetRequest multiGetRequest);
|
||||
Flux<MultiGetItemResponse> multiGet(HttpHeaders headers, MultiGetRequest multiGetRequest);
|
||||
|
||||
/**
|
||||
* Checks for the existence of a document. Emits {@literal true} if it exists, {@literal false} otherwise.
|
||||
@@ -277,6 +271,14 @@ public interface ReactiveElasticsearchClient {
|
||||
*/
|
||||
Indices indices();
|
||||
|
||||
/**
|
||||
* Gain Access to cluster related commands.
|
||||
*
|
||||
* @return Cluster implementations
|
||||
* @since 4.2
|
||||
*/
|
||||
Cluster cluster();
|
||||
|
||||
/**
|
||||
* Execute an {@link UpdateRequest} against the {@literal update} API to alter a document.
|
||||
*
|
||||
@@ -394,6 +396,43 @@ public interface ReactiveElasticsearchClient {
|
||||
*/
|
||||
Mono<Long> count(HttpHeaders headers, SearchRequest searchRequest);
|
||||
|
||||
/**
|
||||
* Executes a {@link SearchTemplateRequest} against the {@literal search template} API.
|
||||
*
|
||||
* @param consumer must not be {@literal null}.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-template.html">Search Template
|
||||
* API on elastic.co</a>
|
||||
* @return the {@link Flux} emitting {@link SearchHit hits} one by one.
|
||||
*/
|
||||
default Flux<SearchHit> searchTemplate(Consumer<SearchTemplateRequest> consumer) {
|
||||
SearchTemplateRequest request = new SearchTemplateRequest();
|
||||
consumer.accept(request);
|
||||
return searchTemplate(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a {@link SearchTemplateRequest} against the {@literal search template} API.
|
||||
*
|
||||
* @param searchTemplateRequest must not be {@literal null}.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-template.html">Search Template
|
||||
* API on elastic.co</a>
|
||||
* @return the {@link Flux} emitting {@link SearchHit hits} one by one.
|
||||
*/
|
||||
default Flux<SearchHit> searchTemplate(SearchTemplateRequest searchTemplateRequest) {
|
||||
return searchTemplate(HttpHeaders.EMPTY, searchTemplateRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a {@link SearchTemplateRequest} against the {@literal search template} API.
|
||||
*
|
||||
* @param headers Use {@link HttpHeaders} to provide eg. authentication data. Must not be {@literal null}.
|
||||
* @param searchTemplateRequest must not be {@literal null}.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-template.html">Search Template
|
||||
* API on elastic.co</a>
|
||||
* @return the {@link Flux} emitting {@link SearchHit hits} one by one.
|
||||
*/
|
||||
Flux<SearchHit> searchTemplate(HttpHeaders headers, SearchTemplateRequest searchTemplateRequest);
|
||||
|
||||
/**
|
||||
* Execute a {@link SearchRequest} against the {@literal search} API.
|
||||
*
|
||||
@@ -747,20 +786,53 @@ public interface ReactiveElasticsearchClient {
|
||||
interface Indices {
|
||||
|
||||
/**
|
||||
* Execute the given {@link GetIndexRequest} against the {@literal indices} API.
|
||||
* Execute the given {@link org.elasticsearch.action.admin.indices.get.GetIndexRequest} against the
|
||||
* {@literal indices} API.
|
||||
*
|
||||
* @param consumer never {@literal null}.
|
||||
* @return the {@link Mono} emitting {@literal true} if the index exists, {@literal false} otherwise.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-exists.html"> Indices
|
||||
* Exists API on elastic.co</a>
|
||||
* @deprecated since 4.2
|
||||
*/
|
||||
default Mono<Boolean> existsIndex(Consumer<GetIndexRequest> consumer) {
|
||||
@Deprecated
|
||||
default Mono<Boolean> existsIndex(Consumer<org.elasticsearch.action.admin.indices.get.GetIndexRequest> consumer) {
|
||||
|
||||
GetIndexRequest request = new GetIndexRequest();
|
||||
org.elasticsearch.action.admin.indices.get.GetIndexRequest request = new org.elasticsearch.action.admin.indices.get.GetIndexRequest();
|
||||
consumer.accept(request);
|
||||
return existsIndex(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given {@link org.elasticsearch.action.admin.indices.get.GetIndexRequest} against the
|
||||
* {@literal indices} API.
|
||||
*
|
||||
* @param getIndexRequest must not be {@literal null}.
|
||||
* @return the {@link Mono} emitting {@literal true} if the index exists, {@literal false} otherwise.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-exists.html"> Indices
|
||||
* Exists API on elastic.co</a>
|
||||
* @deprecated since 4.2, use {@link #existsIndex(GetIndexRequest)}
|
||||
*/
|
||||
@Deprecated
|
||||
default Mono<Boolean> existsIndex(org.elasticsearch.action.admin.indices.get.GetIndexRequest getIndexRequest) {
|
||||
return existsIndex(HttpHeaders.EMPTY, getIndexRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given {@link org.elasticsearch.action.admin.indices.get.GetIndexRequest} against the
|
||||
* {@literal indices} API.
|
||||
*
|
||||
* @param headers Use {@link HttpHeaders} to provide eg. authentication data. Must not be {@literal null}.
|
||||
* @param getIndexRequest must not be {@literal null}.
|
||||
* @return the {@link Mono} emitting {@literal true} if the index exists, {@literal false} otherwise.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-exists.html"> Indices
|
||||
* Exists API on elastic.co</a>
|
||||
* @deprecated since 4.2, use {@link #existsIndex(HttpHeaders, GetIndexRequest)}
|
||||
*/
|
||||
@Deprecated
|
||||
Mono<Boolean> existsIndex(HttpHeaders headers,
|
||||
org.elasticsearch.action.admin.indices.get.GetIndexRequest getIndexRequest);
|
||||
|
||||
/**
|
||||
* Execute the given {@link GetIndexRequest} against the {@literal indices} API.
|
||||
*
|
||||
@@ -768,6 +840,7 @@ public interface ReactiveElasticsearchClient {
|
||||
* @return the {@link Mono} emitting {@literal true} if the index exists, {@literal false} otherwise.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-exists.html"> Indices
|
||||
* Exists API on elastic.co</a>
|
||||
* @since 4.2
|
||||
*/
|
||||
default Mono<Boolean> existsIndex(GetIndexRequest getIndexRequest) {
|
||||
return existsIndex(HttpHeaders.EMPTY, getIndexRequest);
|
||||
@@ -781,6 +854,7 @@ public interface ReactiveElasticsearchClient {
|
||||
* @return the {@link Mono} emitting {@literal true} if the index exists, {@literal false} otherwise.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-exists.html"> Indices
|
||||
* Exists API on elastic.co</a>
|
||||
* @since 4.2
|
||||
*/
|
||||
Mono<Boolean> existsIndex(HttpHeaders headers, GetIndexRequest getIndexRequest);
|
||||
|
||||
@@ -826,21 +900,58 @@ public interface ReactiveElasticsearchClient {
|
||||
Mono<Boolean> deleteIndex(HttpHeaders headers, DeleteIndexRequest deleteIndexRequest);
|
||||
|
||||
/**
|
||||
* Execute the given {@link CreateIndexRequest} against the {@literal indices} API.
|
||||
* Execute the given {@link org.elasticsearch.action.admin.indices.create.CreateIndexRequest} against the
|
||||
* {@literal indices} API.
|
||||
*
|
||||
* @param consumer never {@literal null}.
|
||||
* @return a {@link Mono} signalling successful operation completion or an {@link Mono#error(Throwable) error} if
|
||||
* eg. the index already exist.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html"> Indices
|
||||
* Create API on elastic.co</a>
|
||||
* @deprecated since 4.2
|
||||
*/
|
||||
default Mono<Boolean> createIndex(Consumer<CreateIndexRequest> consumer) {
|
||||
@Deprecated
|
||||
default Mono<Boolean> createIndex(
|
||||
Consumer<org.elasticsearch.action.admin.indices.create.CreateIndexRequest> consumer) {
|
||||
|
||||
CreateIndexRequest request = new CreateIndexRequest();
|
||||
org.elasticsearch.action.admin.indices.create.CreateIndexRequest request = new org.elasticsearch.action.admin.indices.create.CreateIndexRequest();
|
||||
consumer.accept(request);
|
||||
return createIndex(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given {@link org.elasticsearch.action.admin.indices.create.CreateIndexRequest} against the
|
||||
* {@literal indices} API.
|
||||
*
|
||||
* @param createIndexRequest must not be {@literal null}.
|
||||
* @return a {@link Mono} signalling successful operation completion or an {@link Mono#error(Throwable) error} if
|
||||
* eg. the index already exist.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html"> Indices
|
||||
* Create API on elastic.co</a>
|
||||
* @deprecated since 4.2, use {@link #createIndex(CreateIndexRequest)}
|
||||
*/
|
||||
@Deprecated
|
||||
default Mono<Boolean> createIndex(
|
||||
org.elasticsearch.action.admin.indices.create.CreateIndexRequest createIndexRequest) {
|
||||
return createIndex(HttpHeaders.EMPTY, createIndexRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given {@link org.elasticsearch.action.admin.indices.create.CreateIndexRequest} against the
|
||||
* {@literal indices} API.
|
||||
*
|
||||
* @param headers Use {@link HttpHeaders} to provide eg. authentication data. Must not be {@literal null}.
|
||||
* @param createIndexRequest must not be {@literal null}.
|
||||
* @return a {@link Mono} signalling successful operation completion or an {@link Mono#error(Throwable) error} if
|
||||
* eg. the index already exist.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html"> Indices
|
||||
* Create API on elastic.co</a>
|
||||
* @deprecated since 4.2, use {@link #createIndex(HttpHeaders, CreateIndexRequest)}
|
||||
*/
|
||||
@Deprecated
|
||||
Mono<Boolean> createIndex(HttpHeaders headers,
|
||||
org.elasticsearch.action.admin.indices.create.CreateIndexRequest createIndexRequest);
|
||||
|
||||
/**
|
||||
* Execute the given {@link CreateIndexRequest} against the {@literal indices} API.
|
||||
*
|
||||
@@ -849,6 +960,7 @@ public interface ReactiveElasticsearchClient {
|
||||
* eg. the index already exist.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html"> Indices
|
||||
* Create API on elastic.co</a>
|
||||
* @since 4.2
|
||||
*/
|
||||
default Mono<Boolean> createIndex(CreateIndexRequest createIndexRequest) {
|
||||
return createIndex(HttpHeaders.EMPTY, createIndexRequest);
|
||||
@@ -863,6 +975,7 @@ public interface ReactiveElasticsearchClient {
|
||||
* eg. the index already exist.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html"> Indices
|
||||
* Create API on elastic.co</a>
|
||||
* @since 4.2
|
||||
*/
|
||||
Mono<Boolean> createIndex(HttpHeaders headers, CreateIndexRequest createIndexRequest);
|
||||
|
||||
@@ -990,7 +1103,8 @@ public interface ReactiveElasticsearchClient {
|
||||
Mono<Void> refreshIndex(HttpHeaders headers, RefreshRequest refreshRequest);
|
||||
|
||||
/**
|
||||
* Execute the given {@link PutMappingRequest} against the {@literal indices} API.
|
||||
* Execute the given {@link org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest} against the
|
||||
* {@literal indices} API.
|
||||
*
|
||||
* @param consumer never {@literal null}.
|
||||
* @return a {@link Mono} signalling operation completion or an {@link Mono#error(Throwable) error} if eg. the index
|
||||
@@ -1000,12 +1114,14 @@ public interface ReactiveElasticsearchClient {
|
||||
* @deprecated since 4.1, use {@link #putMapping(Consumer)}
|
||||
*/
|
||||
@Deprecated
|
||||
default Mono<Boolean> updateMapping(Consumer<PutMappingRequest> consumer) {
|
||||
default Mono<Boolean> updateMapping(
|
||||
Consumer<org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest> consumer) {
|
||||
return putMapping(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given {@link PutMappingRequest} against the {@literal indices} API.
|
||||
* Execute the given {@link org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest} against the
|
||||
* {@literal indices} API.
|
||||
*
|
||||
* @param putMappingRequest must not be {@literal null}.
|
||||
* @return a {@link Mono} signalling operation completion or an {@link Mono#error(Throwable) error} if eg. the index
|
||||
@@ -1015,12 +1131,14 @@ public interface ReactiveElasticsearchClient {
|
||||
* @deprecated since 4.1, use {@link #putMapping(PutMappingRequest)}
|
||||
*/
|
||||
@Deprecated
|
||||
default Mono<Boolean> updateMapping(PutMappingRequest putMappingRequest) {
|
||||
default Mono<Boolean> updateMapping(
|
||||
org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest putMappingRequest) {
|
||||
return putMapping(putMappingRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given {@link PutMappingRequest} against the {@literal indices} API.
|
||||
* Execute the given {@link org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest} against the
|
||||
* {@literal indices} API.
|
||||
*
|
||||
* @param headers Use {@link HttpHeaders} to provide eg. authentication data. Must not be {@literal null}.
|
||||
* @param putMappingRequest must not be {@literal null}.
|
||||
@@ -1031,26 +1149,64 @@ public interface ReactiveElasticsearchClient {
|
||||
* @deprecated since 4.1, use {@link #putMapping(HttpHeaders, PutMappingRequest)}
|
||||
*/
|
||||
@Deprecated
|
||||
default Mono<Boolean> updateMapping(HttpHeaders headers, PutMappingRequest putMappingRequest) {
|
||||
default Mono<Boolean> updateMapping(HttpHeaders headers,
|
||||
org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest putMappingRequest) {
|
||||
return putMapping(headers, putMappingRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given {@link PutMappingRequest} against the {@literal indices} API.
|
||||
* Execute the given {@link org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest} against the
|
||||
* {@literal indices} API.
|
||||
*
|
||||
* @param consumer never {@literal null}.
|
||||
* @return a {@link Mono} signalling operation completion or an {@link Mono#error(Throwable) error} if eg. the index
|
||||
* does not exist.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html"> Indices
|
||||
* Put Mapping API on elastic.co</a>
|
||||
* @deprecated since 4.2
|
||||
*/
|
||||
default Mono<Boolean> putMapping(Consumer<PutMappingRequest> consumer) {
|
||||
@Deprecated
|
||||
default Mono<Boolean> putMapping(
|
||||
Consumer<org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest> consumer) {
|
||||
|
||||
PutMappingRequest request = new PutMappingRequest();
|
||||
org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest request = new org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest();
|
||||
consumer.accept(request);
|
||||
return putMapping(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given {@link org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest} against the
|
||||
* {@literal indices} API.
|
||||
*
|
||||
* @param putMappingRequest must not be {@literal null}.
|
||||
* @return a {@link Mono} signalling operation completion or an {@link Mono#error(Throwable) error} if eg. the index
|
||||
* does not exist.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html"> Indices
|
||||
* Put Mapping API on elastic.co</a>
|
||||
* @deprecated since 4.2, use {@link #putMapping(PutMappingRequest)}
|
||||
*/
|
||||
@Deprecated
|
||||
default Mono<Boolean> putMapping(
|
||||
org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest putMappingRequest) {
|
||||
return putMapping(HttpHeaders.EMPTY, putMappingRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given {@link org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest} against the
|
||||
* {@literal indices} API.
|
||||
*
|
||||
* @param headers Use {@link HttpHeaders} to provide eg. authentication data. Must not be {@literal null}.
|
||||
* @param putMappingRequest must not be {@literal null}.
|
||||
* @return a {@link Mono} signalling operation completion or an {@link Mono#error(Throwable) error} if eg. the index
|
||||
* does not exist.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html"> Indices
|
||||
* Put Mapping API on elastic.co</a>
|
||||
* @deprecated since 4.2, use {@link #putMapping(HttpHeaders, PutMappingRequest)}
|
||||
*/
|
||||
@Deprecated
|
||||
Mono<Boolean> putMapping(HttpHeaders headers,
|
||||
org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest putMappingRequest);
|
||||
|
||||
/**
|
||||
* Execute the given {@link PutMappingRequest} against the {@literal indices} API.
|
||||
*
|
||||
@@ -1059,6 +1215,7 @@ public interface ReactiveElasticsearchClient {
|
||||
* does not exist.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html"> Indices
|
||||
* Put Mapping API on elastic.co</a>
|
||||
* @since 4.2
|
||||
*/
|
||||
default Mono<Boolean> putMapping(PutMappingRequest putMappingRequest) {
|
||||
return putMapping(HttpHeaders.EMPTY, putMappingRequest);
|
||||
@@ -1073,6 +1230,7 @@ public interface ReactiveElasticsearchClient {
|
||||
* does not exist.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html"> Indices
|
||||
* Put Mapping API on elastic.co</a>
|
||||
* @since 4.2
|
||||
*/
|
||||
Mono<Boolean> putMapping(HttpHeaders headers, PutMappingRequest putMappingRequest);
|
||||
|
||||
@@ -1162,7 +1320,8 @@ public interface ReactiveElasticsearchClient {
|
||||
Mono<GetSettingsResponse> getSettings(HttpHeaders headers, GetSettingsRequest getSettingsRequest);
|
||||
|
||||
/**
|
||||
* Execute the given {@link GetMappingsRequest} against the {@literal indices} API.
|
||||
* Execute the given {@link org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest} against the
|
||||
* {@literal indices} API.
|
||||
*
|
||||
* @param consumer never {@literal null}.
|
||||
* @return a {@link Mono} signalling operation completion or an {@link Mono#error(Throwable) error} if eg. the index
|
||||
@@ -1170,14 +1329,52 @@ public interface ReactiveElasticsearchClient {
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-mapping.html"> Indices
|
||||
* Flush API on elastic.co</a>
|
||||
* @since 4.1
|
||||
* @deprecated since 4.2
|
||||
*/
|
||||
default Mono<GetMappingsResponse> getMapping(Consumer<GetMappingsRequest> consumer) {
|
||||
@Deprecated
|
||||
default Mono<org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse> getMapping(
|
||||
Consumer<org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest> consumer) {
|
||||
|
||||
GetMappingsRequest request = new GetMappingsRequest();
|
||||
org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest request = new org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest();
|
||||
consumer.accept(request);
|
||||
return getMapping(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given {@link org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest} against the
|
||||
* {@literal indices} API.
|
||||
*
|
||||
* @param getMappingsRequest must not be {@literal null}.
|
||||
* @return a {@link Mono} signalling operation completion or an {@link Mono#error(Throwable) error} if eg. the index
|
||||
* does not exist.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-mapping.html"> Indices
|
||||
* Flush API on elastic.co</a>
|
||||
* @since 4.1
|
||||
* @deprecated since 4.2, use {@link #getMapping(GetMappingsRequest)}
|
||||
*/
|
||||
@Deprecated
|
||||
default Mono<org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse> getMapping(
|
||||
org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest getMappingsRequest) {
|
||||
return getMapping(HttpHeaders.EMPTY, getMappingsRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given {@link org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest} against the
|
||||
* {@literal indices} API.
|
||||
*
|
||||
* @param headers Use {@link HttpHeaders} to provide eg. authentication data. Must not be {@literal null}.
|
||||
* @param getMappingsRequest must not be {@literal null}.
|
||||
* @return a {@link Mono} signalling operation completion or an {@link Mono#error(Throwable) error} if eg. the index
|
||||
* does not exist.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-mapping.html"> Indices
|
||||
* Flush API on elastic.co</a>
|
||||
* @since 4.1
|
||||
* @deprecated since 4.2, use {@link #getMapping(HttpHeaders, GetMappingsRequest)}
|
||||
*/
|
||||
@Deprecated
|
||||
Mono<org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse> getMapping(HttpHeaders headers,
|
||||
org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest getMappingsRequest);
|
||||
|
||||
/**
|
||||
* Execute the given {@link GetMappingsRequest} against the {@literal indices} API.
|
||||
*
|
||||
@@ -1185,8 +1382,8 @@ public interface ReactiveElasticsearchClient {
|
||||
* @return a {@link Mono} signalling operation completion or an {@link Mono#error(Throwable) error} if eg. the index
|
||||
* does not exist.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-mapping.html"> Indices
|
||||
* Flush API on elastic.co</a>
|
||||
* @since 4.1
|
||||
* Get mapping API on elastic.co</a>
|
||||
* @since 4.2
|
||||
*/
|
||||
default Mono<GetMappingsResponse> getMapping(GetMappingsRequest getMappingsRequest) {
|
||||
return getMapping(HttpHeaders.EMPTY, getMappingsRequest);
|
||||
@@ -1200,8 +1397,8 @@ public interface ReactiveElasticsearchClient {
|
||||
* @return a {@link Mono} signalling operation completion or an {@link Mono#error(Throwable) error} if eg. the index
|
||||
* does not exist.
|
||||
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-mapping.html"> Indices
|
||||
* Flush API on elastic.co</a>
|
||||
* @since 4.1
|
||||
* Get mapping API on elastic.co</a>
|
||||
* @since 4.2
|
||||
*/
|
||||
Mono<GetMappingsResponse> getMapping(HttpHeaders headers, GetMappingsRequest getMappingsRequest);
|
||||
|
||||
@@ -1456,5 +1653,80 @@ public interface ReactiveElasticsearchClient {
|
||||
* @since 4.1
|
||||
*/
|
||||
Mono<Boolean> deleteTemplate(HttpHeaders headers, DeleteIndexTemplateRequest deleteIndexTemplateRequest);
|
||||
|
||||
/**
|
||||
* Execute the given {@link GetIndexRequest} against the {@literal indices} API.
|
||||
*
|
||||
* @param consumer never {@literal null}.
|
||||
* @return the {@link Mono} emitting the response
|
||||
* @since 4.2
|
||||
*/
|
||||
default Mono<GetIndexResponse> getIndex(Consumer<GetIndexRequest> consumer) {
|
||||
GetIndexRequest getIndexRequest = new GetIndexRequest();
|
||||
consumer.accept(getIndexRequest);
|
||||
return getIndex(getIndexRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given {@link GetIndexRequest} against the {@literal indices} API.
|
||||
*
|
||||
* @param getIndexRequest must not be {@literal null}
|
||||
* @return the {@link Mono} emitting the response
|
||||
* @since 4.2
|
||||
*/
|
||||
default Mono<GetIndexResponse> getIndex(GetIndexRequest getIndexRequest) {
|
||||
return getIndex(HttpHeaders.EMPTY, getIndexRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given {@link GetIndexRequest} against the {@literal indices} API.
|
||||
*
|
||||
* @param headers Use {@link HttpHeaders} to provide eg. authentication data. Must not be {@literal null}.
|
||||
* @param getIndexRequest must not be {@literal null}
|
||||
* @return the {@link Mono} emitting the response
|
||||
* @since 4.2
|
||||
*/
|
||||
Mono<GetIndexResponse> getIndex(HttpHeaders headers, GetIndexRequest getIndexRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulation of methods for accessing the Cluster API.
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.2
|
||||
*/
|
||||
interface Cluster {
|
||||
|
||||
/**
|
||||
* Execute the given {{@link ClusterHealthRequest}} against the {@literal cluster} API.
|
||||
*
|
||||
* @param consumer never {@literal null}.
|
||||
* @return Mono emitting the {@link ClusterHealthResponse}.
|
||||
*/
|
||||
default Mono<ClusterHealthResponse> health(Consumer<ClusterHealthRequest> consumer) {
|
||||
|
||||
ClusterHealthRequest clusterHealthRequest = new ClusterHealthRequest();
|
||||
consumer.accept(clusterHealthRequest);
|
||||
return health(clusterHealthRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given {{@link ClusterHealthRequest}} against the {@literal cluster} API.
|
||||
*
|
||||
* @param clusterHealthRequest must not be {@literal null} // * @return Mono emitting the
|
||||
* {@link ClusterHealthResponse}.
|
||||
*/
|
||||
default Mono<ClusterHealthResponse> health(ClusterHealthRequest clusterHealthRequest) {
|
||||
return health(HttpHeaders.EMPTY, clusterHealthRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given {{@link ClusterHealthRequest}} against the {@literal cluster} API.
|
||||
*
|
||||
* @param headers Use {@link HttpHeaders} to provide eg. authentication data. Must not be {@literal null}.
|
||||
* @param clusterHealthRequest must not be {@literal null} // * @return Mono emitting the
|
||||
* {@link ClusterHealthResponse}.
|
||||
*/
|
||||
Mono<ClusterHealthResponse> health(HttpHeaders headers, ClusterHealthRequest clusterHealthRequest);
|
||||
}
|
||||
}
|
||||
|
||||
+71
-8
@@ -3,15 +3,12 @@ package org.springframework.data.elasticsearch.client.reactive;
|
||||
import java.io.IOException;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
|
||||
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
|
||||
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
|
||||
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.flush.FlushRequest;
|
||||
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
|
||||
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
|
||||
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
|
||||
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest;
|
||||
@@ -28,18 +25,24 @@ import org.elasticsearch.action.search.SearchScrollRequest;
|
||||
import org.elasticsearch.action.update.UpdateRequest;
|
||||
import org.elasticsearch.client.Request;
|
||||
import org.elasticsearch.client.core.CountRequest;
|
||||
import org.elasticsearch.client.indices.CreateIndexRequest;
|
||||
import org.elasticsearch.client.indices.GetFieldMappingsRequest;
|
||||
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.elasticsearch.client.indices.PutMappingRequest;
|
||||
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
|
||||
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
|
||||
import org.elasticsearch.script.mustache.SearchTemplateRequest;
|
||||
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
|
||||
import org.springframework.data.elasticsearch.client.util.RequestConverters;
|
||||
|
||||
/**
|
||||
* @author Roman Puchkovskiy
|
||||
* @author Farid Faoudi
|
||||
* @author George Popides
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface RequestCreator {
|
||||
@@ -48,6 +51,10 @@ public interface RequestCreator {
|
||||
return RequestConverters::search;
|
||||
}
|
||||
|
||||
default Function<SearchTemplateRequest, Request> searchTemplate() {
|
||||
return RequestConverters::searchTemplate;
|
||||
}
|
||||
|
||||
default Function<SearchScrollRequest, Request> scroll() {
|
||||
return RequestConverters::searchScroll;
|
||||
}
|
||||
@@ -113,7 +120,18 @@ public interface RequestCreator {
|
||||
|
||||
// --> INDICES
|
||||
|
||||
default Function<GetIndexRequest, Request> indexExists() {
|
||||
/**
|
||||
* @deprecated since 4.2
|
||||
*/
|
||||
@Deprecated
|
||||
default Function<org.elasticsearch.action.admin.indices.get.GetIndexRequest, Request> indexExists() {
|
||||
return RequestConverters::indexExists;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.2
|
||||
*/
|
||||
default Function<GetIndexRequest, Request> indexExistsRequest() {
|
||||
return RequestConverters::indexExists;
|
||||
}
|
||||
|
||||
@@ -121,7 +139,18 @@ public interface RequestCreator {
|
||||
return RequestConverters::indexDelete;
|
||||
}
|
||||
|
||||
default Function<CreateIndexRequest, Request> indexCreate() {
|
||||
/**
|
||||
* @deprecated since 4.2
|
||||
*/
|
||||
@Deprecated
|
||||
default Function<org.elasticsearch.action.admin.indices.create.CreateIndexRequest, Request> indexCreate() {
|
||||
return RequestConverters::indexCreate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.2
|
||||
*/
|
||||
default Function<CreateIndexRequest, Request> createIndexRequest() {
|
||||
return RequestConverters::indexCreate;
|
||||
}
|
||||
|
||||
@@ -137,7 +166,18 @@ public interface RequestCreator {
|
||||
return RequestConverters::indexRefresh;
|
||||
}
|
||||
|
||||
default Function<PutMappingRequest, Request> putMapping() {
|
||||
/**
|
||||
* @deprecated since 4.2
|
||||
*/
|
||||
@Deprecated
|
||||
default Function<org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest, Request> putMapping() {
|
||||
return RequestConverters::putMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.2
|
||||
*/
|
||||
default Function<PutMappingRequest, Request> putMappingRequest() {
|
||||
return RequestConverters::putMapping;
|
||||
}
|
||||
|
||||
@@ -158,8 +198,17 @@ public interface RequestCreator {
|
||||
|
||||
/**
|
||||
* @since 4.1
|
||||
* @deprecated since 4.2
|
||||
*/
|
||||
default Function<GetMappingsRequest, Request> getMapping() {
|
||||
@Deprecated
|
||||
default Function<org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest, Request> getMapping() {
|
||||
return RequestConverters::getMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.2
|
||||
*/
|
||||
default Function<GetMappingsRequest, Request> getMappingRequest() {
|
||||
return RequestConverters::getMapping;
|
||||
}
|
||||
|
||||
@@ -211,4 +260,18 @@ public interface RequestCreator {
|
||||
default Function<GetFieldMappingsRequest, Request> getFieldMapping() {
|
||||
return RequestConverters::getFieldMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.2
|
||||
*/
|
||||
default Function<GetIndexRequest, Request> getIndex() {
|
||||
return RequestConverters::getIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.2
|
||||
*/
|
||||
default Function<ClusterHealthRequest, Request> clusterHealth() {
|
||||
return RequestConverters::clusterHealth;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-7
@@ -19,12 +19,10 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.data.elasticsearch.client.ElasticsearchHost;
|
||||
import org.springframework.data.elasticsearch.client.ElasticsearchHost.State;
|
||||
import org.springframework.data.elasticsearch.client.NoReachableHostException;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
@@ -38,15 +36,12 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
class SingleNodeHostProvider implements HostProvider<SingleNodeHostProvider> {
|
||||
|
||||
private final WebClientProvider clientProvider;
|
||||
private final Supplier<HttpHeaders> headersSupplier;
|
||||
private final InetSocketAddress endpoint;
|
||||
private volatile ElasticsearchHost state;
|
||||
|
||||
SingleNodeHostProvider(WebClientProvider clientProvider, Supplier<HttpHeaders> headersSupplier,
|
||||
InetSocketAddress endpoint) {
|
||||
SingleNodeHostProvider(WebClientProvider clientProvider, InetSocketAddress endpoint) {
|
||||
|
||||
this.clientProvider = clientProvider;
|
||||
this.headersSupplier = headersSupplier;
|
||||
this.endpoint = endpoint;
|
||||
this.state = new ElasticsearchHost(this.endpoint, State.UNKNOWN);
|
||||
}
|
||||
@@ -60,7 +55,6 @@ class SingleNodeHostProvider implements HostProvider<SingleNodeHostProvider> {
|
||||
|
||||
return createWebClient(endpoint) //
|
||||
.head().uri("/") //
|
||||
.headers(httpHeaders -> httpHeaders.addAll(headersSupplier.get())) //
|
||||
.exchangeToMono(it -> {
|
||||
if (it.statusCode().isError()) {
|
||||
state = ElasticsearchHost.offline(endpoint);
|
||||
|
||||
+13
-3
@@ -101,7 +101,7 @@ public interface WebClientProvider {
|
||||
|
||||
/**
|
||||
* Obtain the {@link String pathPrefix} to be used.
|
||||
*
|
||||
*
|
||||
* @return the pathPrefix if set.
|
||||
* @since 4.0
|
||||
*/
|
||||
@@ -126,7 +126,7 @@ public interface WebClientProvider {
|
||||
|
||||
/**
|
||||
* Create a new instance of {@link WebClientProvider} where HTTP requests are called with the given path prefix.
|
||||
*
|
||||
*
|
||||
* @param pathPrefix Path prefix to add to requests
|
||||
* @return new instance of {@link WebClientProvider}
|
||||
* @since 4.0
|
||||
@@ -136,10 +136,20 @@ public interface WebClientProvider {
|
||||
/**
|
||||
* Create a new instance of {@link WebClientProvider} calling the given {@link Function} to configure the
|
||||
* {@link WebClient}.
|
||||
*
|
||||
*
|
||||
* @param webClientConfigurer configuration function
|
||||
* @return new instance of {@link WebClientProvider}
|
||||
* @since 4.0
|
||||
*/
|
||||
WebClientProvider withWebClientConfigurer(Function<WebClient, WebClient> webClientConfigurer);
|
||||
|
||||
/**
|
||||
* Create a new instance of {@link WebClientProvider} calling the given {@link Consumer} to configure the requests of
|
||||
* this {@link WebClient}.
|
||||
*
|
||||
* @param requestConfigurer request configuration callback
|
||||
* @return new instance of {@link WebClientProvider}
|
||||
* @since 4.3
|
||||
*/
|
||||
WebClientProvider withRequestConfigurer(Consumer<WebClient.RequestHeadersSpec<?>> requestConfigurer);
|
||||
}
|
||||
|
||||
+19
-7
@@ -20,6 +20,12 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.elasticsearch.client.analytics.InferencePipelineAggregationBuilder;
|
||||
import org.elasticsearch.client.analytics.ParsedInference;
|
||||
import org.elasticsearch.client.analytics.ParsedStringStats;
|
||||
import org.elasticsearch.client.analytics.ParsedTopMetrics;
|
||||
import org.elasticsearch.client.analytics.StringStatsAggregationBuilder;
|
||||
import org.elasticsearch.client.analytics.TopMetricsAggregationBuilder;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.xcontent.ContextParser;
|
||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||
@@ -44,6 +50,8 @@ import org.elasticsearch.search.aggregations.bucket.histogram.HistogramAggregati
|
||||
import org.elasticsearch.search.aggregations.bucket.histogram.ParsedAutoDateHistogram;
|
||||
import org.elasticsearch.search.aggregations.bucket.histogram.ParsedDateHistogram;
|
||||
import org.elasticsearch.search.aggregations.bucket.histogram.ParsedHistogram;
|
||||
import org.elasticsearch.search.aggregations.bucket.histogram.ParsedVariableWidthHistogram;
|
||||
import org.elasticsearch.search.aggregations.bucket.histogram.VariableWidthHistogramAggregationBuilder;
|
||||
import org.elasticsearch.search.aggregations.bucket.missing.MissingAggregationBuilder;
|
||||
import org.elasticsearch.search.aggregations.bucket.missing.ParsedMissing;
|
||||
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
|
||||
@@ -60,12 +68,7 @@ import org.elasticsearch.search.aggregations.bucket.range.ParsedRange;
|
||||
import org.elasticsearch.search.aggregations.bucket.range.RangeAggregationBuilder;
|
||||
import org.elasticsearch.search.aggregations.bucket.sampler.InternalSampler;
|
||||
import org.elasticsearch.search.aggregations.bucket.sampler.ParsedSampler;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.DoubleTerms;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.ParsedDoubleTerms;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.*;
|
||||
import org.elasticsearch.search.aggregations.metrics.*;
|
||||
import org.elasticsearch.search.aggregations.pipeline.*;
|
||||
import org.elasticsearch.search.suggest.Suggest;
|
||||
@@ -81,7 +84,7 @@ import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsea
|
||||
* <p>
|
||||
* Original implementation source {@link org.elasticsearch.client.RestHighLevelClient#getDefaultNamedXContents()} by
|
||||
* {@literal Elasticsearch} (<a href="https://www.elastic.co">https://www.elastic.co</a>) licensed under the Apache
|
||||
* License, Version 2.0.
|
||||
* License, Version 2.0. The latest version used from Elasticsearch is 7.10.2.
|
||||
* </p>
|
||||
* Modified for usage with {@link ReactiveElasticsearchClient}.
|
||||
* <p>
|
||||
@@ -126,9 +129,13 @@ public class NamedXContents {
|
||||
map.put(HistogramAggregationBuilder.NAME, (p, c) -> ParsedHistogram.fromXContent(p, (String) c));
|
||||
map.put(DateHistogramAggregationBuilder.NAME, (p, c) -> ParsedDateHistogram.fromXContent(p, (String) c));
|
||||
map.put(AutoDateHistogramAggregationBuilder.NAME, (p, c) -> ParsedAutoDateHistogram.fromXContent(p, (String) c));
|
||||
map.put(VariableWidthHistogramAggregationBuilder.NAME,
|
||||
(p, c) -> ParsedVariableWidthHistogram.fromXContent(p, (String) c));
|
||||
map.put(StringTerms.NAME, (p, c) -> ParsedStringTerms.fromXContent(p, (String) c));
|
||||
map.put(LongTerms.NAME, (p, c) -> ParsedLongTerms.fromXContent(p, (String) c));
|
||||
map.put(DoubleTerms.NAME, (p, c) -> ParsedDoubleTerms.fromXContent(p, (String) c));
|
||||
map.put(LongRareTerms.NAME, (p, c) -> ParsedLongRareTerms.fromXContent(p, (String) c));
|
||||
map.put(StringRareTerms.NAME, (p, c) -> ParsedStringRareTerms.fromXContent(p, (String) c));
|
||||
map.put(MissingAggregationBuilder.NAME, (p, c) -> ParsedMissing.fromXContent(p, (String) c));
|
||||
map.put(NestedAggregationBuilder.NAME, (p, c) -> ParsedNested.fromXContent(p, (String) c));
|
||||
map.put(ReverseNestedAggregationBuilder.NAME, (p, c) -> ParsedReverseNested.fromXContent(p, (String) c));
|
||||
@@ -142,10 +149,15 @@ public class NamedXContents {
|
||||
map.put(GeoDistanceAggregationBuilder.NAME, (p, c) -> ParsedGeoDistance.fromXContent(p, (String) c));
|
||||
map.put(FiltersAggregationBuilder.NAME, (p, c) -> ParsedFilters.fromXContent(p, (String) c));
|
||||
map.put(AdjacencyMatrixAggregationBuilder.NAME, (p, c) -> ParsedAdjacencyMatrix.fromXContent(p, (String) c));
|
||||
map.put(SignificantLongTerms.NAME, (p, c) -> ParsedSignificantLongTerms.fromXContent(p, (String) c));
|
||||
map.put(SignificantStringTerms.NAME, (p, c) -> ParsedSignificantStringTerms.fromXContent(p, (String) c));
|
||||
map.put(ScriptedMetricAggregationBuilder.NAME, (p, c) -> ParsedScriptedMetric.fromXContent(p, (String) c));
|
||||
map.put(IpRangeAggregationBuilder.NAME, (p, c) -> ParsedBinaryRange.fromXContent(p, (String) c));
|
||||
map.put(TopHitsAggregationBuilder.NAME, (p, c) -> ParsedTopHits.fromXContent(p, (String) c));
|
||||
map.put(CompositeAggregationBuilder.NAME, (p, c) -> ParsedComposite.fromXContent(p, (String) c));
|
||||
map.put(StringStatsAggregationBuilder.NAME, (p, c) -> ParsedStringStats.PARSER.parse(p, (String) c));
|
||||
map.put(TopMetricsAggregationBuilder.NAME, (p, c) -> ParsedTopMetrics.PARSER.parse(p, (String) c));
|
||||
map.put(InferencePipelineAggregationBuilder.NAME, (p, c) -> ParsedInference.fromXContent(p, (String) (c)));
|
||||
List<NamedXContentRegistry.Entry> entries = map.entrySet().stream().map(
|
||||
entry -> new NamedXContentRegistry.Entry(Aggregation.class, new ParseField(entry.getKey()), entry.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
+112
-3
@@ -98,6 +98,7 @@ import org.elasticsearch.index.reindex.DeleteByQueryRequest;
|
||||
import org.elasticsearch.index.reindex.ReindexRequest;
|
||||
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
|
||||
import org.elasticsearch.index.seqno.SequenceNumbers;
|
||||
import org.elasticsearch.script.mustache.SearchTemplateRequest;
|
||||
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
|
||||
import org.elasticsearch.tasks.TaskId;
|
||||
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
|
||||
@@ -106,8 +107,9 @@ import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Original implementation source {@link org.elasticsearch.client.RequestConverters} and
|
||||
* {@link org.elasticsearch.client.IndicesRequestConverters} by {@literal Elasticsearch}
|
||||
* Original implementation source {@link org.elasticsearch.client.RequestConverters},
|
||||
* {@link org.elasticsearch.client.IndicesRequestConverters} and
|
||||
* {@link org.elasticsearch.client.ClusterRequestConverters} by {@literal Elasticsearch}
|
||||
* (<a href="https://www.elastic.co">https://www.elastic.co</a>) licensed under the Apache License, Version 2.0.
|
||||
* </p>
|
||||
* Modified for usage with {@link ReactiveElasticsearchClient}.
|
||||
@@ -411,6 +413,21 @@ public class RequestConverters {
|
||||
return request;
|
||||
}
|
||||
|
||||
public static Request searchTemplate(SearchTemplateRequest templateRequest) {
|
||||
SearchRequest searchRequest = templateRequest.getRequest();
|
||||
|
||||
String endpoint = new EndpointBuilder().addCommaSeparatedPathParts(templateRequest.getRequest().indices())
|
||||
.addPathPart("_search").addPathPart("template").build();
|
||||
|
||||
Request request = new Request(HttpMethod.GET.name(), endpoint);
|
||||
Params params = new Params(request);
|
||||
addSearchRequestParams(params, searchRequest);
|
||||
|
||||
request.setEntity(createEntity(templateRequest, REQUEST_BODY_CONTENT_TYPE));
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a count request.
|
||||
*
|
||||
@@ -692,6 +709,22 @@ public class RequestConverters {
|
||||
return request;
|
||||
}
|
||||
|
||||
public static Request getIndex(org.elasticsearch.client.indices.GetIndexRequest getIndexRequest) {
|
||||
String[] indices = getIndexRequest.indices() == null ? Strings.EMPTY_ARRAY : getIndexRequest.indices();
|
||||
|
||||
String endpoint = endpoint(indices);
|
||||
Request request = new Request(HttpMethod.GET.name(), endpoint);
|
||||
|
||||
Params params = new Params(request);
|
||||
params.withIndicesOptions(getIndexRequest.indicesOptions());
|
||||
params.withLocal(getIndexRequest.local());
|
||||
params.withIncludeDefaults(getIndexRequest.includeDefaults());
|
||||
params.withHuman(getIndexRequest.humanReadable());
|
||||
params.withMasterTimeout(getIndexRequest.masterNodeTimeout());
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
public static Request indexDelete(DeleteIndexRequest deleteIndexRequest) {
|
||||
String endpoint = RequestConverters.endpoint(deleteIndexRequest.indices());
|
||||
Request request = new Request(HttpMethod.DELETE.name(), endpoint);
|
||||
@@ -719,6 +752,22 @@ public class RequestConverters {
|
||||
return request;
|
||||
}
|
||||
|
||||
public static Request indexExists(org.elasticsearch.client.indices.GetIndexRequest getIndexRequest) {
|
||||
// this can be called with no indices as argument by transport client, not via REST though
|
||||
if (getIndexRequest.indices() == null || getIndexRequest.indices().length == 0) {
|
||||
throw new IllegalArgumentException("indices are mandatory");
|
||||
}
|
||||
String endpoint = endpoint(getIndexRequest.indices(), "");
|
||||
Request request = new Request(HttpMethod.HEAD.name(), endpoint);
|
||||
|
||||
Params params = new Params(request);
|
||||
params.withLocal(getIndexRequest.local());
|
||||
params.withHuman(getIndexRequest.humanReadable());
|
||||
params.withIndicesOptions(getIndexRequest.indicesOptions());
|
||||
params.withIncludeDefaults(getIndexRequest.includeDefaults());
|
||||
return request;
|
||||
}
|
||||
|
||||
public static Request indexOpen(OpenIndexRequest openIndexRequest) {
|
||||
String endpoint = RequestConverters.endpoint(openIndexRequest.indices(), "_open");
|
||||
Request request = new Request(HttpMethod.POST.name(), endpoint);
|
||||
@@ -755,6 +804,19 @@ public class RequestConverters {
|
||||
return request;
|
||||
}
|
||||
|
||||
public static Request indexCreate(org.elasticsearch.client.indices.CreateIndexRequest createIndexRequest) {
|
||||
String endpoint = RequestConverters.endpoint(new String[] { createIndexRequest.index() });
|
||||
Request request = new Request(HttpMethod.PUT.name(), endpoint);
|
||||
|
||||
Params parameters = new Params(request);
|
||||
parameters.withTimeout(createIndexRequest.timeout());
|
||||
parameters.withMasterTimeout(createIndexRequest.masterNodeTimeout());
|
||||
parameters.withWaitForActiveShards(createIndexRequest.waitForActiveShards(), ActiveShardCount.DEFAULT);
|
||||
|
||||
request.setEntity(createEntity(createIndexRequest, RequestConverters.REQUEST_BODY_CONTENT_TYPE));
|
||||
return request;
|
||||
}
|
||||
|
||||
public static Request indexRefresh(RefreshRequest refreshRequest) {
|
||||
|
||||
String[] indices = refreshRequest.indices() == null ? Strings.EMPTY_ARRAY : refreshRequest.indices();
|
||||
@@ -767,6 +829,7 @@ public class RequestConverters {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Request putMapping(PutMappingRequest putMappingRequest) {
|
||||
// The concreteIndex is an internal concept, not applicable to requests made over the REST API.
|
||||
if (putMappingRequest.getConcreteIndex() != null) {
|
||||
@@ -784,6 +847,18 @@ public class RequestConverters {
|
||||
return request;
|
||||
}
|
||||
|
||||
public static Request putMapping(org.elasticsearch.client.indices.PutMappingRequest putMappingRequest) {
|
||||
Request request = new Request(HttpMethod.PUT.name(),
|
||||
RequestConverters.endpoint(putMappingRequest.indices(), "_mapping"));
|
||||
|
||||
new RequestConverters.Params(request) //
|
||||
.withTimeout(putMappingRequest.timeout()) //
|
||||
.withMasterTimeout(putMappingRequest.masterNodeTimeout()) //
|
||||
.withIncludeTypeName(false);
|
||||
request.setEntity(RequestConverters.createEntity(putMappingRequest, RequestConverters.REQUEST_BODY_CONTENT_TYPE));
|
||||
return request;
|
||||
}
|
||||
|
||||
public static Request flushIndex(FlushRequest flushRequest) {
|
||||
String[] indices = flushRequest.indices() == null ? Strings.EMPTY_ARRAY : flushRequest.indices();
|
||||
Request request = new Request(HttpMethod.POST.name(), RequestConverters.endpoint(indices, "_flush"));
|
||||
@@ -809,6 +884,19 @@ public class RequestConverters {
|
||||
return request;
|
||||
}
|
||||
|
||||
public static Request getMapping(org.elasticsearch.client.indices.GetMappingsRequest getMappingsRequest) {
|
||||
String[] indices = getMappingsRequest.indices() == null ? Strings.EMPTY_ARRAY : getMappingsRequest.indices();
|
||||
|
||||
Request request = new Request(HttpMethod.GET.name(), RequestConverters.endpoint(indices, "_mapping"));
|
||||
|
||||
RequestConverters.Params parameters = new RequestConverters.Params(request);
|
||||
parameters.withMasterTimeout(getMappingsRequest.masterNodeTimeout());
|
||||
parameters.withIndicesOptions(getMappingsRequest.indicesOptions());
|
||||
parameters.withLocal(getMappingsRequest.local());
|
||||
parameters.withIncludeTypeName(false);
|
||||
return request;
|
||||
}
|
||||
|
||||
public static Request getSettings(GetSettingsRequest getSettingsRequest) {
|
||||
String[] indices = getSettingsRequest.indices() == null ? Strings.EMPTY_ARRAY : getSettingsRequest.indices();
|
||||
String[] names = getSettingsRequest.names() == null ? Strings.EMPTY_ARRAY : getSettingsRequest.names();
|
||||
@@ -916,6 +1004,26 @@ public class RequestConverters {
|
||||
return request;
|
||||
}
|
||||
|
||||
public static Request clusterHealth(ClusterHealthRequest healthRequest) {
|
||||
String[] indices = healthRequest.indices() == null ? Strings.EMPTY_ARRAY : healthRequest.indices();
|
||||
String endpoint = new EndpointBuilder().addPathPartAsIs(new String[] { "_cluster/health" })
|
||||
.addCommaSeparatedPathParts(indices).build();
|
||||
|
||||
Request request = new Request("GET", endpoint);
|
||||
|
||||
RequestConverters.Params parameters = new Params(request);
|
||||
parameters.withWaitForStatus(healthRequest.waitForStatus());
|
||||
parameters.withWaitForNoRelocatingShards(healthRequest.waitForNoRelocatingShards());
|
||||
parameters.withWaitForNoInitializingShards(healthRequest.waitForNoInitializingShards());
|
||||
parameters.withWaitForActiveShards(healthRequest.waitForActiveShards(), ActiveShardCount.NONE);
|
||||
parameters.withWaitForNodes(healthRequest.waitForNodes());
|
||||
parameters.withWaitForEvents(healthRequest.waitForEvents());
|
||||
parameters.withTimeout(healthRequest.timeout());
|
||||
parameters.withMasterTimeout(healthRequest.masterNodeTimeout());
|
||||
parameters.withLocal(healthRequest.local()).withLevel(healthRequest.level());
|
||||
return request;
|
||||
}
|
||||
|
||||
static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) {
|
||||
|
||||
try {
|
||||
@@ -1344,7 +1452,8 @@ public class RequestConverters {
|
||||
// encode each part (e.g. index, type and id) separately before merging them into the path
|
||||
// we prepend "/" to the path part to make this path absolute, otherwise there can be issues with
|
||||
// paths that start with `-` or contain `:`
|
||||
URI uri = new URI(null, null, null, -1, '/' + pathPart, null, null);
|
||||
// the authority must be an empty string and not null, else paths that being with slashes could have them
|
||||
URI uri = new URI((String) null, "", "/" + pathPart, (String) null, (String) null);
|
||||
// manually encode any slash that each part may contain
|
||||
return uri.getRawPath().substring(1).replaceAll("/", "%2F");
|
||||
} catch (URISyntaxException e) {
|
||||
|
||||
+1
-3
@@ -120,8 +120,7 @@ public class ElasticsearchConfigurationSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given base package for entities, i.e. Elasticsearch specific types annotated with {@link Document} and
|
||||
* {@link Persistent}.
|
||||
* Scans the given base package for entities, i.e. Elasticsearch specific types annotated with {@link Document}.
|
||||
*
|
||||
* @param basePackage must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
@@ -137,7 +136,6 @@ public class ElasticsearchConfigurationSupport {
|
||||
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(
|
||||
false);
|
||||
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Document.class));
|
||||
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Persistent.class));
|
||||
|
||||
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
|
||||
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ import org.springframework.data.mapping.context.PersistentEntities;
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.1
|
||||
*/
|
||||
class PersistentEntitiesFactoryBean implements FactoryBean<PersistentEntities> {
|
||||
public class PersistentEntitiesFactoryBean implements FactoryBean<PersistentEntities> {
|
||||
|
||||
private final MappingElasticsearchConverter converter;
|
||||
|
||||
|
||||
+40
-49
@@ -29,17 +29,16 @@ import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
|
||||
import org.springframework.data.elasticsearch.annotations.Mapping;
|
||||
import org.springframework.data.elasticsearch.annotations.Setting;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.data.elasticsearch.core.index.AliasData;
|
||||
import org.springframework.data.elasticsearch.core.index.MappingBuilder;
|
||||
import org.springframework.data.elasticsearch.core.index.Settings;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.data.elasticsearch.core.query.AliasQuery;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Base implementation of {@link IndexOperations} common to Transport and Rest based Implementations of IndexOperations.
|
||||
@@ -90,41 +89,45 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
|
||||
@Override
|
||||
public boolean create() {
|
||||
|
||||
Document settings = null;
|
||||
|
||||
if (boundClass != null) {
|
||||
settings = createSettings(boundClass);
|
||||
}
|
||||
|
||||
return doCreate(getIndexCoordinates(), settings);
|
||||
Settings settings = boundClass != null ? createSettings(boundClass) : new Settings();
|
||||
return doCreate(getIndexCoordinates(), settings, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document createSettings(Class<?> clazz) {
|
||||
public Settings createSettings(Class<?> clazz) {
|
||||
|
||||
Assert.notNull(clazz, "clazz must not be null");
|
||||
|
||||
Document settings = null;
|
||||
|
||||
Setting setting = AnnotatedElementUtils.findMergedAnnotation(clazz, Setting.class);
|
||||
|
||||
if (setting != null) {
|
||||
settings = loadSettings(setting.settingPath());
|
||||
}
|
||||
|
||||
if (settings == null) {
|
||||
settings = getRequiredPersistentEntity(clazz).getDefaultSettings();
|
||||
}
|
||||
|
||||
return settings;
|
||||
ElasticsearchPersistentEntity<?> persistentEntity = getRequiredPersistentEntity(clazz);
|
||||
String settingPath = persistentEntity.settingPath();
|
||||
return hasText(settingPath) //
|
||||
? Settings.parse(ResourceUtil.readFileFromClasspath(settingPath)) //
|
||||
: persistentEntity.getDefaultSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean create(Document settings) {
|
||||
return doCreate(getIndexCoordinates(), settings);
|
||||
public boolean createWithMapping() {
|
||||
return doCreate(getIndexCoordinates(), createSettings(), createMapping());
|
||||
}
|
||||
|
||||
protected abstract boolean doCreate(IndexCoordinates index, @Nullable Document settings);
|
||||
@Override
|
||||
public boolean create(Map<String, Object> settings) {
|
||||
|
||||
Assert.notNull(settings, "settings must not be null");
|
||||
|
||||
return doCreate(getIndexCoordinates(), settings, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean create(Map<String, Object> settings, Document mapping) {
|
||||
|
||||
Assert.notNull(settings, "settings must not be null");
|
||||
Assert.notNull(mapping, "mapping must not be null");
|
||||
|
||||
return doCreate(getIndexCoordinates(), settings, mapping);
|
||||
}
|
||||
|
||||
protected abstract boolean doCreate(IndexCoordinates index, Map<String, Object> settings, @Nullable Document mapping);
|
||||
|
||||
@Override
|
||||
public boolean delete() {
|
||||
@@ -155,16 +158,16 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
|
||||
abstract protected Map<String, Object> doGetMapping(IndexCoordinates index);
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getSettings() {
|
||||
public Settings getSettings() {
|
||||
return getSettings(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getSettings(boolean includeDefaults) {
|
||||
public Settings getSettings(boolean includeDefaults) {
|
||||
return doGetSettings(getIndexCoordinates(), includeDefaults);
|
||||
}
|
||||
|
||||
protected abstract Map<String, Object> doGetSettings(IndexCoordinates index, boolean includeDefaults);
|
||||
protected abstract Settings doGetSettings(IndexCoordinates index, boolean includeDefaults);
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
@@ -174,10 +177,12 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
|
||||
protected abstract void doRefresh(IndexCoordinates indexCoordinates);
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean addAlias(AliasQuery query) {
|
||||
return doAddAlias(query, getIndexCoordinates());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
protected abstract boolean doAddAlias(AliasQuery query, IndexCoordinates index);
|
||||
|
||||
@Override
|
||||
@@ -188,10 +193,12 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
|
||||
protected abstract List<AliasMetadata> doQueryForAlias(IndexCoordinates index);
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean removeAlias(AliasQuery query) {
|
||||
return doRemoveAlias(query, getIndexCoordinates());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
protected abstract boolean doRemoveAlias(AliasQuery query, IndexCoordinates index);
|
||||
|
||||
@Override
|
||||
@@ -230,10 +237,10 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
|
||||
if (mappingAnnotation != null) {
|
||||
String mappingPath = mappingAnnotation.mappingPath();
|
||||
|
||||
if (StringUtils.hasText(mappingPath)) {
|
||||
if (hasText(mappingPath)) {
|
||||
String mappings = ResourceUtil.readFileFromClasspath(mappingPath);
|
||||
|
||||
if (StringUtils.hasText(mappings)) {
|
||||
if (hasText(mappings)) {
|
||||
return Document.parse(mappings);
|
||||
}
|
||||
} else {
|
||||
@@ -242,9 +249,7 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
|
||||
}
|
||||
|
||||
// build mapping from field annotations
|
||||
try
|
||||
|
||||
{
|
||||
try {
|
||||
String mapping = new MappingBuilder(elasticsearchConverter).buildPropertyMapping(clazz);
|
||||
return Document.parse(mapping);
|
||||
} catch (Exception e) {
|
||||
@@ -253,7 +258,7 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document createSettings() {
|
||||
public Settings createSettings() {
|
||||
return createSettings(checkForBoundClass());
|
||||
}
|
||||
|
||||
@@ -272,19 +277,5 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
|
||||
public IndexCoordinates getIndexCoordinatesFor(Class<?> clazz) {
|
||||
return getRequiredPersistentEntity(clazz).getIndexCoordinates();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Document loadSettings(String settingPath) {
|
||||
if (hasText(settingPath)) {
|
||||
String settingsFile = ResourceUtil.readFileFromClasspath(settingPath);
|
||||
|
||||
if (hasText(settingsFile)) {
|
||||
return Document.parse(settingsFile);
|
||||
}
|
||||
} else {
|
||||
LOGGER.info("settingPath in @Setting has to be defined. Using default instead.");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
|
||||
+5
-2
@@ -79,6 +79,8 @@ import org.springframework.util.Assert;
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Roman Puchkovskiy
|
||||
* @author Subhobrata Dey
|
||||
* @author Steven Pearce
|
||||
* @author Anton Naydenov
|
||||
*/
|
||||
public abstract class AbstractElasticsearchTemplate implements ElasticsearchOperations, ApplicationContextAware {
|
||||
|
||||
@@ -116,6 +118,7 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
|
||||
}
|
||||
|
||||
copy.setRoutingResolver(routingResolver);
|
||||
copy.setRefreshPolicy(refreshPolicy);
|
||||
|
||||
return copy;
|
||||
}
|
||||
@@ -250,7 +253,7 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> multiGet(Query query, Class<T> clazz) {
|
||||
public <T> List<MultiGetItem<T>> multiGet(Query query, Class<T> clazz) {
|
||||
return multiGet(query, clazz, getIndexCoordinatesFor(clazz));
|
||||
}
|
||||
|
||||
@@ -419,7 +422,7 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
|
||||
Assert.notNull(query.getId(), "No document id defined for MoreLikeThisQuery");
|
||||
|
||||
MoreLikeThisQueryBuilder moreLikeThisQueryBuilder = requestFactory.moreLikeThisQueryBuilder(query, index);
|
||||
return search(new NativeSearchQueryBuilder().withQuery(moreLikeThisQueryBuilder).build(), clazz, index);
|
||||
return search(new NativeSearchQueryBuilder().withQuery(moreLikeThisQueryBuilder).withPageable(query.getPageable()).build(), clazz, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+8
-1
@@ -18,12 +18,14 @@ package org.springframework.data.elasticsearch.core;
|
||||
import static org.elasticsearch.index.query.Operator.*;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.*;
|
||||
import static org.springframework.data.elasticsearch.core.query.Criteria.*;
|
||||
import static org.springframework.util.StringUtils.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.lucene.queryparser.flexible.standard.QueryParserUtil;
|
||||
import org.apache.lucene.search.join.ScoreMode;
|
||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||
@@ -136,7 +138,7 @@ class CriteriaQueryProcessor {
|
||||
return null;
|
||||
|
||||
String fieldName = field.getName();
|
||||
Assert.notNull(fieldName, "Unknown field");
|
||||
Assert.notNull(fieldName, "Unknown field " + fieldName);
|
||||
|
||||
Iterator<Criteria.CriteriaEntry> it = criteria.getQueryCriteriaEntries().iterator();
|
||||
QueryBuilder query;
|
||||
@@ -152,6 +154,11 @@ class CriteriaQueryProcessor {
|
||||
}
|
||||
|
||||
addBoost(query, criteria.getBoost());
|
||||
|
||||
if (hasText(field.getPath())) {
|
||||
query = nestedQuery(field.getPath(), query, ScoreMode.Avg);
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
+24
-8
@@ -32,6 +32,7 @@ import org.elasticsearch.client.GetAliasesResponse;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.indices.CreateIndexRequest;
|
||||
import org.elasticsearch.client.indices.GetIndexRequest;
|
||||
import org.elasticsearch.client.indices.GetIndexResponse;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesResponse;
|
||||
import org.elasticsearch.client.indices.GetMappingsRequest;
|
||||
@@ -49,6 +50,7 @@ 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.data.elasticsearch.core.query.AliasQuery;
|
||||
@@ -57,9 +59,10 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link IndexOperations} implementation using the RestClient.
|
||||
*
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Sascha Woo
|
||||
* @author George Popides
|
||||
* @since 4.0
|
||||
*/
|
||||
class DefaultIndexOperations extends AbstractDefaultIndexOperations implements IndexOperations {
|
||||
@@ -79,8 +82,8 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doCreate(IndexCoordinates index, @Nullable Document settings) {
|
||||
CreateIndexRequest request = requestFactory.createIndexRequest(index, settings);
|
||||
protected boolean doCreate(IndexCoordinates index, Map<String, Object> settings, @Nullable Document mapping) {
|
||||
CreateIndexRequest request = requestFactory.createIndexRequest(index, settings, mapping);
|
||||
return restTemplate.execute(client -> client.indices().create(request, RequestOptions.DEFAULT).isAcknowledged());
|
||||
}
|
||||
|
||||
@@ -139,6 +142,7 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
protected boolean doAddAlias(AliasQuery query, IndexCoordinates index) {
|
||||
|
||||
IndicesAliasesRequest request = requestFactory.indicesAddAliasesRequest(query, index);
|
||||
@@ -147,6 +151,7 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
protected boolean doRemoveAlias(AliasQuery query, IndexCoordinates index) {
|
||||
|
||||
Assert.notNull(index, "No index defined for Alias");
|
||||
@@ -175,8 +180,8 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
|
||||
|
||||
GetAliasesRequest getAliasesRequest = requestFactory.getAliasesRequest(aliasNames, indexNames);
|
||||
|
||||
return restTemplate.execute(client -> requestFactory
|
||||
.convertAliasesResponse(client.indices().getAlias(getAliasesRequest, RequestOptions.DEFAULT).getAliases()));
|
||||
return restTemplate.execute(client -> ResponseConverter
|
||||
.aliasDatas(client.indices().getAlias(getAliasesRequest, RequestOptions.DEFAULT).getAliases()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -188,7 +193,7 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> doGetSettings(IndexCoordinates index, boolean includeDefaults) {
|
||||
protected Settings doGetSettings(IndexCoordinates index, boolean includeDefaults) {
|
||||
|
||||
Assert.notNull(index, "index must not be null");
|
||||
|
||||
@@ -196,7 +201,7 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
|
||||
GetSettingsResponse response = restTemplate.execute(client -> client.indices() //
|
||||
.getSettings(getSettingsRequest, RequestOptions.DEFAULT));
|
||||
|
||||
return requestFactory.fromSettingsResponse(response, getSettingsRequest.indices()[0]);
|
||||
return ResponseConverter.fromSettingsResponse(response, getSettingsRequest.indices()[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -231,7 +236,7 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
|
||||
GetIndexTemplatesRequest getIndexTemplatesRequest = requestFactory.getIndexTemplatesRequest(getTemplateRequest);
|
||||
GetIndexTemplatesResponse getIndexTemplatesResponse = restTemplate
|
||||
.execute(client -> client.indices().getIndexTemplate(getIndexTemplatesRequest, RequestOptions.DEFAULT));
|
||||
return requestFactory.getTemplateData(getIndexTemplatesResponse, getTemplateRequest.getTemplateName());
|
||||
return ResponseConverter.getTemplateData(getIndexTemplatesResponse, getTemplateRequest.getTemplateName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -256,5 +261,16 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
|
||||
client -> client.indices().deleteTemplate(deleteIndexTemplateRequest, RequestOptions.DEFAULT).isAcknowledged());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IndexInformation> getInformation(IndexCoordinates index) {
|
||||
|
||||
Assert.notNull(index, "index must not be null");
|
||||
|
||||
GetIndexRequest request = requestFactory.getIndexRequest(index);
|
||||
return restTemplate.execute(client -> {
|
||||
GetIndexResponse getIndexResponse = client.indices().get(request, RequestOptions.DEFAULT);
|
||||
return ResponseConverter.getIndexInformations(getIndexResponse);
|
||||
});
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
|
||||
+69
-34
@@ -18,6 +18,7 @@ package org.springframework.data.elasticsearch.core;
|
||||
import static org.elasticsearch.client.Requests.*;
|
||||
import static org.springframework.util.StringUtils.*;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -25,24 +26,22 @@ import java.util.Set;
|
||||
|
||||
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
|
||||
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
|
||||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
|
||||
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.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.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.elasticsearch.NoSuchIndexException;
|
||||
import org.springframework.data.elasticsearch.annotations.Mapping;
|
||||
import org.springframework.data.elasticsearch.annotations.Setting;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.data.elasticsearch.core.index.AliasActions;
|
||||
@@ -52,6 +51,7 @@ import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest;
|
||||
import org.springframework.data.elasticsearch.core.index.GetTemplateRequest;
|
||||
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;
|
||||
@@ -60,6 +60,7 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Peter-Josef Meisch
|
||||
* @author George Popides
|
||||
* @since 4.1
|
||||
*/
|
||||
class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
|
||||
@@ -100,23 +101,43 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
|
||||
@Override
|
||||
public Mono<Boolean> create() {
|
||||
|
||||
String indexName = getIndexCoordinates().getIndexName();
|
||||
IndexCoordinates index = getIndexCoordinates();
|
||||
|
||||
if (boundClass != null) {
|
||||
return createSettings(boundClass).flatMap(settings -> doCreate(indexName, settings));
|
||||
return createSettings(boundClass).flatMap(settings -> doCreate(index, settings, null));
|
||||
} else {
|
||||
return doCreate(indexName, null);
|
||||
return doCreate(index, new Settings(), null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> create(Document settings) {
|
||||
return doCreate(getIndexCoordinates().getIndexName(), settings);
|
||||
public Mono<Boolean> createWithMapping() {
|
||||
return createSettings() //
|
||||
.flatMap(settings -> //
|
||||
createMapping().flatMap(mapping -> //
|
||||
doCreate(getIndexCoordinates(), settings, mapping))); //
|
||||
}
|
||||
|
||||
private Mono<Boolean> doCreate(String indexName, @Nullable Document settings) {
|
||||
@Override
|
||||
public Mono<Boolean> create(Map<String, Object> settings) {
|
||||
|
||||
CreateIndexRequest request = requestFactory.createIndexRequestReactive(indexName, settings);
|
||||
Assert.notNull(settings, "settings must not be null");
|
||||
|
||||
return doCreate(getIndexCoordinates(), settings, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> create(Map<String, Object> settings, Document mapping) {
|
||||
|
||||
Assert.notNull(settings, "settings must not be null");
|
||||
Assert.notNull(mapping, "mapping must not be null");
|
||||
|
||||
return doCreate(getIndexCoordinates(), settings, mapping);
|
||||
}
|
||||
|
||||
private Mono<Boolean> doCreate(IndexCoordinates index, Map<String, Object> settings, @Nullable Document mapping) {
|
||||
|
||||
CreateIndexRequest request = requestFactory.createIndexRequest(index, settings, mapping);
|
||||
return Mono.from(operations.executeWithIndicesClient(client -> client.createIndex(request)));
|
||||
}
|
||||
|
||||
@@ -139,7 +160,7 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
|
||||
@Override
|
||||
public Mono<Boolean> exists() {
|
||||
|
||||
GetIndexRequest request = requestFactory.getIndexRequestReactive(getIndexCoordinates().getIndexName());
|
||||
GetIndexRequest request = requestFactory.getIndexRequest(getIndexCoordinates());
|
||||
return Mono.from(operations.executeWithIndicesClient(client -> client.existsIndex(request)));
|
||||
}
|
||||
|
||||
@@ -159,11 +180,11 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
|
||||
@Override
|
||||
public Mono<Document> createMapping(Class<?> clazz) {
|
||||
|
||||
Mapping mappingAnnotation = AnnotatedElementUtils.findMergedAnnotation(clazz, Mapping.class);
|
||||
Mapping mappingAnnotation = AnnotatedElementUtils.findMergedAnnotation(clazz, Mapping.class);
|
||||
|
||||
if (mappingAnnotation != null) {
|
||||
return loadDocument(mappingAnnotation.mappingPath(), "@Mapping");
|
||||
}
|
||||
if (mappingAnnotation != null) {
|
||||
return loadDocument(mappingAnnotation.mappingPath(), "@Mapping");
|
||||
}
|
||||
|
||||
String mapping = new MappingBuilder(converter).buildPropertyMapping(clazz);
|
||||
return Mono.just(Document.parse(mapping));
|
||||
@@ -171,7 +192,7 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> putMapping(Mono<Document> mapping) {
|
||||
return mapping.map(document -> requestFactory.putMappingRequestReactive(getIndexCoordinates(), document)) //
|
||||
return mapping.map(document -> requestFactory.putMappingRequest(getIndexCoordinates(), document)) //
|
||||
.flatMap(request -> Mono.from(operations.executeWithIndicesClient(client -> client.putMapping(request))));
|
||||
}
|
||||
|
||||
@@ -179,13 +200,13 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
|
||||
public Mono<Document> getMapping() {
|
||||
|
||||
IndexCoordinates indexCoordinates = getIndexCoordinates();
|
||||
GetMappingsRequest request = requestFactory.getMappingRequestReactive(indexCoordinates);
|
||||
GetMappingsRequest request = requestFactory.getMappingsRequest(indexCoordinates);
|
||||
|
||||
return Mono.from(operations.executeWithIndicesClient(client -> client.getMapping(request)))
|
||||
.flatMap(getMappingsResponse -> {
|
||||
Document document = Document.create();
|
||||
document.put("properties",
|
||||
getMappingsResponse.mappings().get(indexCoordinates.getIndexName()).get("properties").getSourceAsMap());
|
||||
Map<String, Object> source = getMappingsResponse.mappings().get(indexCoordinates.getIndexName())
|
||||
.getSourceAsMap();
|
||||
Document document = Document.from(source);
|
||||
return Mono.just(document);
|
||||
});
|
||||
}
|
||||
@@ -194,30 +215,31 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
|
||||
// region settings
|
||||
|
||||
@Override
|
||||
public Mono<Document> createSettings() {
|
||||
public Mono<Settings> createSettings() {
|
||||
return createSettings(checkForBoundClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Document> createSettings(Class<?> clazz) {
|
||||
public Mono<Settings> createSettings(Class<?> clazz) {
|
||||
|
||||
Setting setting = AnnotatedElementUtils.findMergedAnnotation(clazz, Setting.class);
|
||||
Assert.notNull(clazz, "clazz must not be null");
|
||||
|
||||
if (setting != null) {
|
||||
return loadDocument(setting.settingPath(), "@Setting");
|
||||
}
|
||||
|
||||
return Mono.just(getRequiredPersistentEntity(clazz).getDefaultSettings());
|
||||
ElasticsearchPersistentEntity<?> persistentEntity = getRequiredPersistentEntity(clazz);
|
||||
String settingPath = persistentEntity.settingPath();
|
||||
return hasText(settingPath) //
|
||||
? loadDocument(settingPath, "@Setting") //
|
||||
.map(Settings::new) //
|
||||
: Mono.just(persistentEntity.getDefaultSettings());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Document> getSettings(boolean includeDefaults) {
|
||||
public Mono<Settings> getSettings(boolean includeDefaults) {
|
||||
|
||||
String indexName = getIndexCoordinates().getIndexName();
|
||||
GetSettingsRequest request = requestFactory.getSettingsRequest(indexName, includeDefaults);
|
||||
|
||||
return Mono.from(operations.executeWithIndicesClient(client -> client.getSettings(request)))
|
||||
.map(getSettingsResponse -> requestFactory.fromSettingsResponse(getSettingsResponse, indexName));
|
||||
.map(getSettingsResponse -> ResponseConverter.fromSettingsResponse(getSettingsResponse, indexName));
|
||||
}
|
||||
|
||||
// endregion
|
||||
@@ -244,7 +266,7 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
|
||||
|
||||
GetAliasesRequest getAliasesRequest = requestFactory.getAliasesRequest(aliasNames, indexNames);
|
||||
return Mono.from(operations.executeWithIndicesClient(client -> client.getAliases(getAliasesRequest)))
|
||||
.map(GetAliasesResponse::getAliases).map(requestFactory::convertAliasesResponse);
|
||||
.map(GetAliasesResponse::getAliases).map(ResponseConverter::aliasDatas);
|
||||
}
|
||||
// endregion
|
||||
|
||||
@@ -267,7 +289,8 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
|
||||
return Mono.from(operations.executeWithIndicesClient(client -> client.getTemplate(getIndexTemplatesRequest)))
|
||||
.flatMap(response -> {
|
||||
if (response != null) {
|
||||
TemplateData templateData = requestFactory.getTemplateData(response, getTemplateRequest.getTemplateName());
|
||||
TemplateData templateData = ResponseConverter.getTemplateData(response,
|
||||
getTemplateRequest.getTemplateName());
|
||||
if (templateData != null) {
|
||||
return Mono.just(templateData);
|
||||
}
|
||||
@@ -304,6 +327,18 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
|
||||
return (boundClass != null) ? getIndexCoordinatesFor(boundClass) : boundIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<IndexInformation> getInformation(IndexCoordinates index) {
|
||||
|
||||
Assert.notNull(index, "index must not be null");
|
||||
|
||||
org.elasticsearch.client.indices.GetIndexRequest getIndexRequest = requestFactory.getIndexRequest(index);
|
||||
return Mono
|
||||
.from(operations.executeWithIndicesClient(
|
||||
client -> client.getIndex(getIndexRequest).map(ResponseConverter::getIndexInformations)))
|
||||
.flatMapMany(Flux::fromIterable);
|
||||
}
|
||||
|
||||
private IndexCoordinates getIndexCoordinatesFor(Class<?> clazz) {
|
||||
return operations.getElasticsearchConverter().getMappingContext().getRequiredPersistentEntity(clazz)
|
||||
.getIndexCoordinates();
|
||||
|
||||
+24
-9
@@ -29,6 +29,8 @@ import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
|
||||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
|
||||
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
|
||||
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.get.GetIndexResponse;
|
||||
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
|
||||
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequestBuilder;
|
||||
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
|
||||
@@ -44,7 +46,6 @@ import org.elasticsearch.cluster.metadata.IndexTemplateMetadata;
|
||||
import org.elasticsearch.cluster.metadata.MappingMetadata;
|
||||
import org.elasticsearch.common.collect.ImmutableOpenMap;
|
||||
import org.elasticsearch.common.compress.CompressedXContent;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
@@ -55,6 +56,7 @@ 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.data.elasticsearch.core.query.AliasQuery;
|
||||
@@ -66,6 +68,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Sascha Woo
|
||||
* @author George Popides
|
||||
* @since 4.0
|
||||
*/
|
||||
class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations implements IndexOperations {
|
||||
@@ -87,9 +90,9 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doCreate(IndexCoordinates index, @Nullable Document settings) {
|
||||
protected boolean doCreate(IndexCoordinates index, Map<String, Object> settings, @Nullable Document mapping) {
|
||||
CreateIndexRequestBuilder createIndexRequestBuilder = requestFactory.createIndexRequestBuilder(client, index,
|
||||
settings);
|
||||
settings, mapping);
|
||||
return createIndexRequestBuilder.execute().actionGet().isAcknowledged();
|
||||
}
|
||||
|
||||
@@ -150,6 +153,7 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
protected boolean doRemoveAlias(AliasQuery query, IndexCoordinates index) {
|
||||
|
||||
Assert.notNull(index, "No index defined for Alias");
|
||||
@@ -177,7 +181,7 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp
|
||||
|
||||
Map<String, Set<AliasMetadata>> aliasesResponse = new LinkedHashMap<>();
|
||||
aliases.keysIt().forEachRemaining(index -> aliasesResponse.put(index, new HashSet<>(aliases.get(index))));
|
||||
return requestFactory.convertAliasesResponse(aliasesResponse);
|
||||
return ResponseConverter.aliasDatas(aliasesResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -189,7 +193,7 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> doGetSettings(IndexCoordinates index, boolean includeDefaults) {
|
||||
protected Settings doGetSettings(IndexCoordinates index, boolean includeDefaults) {
|
||||
|
||||
Assert.notNull(index, "index must not be null");
|
||||
|
||||
@@ -199,7 +203,7 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp
|
||||
.getSettings(getSettingsRequest) //
|
||||
.actionGet();
|
||||
|
||||
return requestFactory.fromSettingsResponse(response, index.getIndexName());
|
||||
return ResponseConverter.fromSettingsResponse(response, index.getIndexName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -234,8 +238,8 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp
|
||||
|
||||
if (indexTemplateMetadata.getName().equals(getTemplateRequest.getTemplateName())) {
|
||||
|
||||
Document settings = Document.create();
|
||||
Settings templateSettings = indexTemplateMetadata.settings();
|
||||
Settings settings = new Settings();
|
||||
org.elasticsearch.common.settings.Settings templateSettings = indexTemplateMetadata.settings();
|
||||
templateSettings.keySet().forEach(key -> settings.put(key, templateSettings.get(key)));
|
||||
|
||||
Map<String, AliasData> aliases = new LinkedHashMap<>();
|
||||
@@ -243,7 +247,7 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp
|
||||
Iterator<String> keysItAliases = aliasesResponse.keysIt();
|
||||
while (keysItAliases.hasNext()) {
|
||||
String key = keysItAliases.next();
|
||||
aliases.put(key, requestFactory.convertAliasMetadata(aliasesResponse.get(key)));
|
||||
aliases.put(key, ResponseConverter.toAliasData(aliasesResponse.get(key)));
|
||||
}
|
||||
|
||||
Map<String, String> mappingsDoc = new LinkedHashMap<>();
|
||||
@@ -296,4 +300,15 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp
|
||||
deleteTemplateRequest);
|
||||
return client.admin().indices().deleteTemplate(deleteIndexTemplateRequest).actionGet().isAcknowledged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IndexInformation> getInformation(IndexCoordinates index) {
|
||||
|
||||
Assert.notNull(index, "index must not be null");
|
||||
|
||||
GetIndexRequest getIndexRequest = new GetIndexRequest();
|
||||
getIndexRequest.indices(index.getIndexNames());
|
||||
GetIndexResponse getIndexResponse = client.admin().indices().getIndex(getIndexRequest).actionGet();
|
||||
return ResponseConverter.getIndexInformations(getIndexResponse);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,10 +120,10 @@ public interface DocumentOperations {
|
||||
*
|
||||
* @param query the query defining the ids of the objects to get
|
||||
* @param clazz the type of the object to be returned
|
||||
* @return list of objects, contains null values for ids that are not found
|
||||
* @return list of {@link MultiGetItem}s
|
||||
* @since 4.1
|
||||
*/
|
||||
<T> List<T> multiGet(Query query, Class<T> clazz);
|
||||
<T> List<MultiGetItem<T>> multiGet(Query query, Class<T> clazz);
|
||||
|
||||
/**
|
||||
* Execute a multiGet against elasticsearch for the given ids.
|
||||
@@ -131,9 +131,9 @@ public interface DocumentOperations {
|
||||
* @param query the query defining the ids of the objects to get
|
||||
* @param clazz the type of the object to be returned
|
||||
* @param index the index(es) from which the objects are read.
|
||||
* @return list of objects, contains null values for ids that are not found
|
||||
* @return list of {@link MultiGetItem}s
|
||||
*/
|
||||
<T> List<T> multiGet(Query query, Class<T> clazz, IndexCoordinates index);
|
||||
<T> List<MultiGetItem<T>> multiGet(Query query, Class<T> clazz, IndexCoordinates index);
|
||||
|
||||
/**
|
||||
* Check if an entity with given {@literal id} exists.
|
||||
|
||||
+14
-4
@@ -17,6 +17,7 @@ package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
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;
|
||||
@@ -39,25 +40,34 @@ public interface ElasticsearchOperations extends DocumentOperations, SearchOpera
|
||||
|
||||
/**
|
||||
* get an {@link IndexOperations} that is bound to the given class
|
||||
*
|
||||
*
|
||||
* @return IndexOperations
|
||||
*/
|
||||
IndexOperations indexOps(Class<?> clazz);
|
||||
|
||||
/**
|
||||
* get an {@link IndexOperations} that is bound to the given index
|
||||
*
|
||||
*
|
||||
* @return IndexOperations
|
||||
*/
|
||||
IndexOperations indexOps(IndexCoordinates index);
|
||||
|
||||
/**
|
||||
* return a {@link ClusterOperations} instance that uses the same client communication setup as this
|
||||
* ElasticsearchOperations instance.
|
||||
*
|
||||
* @return ClusterOperations implementation
|
||||
* @since 4.2
|
||||
*/
|
||||
ClusterOperations cluster();
|
||||
|
||||
ElasticsearchConverter getElasticsearchConverter();
|
||||
|
||||
IndexCoordinates getIndexCoordinatesFor(Class<?> clazz);
|
||||
|
||||
/**
|
||||
* gets the routing for an entity which might be defined by a join-type relation
|
||||
*
|
||||
*
|
||||
* @param entity the entity
|
||||
* @return the routing, may be null if not set.
|
||||
* @since 4.1
|
||||
@@ -68,7 +78,7 @@ public interface ElasticsearchOperations extends DocumentOperations, SearchOpera
|
||||
// region helper
|
||||
/**
|
||||
* gets the String representation for an id.
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
* @since 4.0
|
||||
|
||||
+13
-2
@@ -44,6 +44,7 @@ import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
|
||||
import org.elasticsearch.search.suggest.SuggestBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.elasticsearch.core.cluster.ClusterOperations;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.document.DocumentAdapters;
|
||||
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
|
||||
@@ -142,6 +143,13 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region ClusterOperations
|
||||
@Override
|
||||
public ClusterOperations cluster() {
|
||||
return ClusterOperations.forTemplate(this);
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region DocumentOperations
|
||||
public String doIndex(IndexQuery query, IndexCoordinates index) {
|
||||
|
||||
@@ -168,7 +176,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> multiGet(Query query, Class<T> clazz, IndexCoordinates index) {
|
||||
public <T> List<MultiGetItem<T>> multiGet(Query query, Class<T> clazz, IndexCoordinates index) {
|
||||
|
||||
Assert.notNull(index, "index must not be null");
|
||||
Assert.notEmpty(query.getIds(), "No Id defined for Query");
|
||||
@@ -177,7 +185,10 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
|
||||
MultiGetResponse result = execute(client -> client.mget(request, RequestOptions.DEFAULT));
|
||||
|
||||
DocumentCallback<T> callback = new ReadDocumentCallback<>(elasticsearchConverter, clazz, index);
|
||||
return DocumentAdapters.from(result).stream().map(callback::doWith).collect(Collectors.toList());
|
||||
return DocumentAdapters.from(result).stream() //
|
||||
.map(multiGetItem -> MultiGetItem.of( //
|
||||
multiGetItem.isFailed() ? null : callback.doWith(multiGetItem.getItem()), multiGetItem.getFailure())) //
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+14
-4
@@ -41,8 +41,8 @@ import org.elasticsearch.index.reindex.UpdateByQueryRequestBuilder;
|
||||
import org.elasticsearch.search.suggest.SuggestBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.elasticsearch.core.cluster.ClusterOperations;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.data.elasticsearch.core.document.DocumentAdapters;
|
||||
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
@@ -143,6 +143,13 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region ClusterOperations
|
||||
@Override
|
||||
public ClusterOperations cluster() {
|
||||
return ClusterOperations.forTemplate(this);
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region getter/setter
|
||||
@Nullable
|
||||
public String getSearchTimeout() {
|
||||
@@ -190,7 +197,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> multiGet(Query query, Class<T> clazz, IndexCoordinates index) {
|
||||
public <T> List<MultiGetItem<T>> multiGet(Query query, Class<T> clazz, IndexCoordinates index) {
|
||||
|
||||
Assert.notNull(index, "index must not be null");
|
||||
Assert.notEmpty(query.getIds(), "No Ids defined for Query");
|
||||
@@ -198,8 +205,11 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
||||
MultiGetRequestBuilder builder = requestFactory.multiGetRequestBuilder(client, query, clazz, index);
|
||||
|
||||
DocumentCallback<T> callback = new ReadDocumentCallback<>(elasticsearchConverter, clazz, index);
|
||||
List<Document> documents = DocumentAdapters.from(builder.execute().actionGet());
|
||||
return documents.stream().map(callback::doWith).collect(Collectors.toList());
|
||||
|
||||
return DocumentAdapters.from(builder.execute().actionGet()).stream() //
|
||||
.map(multiGetItem -> MultiGetItem.of(multiGetItem.isFailed() ? null : callback.doWith(multiGetItem.getItem()),
|
||||
multiGetItem.getFailure()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2021 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.data.elasticsearch.core.index.AliasData;
|
||||
import org.springframework.data.elasticsearch.core.index.Settings;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Immutable object that holds information(name, settings, mappings, aliases) about an Index
|
||||
*
|
||||
* @author George Popides
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.2
|
||||
*/
|
||||
public class IndexInformation {
|
||||
private final String name;
|
||||
@Nullable private final Settings settings;
|
||||
@Nullable private final Document mapping;
|
||||
@Nullable private final List<AliasData> aliases;
|
||||
|
||||
public static IndexInformation of(String name, @Nullable Settings settings, @Nullable Document mapping,
|
||||
@Nullable List<AliasData> aliases) {
|
||||
return new IndexInformation(name, settings, mapping, aliases);
|
||||
}
|
||||
|
||||
private IndexInformation(String name, @Nullable Settings settings, @Nullable Document mapping,
|
||||
@Nullable List<AliasData> aliases) {
|
||||
this.name = name;
|
||||
this.settings = settings;
|
||||
this.mapping = mapping;
|
||||
this.aliases = aliases;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Document getMapping() {
|
||||
return mapping;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Settings getSettings() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<AliasData> getAliases() {
|
||||
return aliases;
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ 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.data.elasticsearch.core.query.AliasQuery;
|
||||
@@ -38,9 +39,10 @@ import org.springframework.lang.Nullable;
|
||||
* <br/>
|
||||
* IndexOperations are bound to an entity class or an IndexCoordinate by
|
||||
* {@link ElasticsearchOperations#indexOps(IndexCoordinates)} or {@link ElasticsearchOperations#indexOps(Class)}
|
||||
*
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Sascha Woo
|
||||
* @author George Popides
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface IndexOperations {
|
||||
@@ -54,12 +56,30 @@ public interface IndexOperations {
|
||||
boolean create();
|
||||
|
||||
/**
|
||||
* Create an index for given Settings.
|
||||
* Create an index for given settings.
|
||||
*
|
||||
* @param settings the index settings
|
||||
* @return {@literal true} if the index was created
|
||||
*/
|
||||
boolean create(Document settings);
|
||||
boolean create(Map<String, Object> settings);
|
||||
|
||||
/**
|
||||
* Create an index for given settings and mapping.
|
||||
*
|
||||
* @param settings the index settings
|
||||
* @param mapping the index mapping
|
||||
* @return {@literal true} if the index was created
|
||||
* @since 4.2
|
||||
*/
|
||||
boolean create(Map<String, Object> settings, Document mapping);
|
||||
|
||||
/**
|
||||
* Create an index with the settings and mapping defined for the entity this IndexOperations is bound to.
|
||||
*
|
||||
* @return {@literal true} if the index was created
|
||||
* @since 4.2
|
||||
*/
|
||||
boolean createWithMapping();
|
||||
|
||||
/**
|
||||
* Deletes the index this {@link IndexOperations} is bound to
|
||||
@@ -81,7 +101,7 @@ public interface IndexOperations {
|
||||
void refresh();
|
||||
// endregion
|
||||
|
||||
// region mappings
|
||||
// region mapping
|
||||
/**
|
||||
* Creates the index mapping for the entity this IndexOperations is bound to.
|
||||
*
|
||||
@@ -99,7 +119,7 @@ public interface IndexOperations {
|
||||
|
||||
/**
|
||||
* Writes the mapping to the index for the class this IndexOperations is bound to.
|
||||
*
|
||||
*
|
||||
* @return {@literal true} if the mapping could be stored
|
||||
* @since 4.1
|
||||
*/
|
||||
@@ -109,7 +129,7 @@ public interface IndexOperations {
|
||||
|
||||
/**
|
||||
* writes a mapping to the index
|
||||
*
|
||||
*
|
||||
* @param mapping the Document with the mapping definitions
|
||||
* @return {@literal true} if the mapping could be stored
|
||||
*/
|
||||
@@ -117,7 +137,7 @@ public interface IndexOperations {
|
||||
|
||||
/**
|
||||
* Creates the index mapping for the given class and writes it to the index.
|
||||
*
|
||||
*
|
||||
* @param clazz the clazz to create a mapping for
|
||||
* @return {@literal true} if the mapping could be stored
|
||||
* @since 4.1
|
||||
@@ -125,25 +145,6 @@ public interface IndexOperations {
|
||||
default boolean putMapping(Class<?> clazz) {
|
||||
return putMapping(createMapping(clazz));
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region settings
|
||||
/**
|
||||
* Creates the index settings for the entity this IndexOperations is bound to.
|
||||
*
|
||||
* @return a settings document.
|
||||
* @since 4.1
|
||||
*/
|
||||
Document createSettings();
|
||||
|
||||
/**
|
||||
* Creates the index settings from the annotations on the given class
|
||||
*
|
||||
* @param clazz the class to create the index settings from
|
||||
* @return a settings document.
|
||||
* @since 4.1
|
||||
*/
|
||||
Document createSettings(Class<?> clazz);
|
||||
|
||||
/**
|
||||
* Get mapping for an index defined by a class.
|
||||
@@ -152,12 +153,32 @@ public interface IndexOperations {
|
||||
*/
|
||||
Map<String, Object> getMapping();
|
||||
|
||||
// endregion
|
||||
|
||||
// region settings
|
||||
/**
|
||||
* Creates the index settings for the entity this IndexOperations is bound to.
|
||||
*
|
||||
* @return a settings document.
|
||||
* @since 4.1
|
||||
*/
|
||||
Settings createSettings();
|
||||
|
||||
/**
|
||||
* Creates the index settings from the annotations on the given class
|
||||
*
|
||||
* @param clazz the class to create the index settings from
|
||||
* @return a settings document.
|
||||
* @since 4.1
|
||||
*/
|
||||
Settings createSettings(Class<?> clazz);
|
||||
|
||||
/**
|
||||
* Get the index settings.
|
||||
*
|
||||
* @return the settings
|
||||
*/
|
||||
Map<String, Object> getSettings();
|
||||
Settings getSettings();
|
||||
|
||||
/**
|
||||
* Get the index settings.
|
||||
@@ -165,7 +186,7 @@ public interface IndexOperations {
|
||||
* @param includeDefaults whether or not to include all the default settings
|
||||
* @return the settings
|
||||
*/
|
||||
Map<String, Object> getSettings(boolean includeDefaults);
|
||||
Settings getSettings(boolean includeDefaults);
|
||||
// endregion
|
||||
|
||||
// region aliases
|
||||
@@ -200,7 +221,7 @@ public interface IndexOperations {
|
||||
|
||||
/**
|
||||
* Executes the given {@link AliasActions}.
|
||||
*
|
||||
*
|
||||
* @param aliasActions the actions to execute
|
||||
* @return if the operation is acknowledged by Elasticsearch
|
||||
* @since 4.1
|
||||
@@ -209,7 +230,7 @@ public interface IndexOperations {
|
||||
|
||||
/**
|
||||
* gets information about aliases
|
||||
*
|
||||
*
|
||||
* @param aliasNames alias names, must not be {@literal null}
|
||||
* @return a {@link Map} from index names to {@link AliasData} for that index
|
||||
* @since 4.1
|
||||
@@ -218,7 +239,7 @@ public interface IndexOperations {
|
||||
|
||||
/**
|
||||
* gets information about aliases
|
||||
*
|
||||
*
|
||||
* @param indexNames index names, must not be {@literal null}
|
||||
* @return a {@link Map} from index names to {@link AliasData} for that index
|
||||
* @since 4.1
|
||||
@@ -230,7 +251,7 @@ public interface IndexOperations {
|
||||
/**
|
||||
* Creates an index template using the legacy Elasticsearch interface (@see
|
||||
* https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates-v1.html).
|
||||
*
|
||||
*
|
||||
* @param putTemplateRequest template request parameters
|
||||
* @return true if successful
|
||||
* @since 4.1
|
||||
@@ -307,6 +328,27 @@ public interface IndexOperations {
|
||||
|
||||
// endregion
|
||||
|
||||
// region index information
|
||||
/**
|
||||
* Gets the {@link IndexInformation} for the indices defined by {@link #getIndexCoordinates()}.
|
||||
*
|
||||
* @return a list of {@link IndexInformation}
|
||||
* @since 4.2
|
||||
*/
|
||||
default List<IndexInformation> getInformation() {
|
||||
return getInformation(getIndexCoordinates());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link IndexInformation} for the indices defined by #index.
|
||||
*
|
||||
* @param index defines the index names to get the information for
|
||||
* @return a list of {@link IndexInformation}
|
||||
* @since 4.2
|
||||
*/
|
||||
List<IndexInformation> getInformation(IndexCoordinates index);
|
||||
// endregion
|
||||
|
||||
// region helper functions
|
||||
/**
|
||||
* get the current {@link IndexCoordinates}. These may change over time when the entity class has a SpEL constructed
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2021 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;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Response object for items returned from multiget requests, encapsulating the returned data and potential error
|
||||
* information.
|
||||
*
|
||||
* @param <T> the entity type
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.2
|
||||
*/
|
||||
public class MultiGetItem<T> {
|
||||
@Nullable private final T item;
|
||||
@Nullable private final Failure failure;
|
||||
|
||||
private MultiGetItem(@Nullable T item, @Nullable Failure failure) {
|
||||
this.item = item;
|
||||
this.failure = failure;
|
||||
}
|
||||
|
||||
public static <T> MultiGetItem<T> of(@Nullable T item, @Nullable Failure failure) {
|
||||
return new MultiGetItem<>(item, failure);
|
||||
}
|
||||
|
||||
public boolean hasItem() {
|
||||
return item != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public T getItem() {
|
||||
return item;
|
||||
}
|
||||
|
||||
public boolean isFailed() {
|
||||
return failure != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Failure getFailure() {
|
||||
return failure;
|
||||
}
|
||||
|
||||
public static class Failure {
|
||||
@Nullable private final String index;
|
||||
@Nullable private final String type;
|
||||
@Nullable private final String id;
|
||||
@Nullable private final Exception exception;
|
||||
|
||||
private Failure(@Nullable String index, @Nullable String type, @Nullable String id, @Nullable Exception exception) {
|
||||
this.index = index;
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
public static Failure of(String index, String type, String id, Exception exception) {
|
||||
return new Failure(index, type, id, exception);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Exception getException() {
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -147,10 +147,10 @@ public interface ReactiveDocumentOperations {
|
||||
*
|
||||
* @param query the query defining the ids of the objects to get
|
||||
* @param clazz the type of the object to be returned, used to determine the index
|
||||
* @return flux with list of nullable objects
|
||||
* @return flux with list of {@link MultiGetItem}s that contain the entities
|
||||
* @since 4.1
|
||||
*/
|
||||
<T> Flux<T> multiGet(Query query, Class<T> clazz);
|
||||
<T> Flux<MultiGetItem<T>> multiGet(Query query, Class<T> clazz);
|
||||
|
||||
/**
|
||||
* Execute a multiGet against elasticsearch for the given ids.
|
||||
@@ -158,10 +158,10 @@ public interface ReactiveDocumentOperations {
|
||||
* @param query the query defining the ids of the objects to get
|
||||
* @param clazz the type of the object to be returned
|
||||
* @param index the index(es) from which the objects are read.
|
||||
* @return flux with list of nullable objects
|
||||
* @return flux with list of {@link MultiGetItem}s that contain the entities
|
||||
* @since 4.0
|
||||
*/
|
||||
<T> Flux<T> multiGet(Query query, Class<T> clazz, IndexCoordinates index);
|
||||
<T> Flux<MultiGetItem<T>> multiGet(Query query, Class<T> clazz, IndexCoordinates index);
|
||||
|
||||
/**
|
||||
* Bulk update all objects. Will do update.
|
||||
|
||||
+37
-4
@@ -17,6 +17,7 @@ package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
|
||||
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;
|
||||
@@ -56,6 +57,16 @@ public interface ReactiveElasticsearchOperations extends ReactiveDocumentOperati
|
||||
*/
|
||||
<T> Publisher<T> executeWithIndicesClient(IndicesClientCallback<Publisher<T>> callback);
|
||||
|
||||
/**
|
||||
* Execute within a {@link ClusterClientCallback} managing resources and translating errors.
|
||||
*
|
||||
* @param callback must not be {@literal null}.
|
||||
* @param <T> the type the Publisher emits
|
||||
* @return the {@link Publisher} emitting results.
|
||||
* @since 4.1
|
||||
*/
|
||||
<T> Publisher<T> executeWithClusterClient(ClusterClientCallback<Publisher<T>> callback);
|
||||
|
||||
/**
|
||||
* Get the {@link ElasticsearchConverter} used.
|
||||
*
|
||||
@@ -75,6 +86,7 @@ public interface ReactiveElasticsearchOperations extends ReactiveDocumentOperati
|
||||
|
||||
/**
|
||||
* Creates a {@link ReactiveIndexOperations} that is bound to the given index
|
||||
*
|
||||
* @param index IndexCoordinates specifying the index
|
||||
* @return ReactiveIndexOperations implementation
|
||||
* @since 4.1
|
||||
@@ -83,13 +95,23 @@ public interface ReactiveElasticsearchOperations extends ReactiveDocumentOperati
|
||||
|
||||
/**
|
||||
* Creates a {@link ReactiveIndexOperations} that is bound to the given class
|
||||
*
|
||||
* @param clazz the entity clazz specifiying the index information
|
||||
* @return ReactiveIndexOperations implementation
|
||||
* @since 4.1
|
||||
*/
|
||||
ReactiveIndexOperations indexOps(Class<?> clazz);
|
||||
|
||||
//region routing
|
||||
/**
|
||||
* return a {@link ReactiveClusterOperations} instance that uses the same client communication setup as this
|
||||
* ElasticsearchOperations instance.
|
||||
*
|
||||
* @return ClusterOperations implementation
|
||||
* @since 4.2
|
||||
*/
|
||||
ReactiveClusterOperations cluster();
|
||||
|
||||
// region routing
|
||||
/**
|
||||
* Returns a copy of this instance with the same configuration, but that uses a different {@link RoutingResolver} to
|
||||
* obtain routing information.
|
||||
@@ -98,7 +120,7 @@ public interface ReactiveElasticsearchOperations extends ReactiveDocumentOperati
|
||||
* @return DocumentOperations instance
|
||||
*/
|
||||
ReactiveElasticsearchOperations withRouting(RoutingResolver routingResolver);
|
||||
//endregion
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* Callback interface to be used with {@link #execute(ClientCallback)} for operating directly on
|
||||
@@ -114,8 +136,8 @@ public interface ReactiveElasticsearchOperations extends ReactiveDocumentOperati
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface to be used with {@link #executeWithIndicesClient(IndicesClientCallback)} for operating directly on
|
||||
* {@link ReactiveElasticsearchClient.Indices}.
|
||||
* Callback interface to be used with {@link #executeWithIndicesClient(IndicesClientCallback)} for operating directly
|
||||
* on {@link ReactiveElasticsearchClient.Indices}.
|
||||
*
|
||||
* @param <T> the return type
|
||||
* @since 4.1
|
||||
@@ -123,4 +145,15 @@ public interface ReactiveElasticsearchOperations extends ReactiveDocumentOperati
|
||||
interface IndicesClientCallback<T extends Publisher<?>> {
|
||||
T doWithClient(ReactiveElasticsearchClient.Indices client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface to be used with {@link #executeWithClusterClient(ClusterClientCallback)} for operating directly
|
||||
* on {@link ReactiveElasticsearchClient.Cluster}.
|
||||
*
|
||||
* @param <T> the return type
|
||||
* @since 4.2
|
||||
*/
|
||||
interface ClusterClientCallback<T extends Publisher<?>> {
|
||||
T doWithClient(ReactiveElasticsearchClient.Cluster client);
|
||||
}
|
||||
}
|
||||
|
||||
+34
-5
@@ -57,6 +57,8 @@ import org.springframework.data.elasticsearch.NoSuchIndexException;
|
||||
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
|
||||
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
|
||||
import org.springframework.data.elasticsearch.core.EntityOperations.AdaptibleEntity;
|
||||
import org.springframework.data.elasticsearch.core.cluster.DefaultReactiveClusterOperations;
|
||||
import org.springframework.data.elasticsearch.core.cluster.ReactiveClusterOperations;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
@@ -71,10 +73,10 @@ import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersiste
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
||||
import org.springframework.data.elasticsearch.core.query.BulkOptions;
|
||||
import org.springframework.data.elasticsearch.core.query.ByQueryResponse;
|
||||
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm;
|
||||
import org.springframework.data.elasticsearch.core.query.ByQueryResponse;
|
||||
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.UpdateResponse;
|
||||
import org.springframework.data.elasticsearch.core.routing.DefaultRoutingResolver;
|
||||
@@ -298,12 +300,12 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Flux<T> multiGet(Query query, Class<T> clazz) {
|
||||
public <T> Flux<MultiGetItem<T>> multiGet(Query query, Class<T> clazz) {
|
||||
return multiGet(query, clazz, getIndexCoordinatesFor(clazz));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Flux<T> multiGet(Query query, Class<T> clazz, IndexCoordinates index) {
|
||||
public <T> Flux<MultiGetItem<T>> multiGet(Query query, Class<T> clazz, IndexCoordinates index) {
|
||||
|
||||
Assert.notNull(index, "Index must not be null");
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
@@ -314,7 +316,12 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
||||
|
||||
MultiGetRequest request = requestFactory.multiGetRequest(query, clazz, index);
|
||||
return Flux.from(execute(client -> client.multiGet(request))) //
|
||||
.concatMap(result -> callback.toEntity(DocumentAdapters.from(result)));
|
||||
.map(DocumentAdapters::from) //
|
||||
.flatMap(multiGetItem -> multiGetItem.isFailed() //
|
||||
? Mono.just(MultiGetItem.of(null, multiGetItem.getFailure())) //
|
||||
: callback.toEntity(multiGetItem.getItem())
|
||||
.map((T item) -> MultiGetItem.of(item, multiGetItem.getFailure())) //
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -916,6 +923,11 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
||||
return Flux.defer(() -> callback.doWithClient(getIndicesClient())).onErrorMap(this::translateException);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Publisher<T> executeWithClusterClient(ClusterClientCallback<Publisher<T>> callback) {
|
||||
return Flux.defer(() -> callback.doWithClient(getClusterClient())).onErrorMap(this::translateException);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElasticsearchConverter getElasticsearchConverter() {
|
||||
return converter;
|
||||
@@ -931,6 +943,11 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
||||
return new DefaultReactiveIndexOperations(this, clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReactiveClusterOperations cluster() {
|
||||
return new DefaultReactiveClusterOperations(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndexCoordinates getIndexCoordinatesFor(Class<?> clazz) {
|
||||
return getPersistentEntityFor(clazz).getIndexCoordinates();
|
||||
@@ -965,7 +982,19 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
|
||||
throw new UncategorizedElasticsearchException("No ReactiveElasticsearchClient.Indices implementation available");
|
||||
}
|
||||
|
||||
// endregion
|
||||
/**
|
||||
* Obtain the {@link ReactiveElasticsearchClient.Cluster} to operate upon.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
protected ReactiveElasticsearchClient.Cluster getClusterClient() {
|
||||
|
||||
if (client instanceof ReactiveElasticsearchClient.Cluster) {
|
||||
return (ReactiveElasticsearchClient.Cluster) client;
|
||||
}
|
||||
|
||||
throw new UncategorizedElasticsearchException("No ReactiveElasticsearchClient.Cluster implementation available");
|
||||
}
|
||||
|
||||
/**
|
||||
* translates an Exception if possible. Exceptions that are no {@link RuntimeException}s are wrapped in a
|
||||
|
||||
+56
-12
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -27,6 +28,7 @@ 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;
|
||||
|
||||
@@ -34,6 +36,7 @@ import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
* Interface defining operations on indexes for the reactive stack.
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @author George Popides
|
||||
* @since 4.1
|
||||
*/
|
||||
public interface ReactiveIndexOperations {
|
||||
@@ -54,7 +57,27 @@ public interface ReactiveIndexOperations {
|
||||
* @return a {@link Mono} signalling successful operation completion or an {@link Mono#error(Throwable) error} if eg.
|
||||
* the index already exist.
|
||||
*/
|
||||
Mono<Boolean> create(Document settings);
|
||||
Mono<Boolean> create(Map<String, Object> settings);
|
||||
|
||||
/**
|
||||
* Create an index for given settings and mapping.
|
||||
*
|
||||
* @param settings the index settings
|
||||
* @param mapping the index mapping
|
||||
* @return a {@link Mono} signalling successful operation completion or an {@link Mono#error(Throwable) error} if eg.
|
||||
* the index already exist.
|
||||
* @since 4.2
|
||||
*/
|
||||
Mono<Boolean> create(Map<String, Object> settings, Document mapping);
|
||||
|
||||
/**
|
||||
* Create an index with the settings and mapping defined for the entity this IndexOperations is bound to.
|
||||
*
|
||||
* @return a {@link Mono} signalling successful operation completion or an {@link Mono#error(Throwable) error} if eg.
|
||||
* the index already exist.
|
||||
* @since 4.2
|
||||
*/
|
||||
Mono<Boolean> createWithMapping();
|
||||
|
||||
/**
|
||||
* Delete an index.
|
||||
@@ -66,14 +89,14 @@ public interface ReactiveIndexOperations {
|
||||
|
||||
/**
|
||||
* checks if an index exists
|
||||
*
|
||||
*
|
||||
* @return a {@link Mono} with the result of exist check
|
||||
*/
|
||||
Mono<Boolean> exists();
|
||||
|
||||
/**
|
||||
* Refresh the index(es) this IndexOperations is bound to
|
||||
*
|
||||
*
|
||||
* @return a {@link Mono} signalling operation completion.
|
||||
*/
|
||||
Mono<Void> refresh();
|
||||
@@ -97,7 +120,7 @@ public interface ReactiveIndexOperations {
|
||||
|
||||
/**
|
||||
* Writes the mapping to the index for the class this IndexOperations is bound to.
|
||||
*
|
||||
*
|
||||
* @return {@literal true} if the mapping could be stored
|
||||
*/
|
||||
default Mono<Boolean> putMapping() {
|
||||
@@ -114,7 +137,7 @@ public interface ReactiveIndexOperations {
|
||||
|
||||
/**
|
||||
* Creates the index mapping for the given class and writes it to the index.
|
||||
*
|
||||
*
|
||||
* @param clazz the clazz to create a mapping for
|
||||
* @return {@literal true} if the mapping could be stored
|
||||
*/
|
||||
@@ -137,7 +160,7 @@ public interface ReactiveIndexOperations {
|
||||
* @return a settings document.
|
||||
* @since 4.1
|
||||
*/
|
||||
Mono<Document> createSettings();
|
||||
Mono<Settings> createSettings();
|
||||
|
||||
/**
|
||||
* Creates the index settings from the annotations on the given class
|
||||
@@ -146,14 +169,14 @@ public interface ReactiveIndexOperations {
|
||||
* @return a settings document.
|
||||
* @since 4.1
|
||||
*/
|
||||
Mono<Document> createSettings(Class<?> clazz);
|
||||
Mono<Settings> createSettings(Class<?> clazz);
|
||||
|
||||
/**
|
||||
* get the settings for the index
|
||||
*
|
||||
*
|
||||
* @return a {@link Mono} with a {@link Document} containing the index settings
|
||||
*/
|
||||
default Mono<Document> getSettings() {
|
||||
default Mono<Settings> getSettings() {
|
||||
return getSettings(false);
|
||||
}
|
||||
|
||||
@@ -163,7 +186,7 @@ public interface ReactiveIndexOperations {
|
||||
* @param includeDefaults whether or not to include all the default settings
|
||||
* @return a {@link Mono} with a {@link Document} containing the index settings
|
||||
*/
|
||||
Mono<Document> getSettings(boolean includeDefaults);
|
||||
Mono<Settings> getSettings(boolean includeDefaults);
|
||||
// endregion
|
||||
|
||||
// region aliases
|
||||
@@ -178,7 +201,7 @@ public interface ReactiveIndexOperations {
|
||||
|
||||
/**
|
||||
* gets information about aliases
|
||||
*
|
||||
*
|
||||
* @param aliasNames alias names, must not be {@literal null}
|
||||
* @return a {@link Mono} of {@link Map} from index names to {@link AliasData} for that index
|
||||
* @since 4.1
|
||||
@@ -187,7 +210,7 @@ public interface ReactiveIndexOperations {
|
||||
|
||||
/**
|
||||
* gets information about aliases
|
||||
*
|
||||
*
|
||||
* @param indexNames alias names, must not be {@literal null}
|
||||
* @return a {@link Mono} of {@link Map} from index names to {@link AliasData} for that index
|
||||
* @since 4.1
|
||||
@@ -274,6 +297,27 @@ public interface ReactiveIndexOperations {
|
||||
|
||||
// endregion
|
||||
|
||||
// region index information
|
||||
/**
|
||||
* Gets the {@link IndexInformation} for the indices defined by {@link #getIndexCoordinates()}.
|
||||
*
|
||||
* @return a flux of {@link IndexInformation}
|
||||
* @since 4.2
|
||||
*/
|
||||
default Flux<IndexInformation> getInformation() {
|
||||
return getInformation(getIndexCoordinates());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link IndexInformation} for the indices defined by {@link #getIndexCoordinates()}.
|
||||
*
|
||||
* @return a flux of {@link IndexInformation}
|
||||
* @since 4.2
|
||||
*/
|
||||
Flux<IndexInformation> getInformation(IndexCoordinates index);
|
||||
|
||||
// endregion
|
||||
|
||||
// region helper functions
|
||||
/**
|
||||
* get the current {@link IndexCoordinates}. These may change over time when the entity class has a SpEL constructed
|
||||
|
||||
@@ -27,6 +27,8 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
||||
import org.springframework.data.elasticsearch.ResourceFailureException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Utility to reactively read {@link org.springframework.core.io.Resource}s.
|
||||
@@ -47,6 +49,8 @@ public abstract class ReactiveResourceUtil {
|
||||
*/
|
||||
public static Mono<String> readFileFromClasspath(String url) {
|
||||
|
||||
Assert.notNull(url, "url must not be null");
|
||||
|
||||
return DataBufferUtils
|
||||
.join(DataBufferUtils.read(new ClassPathResource(url), new DefaultDataBufferFactory(), BUFFER_SIZE))
|
||||
.<String> handle((it, sink) -> {
|
||||
@@ -65,15 +69,12 @@ public abstract class ReactiveResourceUtil {
|
||||
sink.next(sb.toString());
|
||||
sink.complete();
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn(String.format("Failed to load file from url: %s: %s", url, e.getMessage()));
|
||||
sink.complete();
|
||||
} finally {
|
||||
DataBufferUtils.release(it);
|
||||
}
|
||||
}).onErrorResume(throwable -> {
|
||||
LOGGER.warn(String.format("Failed to load file from url: %s: %s", url, throwable.getMessage()));
|
||||
return Mono.empty();
|
||||
});
|
||||
}).onErrorResume(
|
||||
throwable -> Mono.error(new ResourceFailureException("Could not load resource from " + url, throwable)));
|
||||
}
|
||||
|
||||
// Utility constructor
|
||||
|
||||
-4
@@ -124,7 +124,6 @@ public interface ReactiveSearchOperations {
|
||||
/**
|
||||
* Search the index for entities matching the given {@link Query query}.
|
||||
*
|
||||
* @param <T>
|
||||
* @param query must not be {@literal null}.
|
||||
* @param entityType must not be {@literal null}.
|
||||
* @param <T>
|
||||
@@ -138,7 +137,6 @@ public interface ReactiveSearchOperations {
|
||||
/**
|
||||
* Search the index for entities matching the given {@link Query query}.
|
||||
*
|
||||
* @param <T>
|
||||
* @param query must not be {@literal null}.
|
||||
* @param entityType must not be {@literal null}.
|
||||
* @param resultType the projection result type.
|
||||
@@ -151,7 +149,6 @@ public interface ReactiveSearchOperations {
|
||||
/**
|
||||
* Search the index for entities matching the given {@link Query query}.
|
||||
*
|
||||
* @param <T>
|
||||
* @param query must not be {@literal null}.
|
||||
* @param entityType must not be {@literal null}.
|
||||
* @param index the target index, must not be {@literal null}
|
||||
@@ -166,7 +163,6 @@ public interface ReactiveSearchOperations {
|
||||
/**
|
||||
* Search the index for entities matching the given {@link Query query}.
|
||||
*
|
||||
* @param <T>
|
||||
* @param query must not be {@literal null}.
|
||||
* @param entityType must not be {@literal null}.
|
||||
* @param resultType the projection result type.
|
||||
|
||||
@@ -18,7 +18,14 @@ package org.springframework.data.elasticsearch.core;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.*;
|
||||
import static org.springframework.util.CollectionUtils.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.elasticsearch.action.DocWriteRequest;
|
||||
import org.elasticsearch.action.admin.indices.alias.Alias;
|
||||
@@ -31,7 +38,6 @@ import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsReques
|
||||
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequestBuilder;
|
||||
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
|
||||
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest;
|
||||
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse;
|
||||
import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateRequest;
|
||||
import org.elasticsearch.action.bulk.BulkRequest;
|
||||
import org.elasticsearch.action.bulk.BulkRequestBuilder;
|
||||
@@ -54,17 +60,11 @@ import org.elasticsearch.client.Requests;
|
||||
import org.elasticsearch.client.indices.CreateIndexRequest;
|
||||
import org.elasticsearch.client.indices.GetIndexRequest;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesResponse;
|
||||
import org.elasticsearch.client.indices.GetMappingsRequest;
|
||||
import org.elasticsearch.client.indices.IndexTemplateMetadata;
|
||||
import org.elasticsearch.client.indices.IndexTemplatesExistRequest;
|
||||
import org.elasticsearch.client.indices.PutIndexTemplateRequest;
|
||||
import org.elasticsearch.client.indices.PutMappingRequest;
|
||||
import org.elasticsearch.cluster.metadata.AliasMetadata;
|
||||
import org.elasticsearch.common.collect.ImmutableOpenMap;
|
||||
import org.elasticsearch.common.compress.CompressedXContent;
|
||||
import org.elasticsearch.common.geo.GeoDistance;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.DistanceUnit;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.index.VersionType;
|
||||
@@ -82,6 +82,8 @@ import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
|
||||
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
|
||||
import org.elasticsearch.search.rescore.QueryRescoreMode;
|
||||
import org.elasticsearch.search.rescore.QueryRescorerBuilder;
|
||||
import org.elasticsearch.search.sort.FieldSortBuilder;
|
||||
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
|
||||
import org.elasticsearch.search.sort.ScoreSortBuilder;
|
||||
@@ -97,16 +99,15 @@ import org.springframework.data.elasticsearch.core.document.Document;
|
||||
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.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.TemplateData;
|
||||
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.RescorerQuery.ScoreMode;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -120,6 +121,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Roman Puchkovskiy
|
||||
* @author Subhobrata Dey
|
||||
* @author Farid Faoudi
|
||||
* @author Peer Mueller
|
||||
* @since 4.0
|
||||
*/
|
||||
class RequestFactory {
|
||||
@@ -134,6 +136,7 @@ class RequestFactory {
|
||||
}
|
||||
|
||||
// region alias
|
||||
@Deprecated
|
||||
public IndicesAliasesRequest.AliasActions aliasAction(AliasQuery query, IndexCoordinates index) {
|
||||
|
||||
Assert.notNull(index, "No index defined for Alias");
|
||||
@@ -179,6 +182,7 @@ class RequestFactory {
|
||||
return getAliasesRequest;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public IndicesAliasesRequest indicesAddAliasesRequest(AliasQuery query, IndexCoordinates index) {
|
||||
IndicesAliasesRequest.AliasActions aliasAction = aliasAction(query, index);
|
||||
IndicesAliasesRequest request = new IndicesAliasesRequest();
|
||||
@@ -254,6 +258,7 @@ class RequestFactory {
|
||||
return requestBuilder;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public IndicesAliasesRequest indicesRemoveAliasesRequest(AliasQuery query, IndexCoordinates index) {
|
||||
|
||||
String[] indexNames = index.getIndexNames();
|
||||
@@ -265,6 +270,7 @@ class RequestFactory {
|
||||
.addAliasAction(aliasAction);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
IndicesAliasesRequestBuilder indicesRemoveAliasesRequestBuilder(Client client, AliasQuery query,
|
||||
IndexCoordinates index) {
|
||||
|
||||
@@ -348,77 +354,49 @@ class RequestFactory {
|
||||
// endregion
|
||||
|
||||
// region index management
|
||||
/**
|
||||
* creates a CreateIndexRequest from the rest-high-level-client library.
|
||||
*
|
||||
* @param index name of the index
|
||||
* @param settings optional settings
|
||||
* @return request
|
||||
*/
|
||||
public CreateIndexRequest createIndexRequest(IndexCoordinates index, @Nullable Document settings) {
|
||||
|
||||
public CreateIndexRequest createIndexRequest(IndexCoordinates index, Map<String, Object> settings, @Nullable Document mapping) {
|
||||
|
||||
Assert.notNull(index, "index must not be null");
|
||||
Assert.notNull(settings, "settings must not be null");
|
||||
|
||||
CreateIndexRequest request = new CreateIndexRequest(index.getIndexName());
|
||||
|
||||
if (settings != null && !settings.isEmpty()) {
|
||||
if (!settings.isEmpty()) {
|
||||
request.settings(settings);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a CreateIndexRequest from the elasticsearch library, used by the reactive methods.
|
||||
*
|
||||
* @param indexName name of the index
|
||||
* @param settings optional settings
|
||||
* @return request
|
||||
*/
|
||||
public org.elasticsearch.action.admin.indices.create.CreateIndexRequest createIndexRequestReactive(String indexName,
|
||||
@Nullable Document settings) {
|
||||
|
||||
org.elasticsearch.action.admin.indices.create.CreateIndexRequest request = new org.elasticsearch.action.admin.indices.create.CreateIndexRequest(
|
||||
indexName);
|
||||
request.index(indexName);
|
||||
|
||||
if (settings != null && !settings.isEmpty()) {
|
||||
request.settings(settings);
|
||||
if (mapping != null && !mapping.isEmpty()) {
|
||||
request.mapping(mapping);
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
public CreateIndexRequestBuilder createIndexRequestBuilder(Client client, IndexCoordinates index,
|
||||
@Nullable Document settings) {
|
||||
Map<String, Object> settings, @Nullable Document mapping) {
|
||||
|
||||
Assert.notNull(index, "index must not be null");
|
||||
Assert.notNull(settings, "settings must not be null");
|
||||
|
||||
String indexName = index.getIndexName();
|
||||
CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices().prepareCreate(indexName);
|
||||
|
||||
if (settings != null) {
|
||||
if (!settings.isEmpty()) {
|
||||
createIndexRequestBuilder.setSettings(settings);
|
||||
}
|
||||
|
||||
if (mapping != null && !mapping.isEmpty()) {
|
||||
createIndexRequestBuilder.addMapping(IndexCoordinates.TYPE, mapping);
|
||||
}
|
||||
|
||||
return createIndexRequestBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a GetIndexRequest from the rest-high-level-client library.
|
||||
*
|
||||
* @param index name of the index
|
||||
* @return request
|
||||
*/
|
||||
public GetIndexRequest getIndexRequest(IndexCoordinates index) {
|
||||
return new GetIndexRequest(index.getIndexNames());
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a CreateIndexRequest from the elasticsearch library, used by the reactive methods.
|
||||
*
|
||||
* @param indexName name of the index
|
||||
* @return request
|
||||
*/
|
||||
public org.elasticsearch.action.admin.indices.get.GetIndexRequest getIndexRequestReactive(String indexName) {
|
||||
|
||||
org.elasticsearch.action.admin.indices.get.GetIndexRequest request = new org.elasticsearch.action.admin.indices.get.GetIndexRequest();
|
||||
request.indices(indexName);
|
||||
return request;
|
||||
}
|
||||
|
||||
public IndicesExistsRequest indicesExistsRequest(IndexCoordinates index) {
|
||||
|
||||
String[] indexNames = index.getIndexNames();
|
||||
@@ -450,15 +428,6 @@ class RequestFactory {
|
||||
return request;
|
||||
}
|
||||
|
||||
public org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest putMappingRequestReactive(
|
||||
IndexCoordinates index, Document mapping) {
|
||||
org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest request = new org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest(
|
||||
index.getIndexName());
|
||||
request.type("not-used-but-must-be-there");
|
||||
request.source(mapping);
|
||||
return request;
|
||||
}
|
||||
|
||||
public PutMappingRequestBuilder putMappingRequestBuilder(Client client, IndexCoordinates index, Document mapping) {
|
||||
|
||||
String[] indexNames = index.getIndexNames();
|
||||
@@ -468,13 +437,6 @@ class RequestFactory {
|
||||
return requestBuilder;
|
||||
}
|
||||
|
||||
public org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest getMappingRequestReactive(
|
||||
IndexCoordinates index) {
|
||||
org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest request = new org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest();
|
||||
request.indices(index.getIndexName());
|
||||
return request;
|
||||
}
|
||||
|
||||
public GetSettingsRequest getSettingsRequest(String indexName, boolean includeDefaults) {
|
||||
return new GetSettingsRequest().indices(indexName).includeDefaults(includeDefaults);
|
||||
}
|
||||
@@ -492,27 +454,6 @@ class RequestFactory {
|
||||
return new org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest().indices(indexNames);
|
||||
}
|
||||
|
||||
public Map<String, Set<AliasData>> convertAliasesResponse(Map<String, Set<AliasMetadata>> aliasesResponse) {
|
||||
Map<String, Set<AliasData>> converted = new LinkedHashMap<>();
|
||||
aliasesResponse.forEach((index, aliasMetaDataSet) -> {
|
||||
Set<AliasData> aliasDataSet = new LinkedHashSet<>();
|
||||
aliasMetaDataSet.forEach(aliasMetaData -> aliasDataSet.add(convertAliasMetadata(aliasMetaData)));
|
||||
converted.put(index, aliasDataSet);
|
||||
});
|
||||
return converted;
|
||||
}
|
||||
|
||||
public AliasData convertAliasMetadata(AliasMetadata aliasMetaData) {
|
||||
Document filter = null;
|
||||
CompressedXContent aliasMetaDataFilter = aliasMetaData.getFilter();
|
||||
if (aliasMetaDataFilter != null) {
|
||||
filter = Document.parse(aliasMetaDataFilter.string());
|
||||
}
|
||||
AliasData aliasData = AliasData.of(aliasMetaData.alias(), filter, aliasMetaData.indexRouting(),
|
||||
aliasMetaData.getSearchRouting(), aliasMetaData.writeIndex(), aliasMetaData.isHidden());
|
||||
return aliasData;
|
||||
}
|
||||
|
||||
public PutIndexTemplateRequest putIndexTemplateRequest(PutTemplateRequest putTemplateRequest) {
|
||||
|
||||
PutIndexTemplateRequest request = new PutIndexTemplateRequest(putTemplateRequest.getName())
|
||||
@@ -656,38 +597,6 @@ class RequestFactory {
|
||||
return new GetIndexTemplatesRequest(getTemplateRequest.getTemplateName());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TemplateData getTemplateData(GetIndexTemplatesResponse getIndexTemplatesResponse, String templateName) {
|
||||
for (IndexTemplateMetadata indexTemplateMetadata : getIndexTemplatesResponse.getIndexTemplates()) {
|
||||
|
||||
if (indexTemplateMetadata.name().equals(templateName)) {
|
||||
|
||||
Document settings = Document.create();
|
||||
Settings templateSettings = indexTemplateMetadata.settings();
|
||||
templateSettings.keySet().forEach(key -> settings.put(key, templateSettings.get(key)));
|
||||
|
||||
Map<String, AliasData> aliases = new LinkedHashMap<>();
|
||||
|
||||
ImmutableOpenMap<String, AliasMetadata> aliasesResponse = indexTemplateMetadata.aliases();
|
||||
Iterator<String> keysIt = aliasesResponse.keysIt();
|
||||
while (keysIt.hasNext()) {
|
||||
String key = keysIt.next();
|
||||
aliases.put(key, convertAliasMetadata(aliasesResponse.get(key)));
|
||||
}
|
||||
TemplateData templateData = TemplateData.builder()
|
||||
.withIndexPatterns(indexTemplateMetadata.patterns().toArray(new String[0])) //
|
||||
.withSettings(settings) //
|
||||
.withMapping(Document.from(indexTemplateMetadata.mappings().getSourceAsMap())) //
|
||||
.withAliases(aliases) //
|
||||
.withOrder(indexTemplateMetadata.order()) //
|
||||
.withVersion(indexTemplateMetadata.version()).build();
|
||||
|
||||
return templateData;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesRequest getIndexTemplatesRequest(
|
||||
Client client, GetTemplateRequest getTemplateRequest) {
|
||||
return new org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesRequest(
|
||||
@@ -851,15 +760,17 @@ class RequestFactory {
|
||||
String indexName = index.getIndexName();
|
||||
IndexRequest indexRequest;
|
||||
|
||||
if (query.getObject() != null) {
|
||||
String id = StringUtils.isEmpty(query.getId()) ? getPersistentEntityId(query.getObject()) : query.getId();
|
||||
Object queryObject = query.getObject();
|
||||
|
||||
if (queryObject != null) {
|
||||
String id = StringUtils.isEmpty(query.getId()) ? getPersistentEntityId(queryObject) : query.getId();
|
||||
// If we have a query id and a document id, do not ask ES to generate one.
|
||||
if (id != null) {
|
||||
indexRequest = new IndexRequest(indexName).id(id);
|
||||
} else {
|
||||
indexRequest = new IndexRequest(indexName);
|
||||
}
|
||||
indexRequest.source(elasticsearchConverter.mapObject(query.getObject()).toJson(), Requests.INDEX_CONTENT_TYPE);
|
||||
indexRequest.source(elasticsearchConverter.mapObject(queryObject).toJson(), Requests.INDEX_CONTENT_TYPE);
|
||||
} else if (query.getSource() != null) {
|
||||
indexRequest = new IndexRequest(indexName).id(query.getId()).source(query.getSource(),
|
||||
Requests.INDEX_CONTENT_TYPE);
|
||||
@@ -870,7 +781,8 @@ class RequestFactory {
|
||||
|
||||
if (query.getVersion() != null) {
|
||||
indexRequest.version(query.getVersion());
|
||||
VersionType versionType = retrieveVersionTypeFromPersistentEntity(query.getObject().getClass());
|
||||
VersionType versionType = retrieveVersionTypeFromPersistentEntity(
|
||||
queryObject != null ? queryObject.getClass() : null);
|
||||
indexRequest.versionType(versionType);
|
||||
}
|
||||
|
||||
@@ -905,15 +817,16 @@ class RequestFactory {
|
||||
|
||||
IndexRequestBuilder indexRequestBuilder;
|
||||
|
||||
if (query.getObject() != null) {
|
||||
String id = StringUtils.isEmpty(query.getId()) ? getPersistentEntityId(query.getObject()) : query.getId();
|
||||
Object queryObject = query.getObject();
|
||||
if (queryObject != null) {
|
||||
String id = StringUtils.isEmpty(query.getId()) ? getPersistentEntityId(queryObject) : query.getId();
|
||||
// If we have a query id and a document id, do not ask ES to generate one.
|
||||
if (id != null) {
|
||||
indexRequestBuilder = client.prepareIndex(indexName, type, id);
|
||||
} else {
|
||||
indexRequestBuilder = client.prepareIndex(indexName, type);
|
||||
}
|
||||
indexRequestBuilder.setSource(elasticsearchConverter.mapObject(query.getObject()).toJson(),
|
||||
indexRequestBuilder.setSource(elasticsearchConverter.mapObject(queryObject).toJson(),
|
||||
Requests.INDEX_CONTENT_TYPE);
|
||||
} else if (query.getSource() != null) {
|
||||
indexRequestBuilder = client.prepareIndex(indexName, type, query.getId()).setSource(query.getSource(),
|
||||
@@ -925,7 +838,8 @@ class RequestFactory {
|
||||
|
||||
if (query.getVersion() != null) {
|
||||
indexRequestBuilder.setVersion(query.getVersion());
|
||||
VersionType versionType = retrieveVersionTypeFromPersistentEntity(query.getObject().getClass());
|
||||
VersionType versionType = retrieveVersionTypeFromPersistentEntity(
|
||||
queryObject != null ? queryObject.getClass() : null);
|
||||
indexRequestBuilder.setVersionType(versionType);
|
||||
}
|
||||
|
||||
@@ -1150,6 +1064,12 @@ class RequestFactory {
|
||||
sourceBuilder.searchAfter(query.getSearchAfter().toArray());
|
||||
}
|
||||
|
||||
query.getRescorerQueries().forEach(rescorer -> sourceBuilder.addRescorer(getQueryRescorerBuilder(rescorer)));
|
||||
|
||||
if (query.getScrollTime() != null) {
|
||||
request.scroll(TimeValue.timeValueMillis(query.getScrollTime().toMillis()));
|
||||
}
|
||||
|
||||
request.source(sourceBuilder);
|
||||
return request;
|
||||
}
|
||||
@@ -1236,6 +1156,12 @@ class RequestFactory {
|
||||
searchRequestBuilder.searchAfter(query.getSearchAfter().toArray());
|
||||
}
|
||||
|
||||
query.getRescorerQueries().forEach(rescorer -> searchRequestBuilder.addRescorer(getQueryRescorerBuilder(rescorer)));
|
||||
|
||||
if (query.getScrollTime() != null) {
|
||||
searchRequestBuilder.setScroll(TimeValue.timeValueMillis(query.getScrollTime().toMillis()));
|
||||
}
|
||||
|
||||
return searchRequestBuilder;
|
||||
}
|
||||
|
||||
@@ -1360,6 +1286,33 @@ class RequestFactory {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private QueryRescorerBuilder getQueryRescorerBuilder(RescorerQuery rescorerQuery) {
|
||||
|
||||
QueryBuilder queryBuilder = getQuery(rescorerQuery.getQuery());
|
||||
Assert.notNull("queryBuilder", "Could not build query for rescorerQuery");
|
||||
|
||||
QueryRescorerBuilder builder = new QueryRescorerBuilder(queryBuilder);
|
||||
|
||||
if (rescorerQuery.getScoreMode() != ScoreMode.Default) {
|
||||
builder.setScoreMode(QueryRescoreMode.valueOf(rescorerQuery.getScoreMode().name()));
|
||||
}
|
||||
|
||||
if (rescorerQuery.getQueryWeight() != null) {
|
||||
builder.setQueryWeight(rescorerQuery.getQueryWeight());
|
||||
}
|
||||
|
||||
if (rescorerQuery.getRescoreQueryWeight() != null) {
|
||||
builder.setRescoreQueryWeight(rescorerQuery.getRescoreQueryWeight());
|
||||
}
|
||||
|
||||
if (rescorerQuery.getWindowSize() != null) {
|
||||
builder.windowSize(rescorerQuery.getWindowSize());
|
||||
}
|
||||
|
||||
return builder;
|
||||
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region update
|
||||
@@ -1755,12 +1708,13 @@ class RequestFactory {
|
||||
return null;
|
||||
}
|
||||
|
||||
private VersionType retrieveVersionTypeFromPersistentEntity(Class<?> clazz) {
|
||||
private VersionType retrieveVersionTypeFromPersistentEntity(@Nullable Class<?> clazz) {
|
||||
|
||||
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext = elasticsearchConverter
|
||||
.getMappingContext();
|
||||
|
||||
ElasticsearchPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(clazz);
|
||||
ElasticsearchPersistentEntity<?> persistentEntity = clazz != null ? mappingContext.getPersistentEntity(clazz)
|
||||
: null;
|
||||
|
||||
VersionType versionType = null;
|
||||
|
||||
@@ -1817,36 +1771,4 @@ class RequestFactory {
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region response stuff
|
||||
|
||||
/**
|
||||
* extract the index settings information for a given index
|
||||
*
|
||||
* @param response the Elasticsearch response
|
||||
* @param indexName the index name
|
||||
* @return settings as {@link Document}
|
||||
*/
|
||||
public Document fromSettingsResponse(GetSettingsResponse response, String indexName) {
|
||||
|
||||
Document settings = Document.create();
|
||||
|
||||
if (!response.getIndexToDefaultSettings().isEmpty()) {
|
||||
Settings defaultSettings = response.getIndexToDefaultSettings().get(indexName);
|
||||
for (String key : defaultSettings.keySet()) {
|
||||
settings.put(key, defaultSettings.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
if (!response.getIndexToSettings().isEmpty()) {
|
||||
Settings customSettings = response.getIndexToSettings().get(indexName);
|
||||
for (String key : customSettings.keySet()) {
|
||||
settings.put(key, customSettings.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
||||
@@ -18,10 +18,9 @@ package org.springframework.data.elasticsearch.core;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.data.elasticsearch.ResourceFailureException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
/**
|
||||
@@ -33,23 +32,20 @@ import org.springframework.util.StreamUtils;
|
||||
*/
|
||||
public abstract class ResourceUtil {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ResourceUtil.class);
|
||||
|
||||
/**
|
||||
* Read a {@link ClassPathResource} into a {@link String}.
|
||||
*
|
||||
* @param url url the file url
|
||||
* @return the contents of the file or null if it could not be read
|
||||
* @param url url the resource
|
||||
* @return the contents of the resource
|
||||
*/
|
||||
@Nullable
|
||||
public static String readFileFromClasspath(String url) {
|
||||
|
||||
ClassPathResource classPathResource = new ClassPathResource(url);
|
||||
try (InputStream is = classPathResource.getInputStream()) {
|
||||
Assert.notNull(url, "url must not be null");
|
||||
|
||||
try (InputStream is = new ClassPathResource(url).getInputStream()) {
|
||||
return StreamUtils.copyToString(is, Charset.defaultCharset());
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn(String.format("Failed to load file from url: %s: %s", url, e.getMessage()));
|
||||
return null;
|
||||
throw new ResourceFailureException("Could not load resource from " + url, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright 2021 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
||||
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse;
|
||||
import org.elasticsearch.action.get.MultiGetItemResponse;
|
||||
import org.elasticsearch.action.get.MultiGetResponse;
|
||||
import org.elasticsearch.client.indices.GetIndexResponse;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesResponse;
|
||||
import org.elasticsearch.client.indices.IndexTemplateMetadata;
|
||||
import org.elasticsearch.cluster.metadata.AliasMetadata;
|
||||
import org.elasticsearch.cluster.metadata.MappingMetadata;
|
||||
import org.elasticsearch.common.collect.ImmutableOpenMap;
|
||||
import org.elasticsearch.common.compress.CompressedXContent;
|
||||
import org.springframework.data.elasticsearch.core.cluster.ClusterHealth;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
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.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Factory class to convert elasticsearch responses to different type of data classes.
|
||||
*
|
||||
* @author George Popides
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.2
|
||||
*/
|
||||
public class ResponseConverter {
|
||||
private ResponseConverter() {}
|
||||
|
||||
// region alias
|
||||
|
||||
public static Map<String, Set<AliasData>> aliasDatas(Map<String, Set<AliasMetadata>> aliasesMetadatas) {
|
||||
Map<String, Set<AliasData>> converted = new LinkedHashMap<>();
|
||||
aliasesMetadatas.forEach((index, aliasMetaDataSet) -> {
|
||||
Set<AliasData> aliasDataSet = new LinkedHashSet<>();
|
||||
aliasMetaDataSet.forEach(aliasMetaData -> aliasDataSet.add(toAliasData(aliasMetaData)));
|
||||
converted.put(index, aliasDataSet);
|
||||
});
|
||||
return converted;
|
||||
}
|
||||
|
||||
public static AliasData toAliasData(AliasMetadata aliasMetaData) {
|
||||
Document filter = null;
|
||||
CompressedXContent aliasMetaDataFilter = aliasMetaData.getFilter();
|
||||
|
||||
if (aliasMetaDataFilter != null) {
|
||||
filter = Document.parse(aliasMetaDataFilter.string());
|
||||
}
|
||||
return AliasData.of(aliasMetaData.alias(), filter, aliasMetaData.indexRouting(), aliasMetaData.getSearchRouting(),
|
||||
aliasMetaData.writeIndex(), aliasMetaData.isHidden());
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region index informations
|
||||
/**
|
||||
* get the index informations from a {@link GetIndexResponse}
|
||||
*
|
||||
* @param getIndexResponse the index response, must not be {@literal null}
|
||||
* @return list of {@link IndexInformation}s for the different indices
|
||||
*/
|
||||
public static List<IndexInformation> getIndexInformations(GetIndexResponse getIndexResponse) {
|
||||
|
||||
Assert.notNull(getIndexResponse, "getIndexResponse must not be null");
|
||||
|
||||
List<IndexInformation> indexInformationList = new ArrayList<>();
|
||||
|
||||
for (String indexName : getIndexResponse.getIndices()) {
|
||||
Settings settings = settingsFromGetIndexResponse(getIndexResponse, indexName);
|
||||
Document mappings = mappingsFromGetIndexResponse(getIndexResponse, indexName);
|
||||
List<AliasData> aliases = aliasDataFromIndexResponse(getIndexResponse, indexName);
|
||||
|
||||
indexInformationList.add(IndexInformation.of(indexName, settings, mappings, aliases));
|
||||
}
|
||||
|
||||
return indexInformationList;
|
||||
}
|
||||
|
||||
/**
|
||||
* extract the index settings information from a given index
|
||||
*
|
||||
* @param getIndexResponse the elastic GetIndexResponse
|
||||
* @param indexName the index name
|
||||
* @return a document that represents {@link Settings}
|
||||
*/
|
||||
private static Settings settingsFromGetIndexResponse(GetIndexResponse getIndexResponse, String indexName) {
|
||||
Settings settings = new Settings();
|
||||
|
||||
org.elasticsearch.common.settings.Settings indexSettings = getIndexResponse.getSettings().get(indexName);
|
||||
|
||||
if (!indexSettings.isEmpty()) {
|
||||
for (String key : indexSettings.keySet()) {
|
||||
settings.put(key, indexSettings.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* extract the mappings information from a given index
|
||||
*
|
||||
* @param getIndexResponse the elastic GetIndexResponse
|
||||
* @param indexName the index name
|
||||
* @return a document that represents {@link MappingMetadata}
|
||||
*/
|
||||
private static Document mappingsFromGetIndexResponse(GetIndexResponse getIndexResponse, String indexName) {
|
||||
Document document = Document.create();
|
||||
|
||||
if (getIndexResponse.getMappings().containsKey(indexName)) {
|
||||
MappingMetadata mappings = getIndexResponse.getMappings().get(indexName);
|
||||
document = Document.from(mappings.getSourceAsMap());
|
||||
}
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
private static List<AliasData> aliasDataFromIndexResponse(GetIndexResponse getIndexResponse, String indexName) {
|
||||
List<AliasData> aliases = Collections.emptyList();
|
||||
|
||||
if (getIndexResponse.getAliases().get(indexName) != null) {
|
||||
aliases = getIndexResponse.getAliases().get(indexName).stream().map(ResponseConverter::toAliasData)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
return aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the index informations from a {@link org.elasticsearch.action.admin.indices.get.GetIndexResponse} (transport
|
||||
* client)
|
||||
*
|
||||
* @param getIndexResponse the index response, must not be {@literal null}
|
||||
* @return list of {@link IndexInformation}s for the different indices
|
||||
*/
|
||||
public static List<IndexInformation> getIndexInformations(
|
||||
org.elasticsearch.action.admin.indices.get.GetIndexResponse getIndexResponse) {
|
||||
List<IndexInformation> indexInformationList = new ArrayList<>();
|
||||
|
||||
for (String indexName : getIndexResponse.getIndices()) {
|
||||
Settings settings = settingsFromGetIndexResponse(getIndexResponse, indexName);
|
||||
Document mappings = mappingsFromGetIndexResponse(getIndexResponse, indexName);
|
||||
List<AliasData> aliases = aliasDataFromIndexResponse(getIndexResponse, indexName);
|
||||
|
||||
indexInformationList.add(IndexInformation.of(indexName, settings, mappings, aliases));
|
||||
}
|
||||
|
||||
return indexInformationList;
|
||||
}
|
||||
|
||||
private static Settings settingsFromGetIndexResponse(
|
||||
org.elasticsearch.action.admin.indices.get.GetIndexResponse getIndexResponse, String indexName) {
|
||||
|
||||
Settings settings = new Settings();
|
||||
|
||||
if (getIndexResponse.getSettings().containsKey(indexName)) {
|
||||
org.elasticsearch.common.settings.Settings indexSettings = getIndexResponse.getSettings().get(indexName);
|
||||
|
||||
for (String key : indexSettings.keySet()) {
|
||||
settings.put(key, indexSettings.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
private static Document mappingsFromGetIndexResponse(
|
||||
org.elasticsearch.action.admin.indices.get.GetIndexResponse getIndexResponse, String indexName) {
|
||||
Document document = Document.create();
|
||||
|
||||
boolean responseHasMappings = getIndexResponse.getMappings().containsKey(indexName)
|
||||
&& (getIndexResponse.getMappings().get(indexName).get("_doc") != null);
|
||||
|
||||
if (responseHasMappings) {
|
||||
MappingMetadata mappings = getIndexResponse.getMappings().get(indexName).get("_doc");
|
||||
document = Document.from(mappings.getSourceAsMap());
|
||||
}
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
private static List<AliasData> aliasDataFromIndexResponse(
|
||||
org.elasticsearch.action.admin.indices.get.GetIndexResponse getIndexResponse, String indexName) {
|
||||
List<AliasData> aliases = Collections.emptyList();
|
||||
|
||||
if (getIndexResponse.getAliases().get(indexName) != null) {
|
||||
aliases = getIndexResponse.getAliases().get(indexName).stream().map(ResponseConverter::toAliasData)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
return aliases;
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region templates
|
||||
@Nullable
|
||||
public static TemplateData getTemplateData(GetIndexTemplatesResponse getIndexTemplatesResponse, String templateName) {
|
||||
for (IndexTemplateMetadata indexTemplateMetadata : getIndexTemplatesResponse.getIndexTemplates()) {
|
||||
|
||||
if (indexTemplateMetadata.name().equals(templateName)) {
|
||||
|
||||
Settings settings = new Settings();
|
||||
org.elasticsearch.common.settings.Settings templateSettings = indexTemplateMetadata.settings();
|
||||
templateSettings.keySet().forEach(key -> settings.put(key, templateSettings.get(key)));
|
||||
|
||||
Map<String, AliasData> aliases = new LinkedHashMap<>();
|
||||
|
||||
ImmutableOpenMap<String, AliasMetadata> aliasesResponse = indexTemplateMetadata.aliases();
|
||||
Iterator<String> keysIt = aliasesResponse.keysIt();
|
||||
while (keysIt.hasNext()) {
|
||||
String key = keysIt.next();
|
||||
aliases.put(key, ResponseConverter.toAliasData(aliasesResponse.get(key)));
|
||||
}
|
||||
|
||||
return TemplateData.builder().withIndexPatterns(indexTemplateMetadata.patterns().toArray(new String[0])) //
|
||||
.withSettings(settings) //
|
||||
.withMapping(Document.from(indexTemplateMetadata.mappings().getSourceAsMap())) //
|
||||
.withAliases(aliases) //
|
||||
.withOrder(indexTemplateMetadata.order()) //
|
||||
.withVersion(indexTemplateMetadata.version()).build();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region settings
|
||||
/**
|
||||
* extract the index settings information for a given index
|
||||
*
|
||||
* @param response the Elasticsearch response
|
||||
* @param indexName the index name
|
||||
* @return settings
|
||||
*/
|
||||
public static Settings fromSettingsResponse(GetSettingsResponse response, String indexName) {
|
||||
|
||||
Settings settings = new Settings();
|
||||
|
||||
if (!response.getIndexToDefaultSettings().isEmpty()) {
|
||||
org.elasticsearch.common.settings.Settings defaultSettings = response.getIndexToDefaultSettings().get(indexName);
|
||||
for (String key : defaultSettings.keySet()) {
|
||||
settings.put(key, defaultSettings.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
if (!response.getIndexToSettings().isEmpty()) {
|
||||
org.elasticsearch.common.settings.Settings customSettings = response.getIndexToSettings().get(indexName);
|
||||
for (String key : customSettings.keySet()) {
|
||||
settings.put(key, customSettings.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region multiget
|
||||
|
||||
@Nullable
|
||||
public static MultiGetItem.Failure getFailure(MultiGetItemResponse itemResponse) {
|
||||
|
||||
MultiGetResponse.Failure responseFailure = itemResponse.getFailure();
|
||||
return responseFailure != null ? MultiGetItem.Failure.of(responseFailure.getIndex(), responseFailure.getType(),
|
||||
responseFailure.getId(), responseFailure.getFailure()) : null;
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region cluster operations
|
||||
public static ClusterHealth clusterHealth(ClusterHealthResponse clusterHealthResponse) {
|
||||
return ClusterHealth.builder() //
|
||||
.withActivePrimaryShards(clusterHealthResponse.getActivePrimaryShards()) //
|
||||
.withActiveShards(clusterHealthResponse.getActiveShards()) //
|
||||
.withActiveShardsPercent(clusterHealthResponse.getActiveShardsPercent()) //
|
||||
.withClusterName(clusterHealthResponse.getClusterName()) //
|
||||
.withDelayedUnassignedShards(clusterHealthResponse.getDelayedUnassignedShards()) //
|
||||
.withInitializingShards(clusterHealthResponse.getInitializingShards()) //
|
||||
.withNumberOfDataNodes(clusterHealthResponse.getNumberOfDataNodes()) //
|
||||
.withNumberOfInFlightFetch(clusterHealthResponse.getNumberOfInFlightFetch()) //
|
||||
.withNumberOfNodes(clusterHealthResponse.getNumberOfNodes()) //
|
||||
.withNumberOfPendingTasks(clusterHealthResponse.getNumberOfPendingTasks()) //
|
||||
.withRelocatingShards(clusterHealthResponse.getRelocatingShards()) //
|
||||
.withStatus(clusterHealthResponse.getStatus().toString()) //
|
||||
.withTaskMaxWaitingTimeMillis(clusterHealthResponse.getTaskMaxWaitingTime().millis()) //
|
||||
.withTimedOut(clusterHealthResponse.isTimedOut()) //
|
||||
.withUnassignedShards(clusterHealthResponse.getUnassignedShards()) //
|
||||
.build(); //
|
||||
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
@@ -30,9 +30,10 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Encapsulates the found data with additional information from the search.
|
||||
*
|
||||
*
|
||||
* @param <T> the result data class.
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Matt Gilene
|
||||
* @since 4.0
|
||||
*/
|
||||
public class SearchHit<T> {
|
||||
@@ -47,16 +48,22 @@ public class SearchHit<T> {
|
||||
@Nullable private final NestedMetaData nestedMetaData;
|
||||
@Nullable private final String routing;
|
||||
@Nullable private final Explanation explanation;
|
||||
private final List<String> matchedQueries = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* @deprecated since 4.2 use
|
||||
* {@link #SearchHit(String, String, String, float, Object[], Map, Map, NestedMetaData, Explanation, List, Object)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public SearchHit(@Nullable String index, @Nullable String id, @Nullable String routing, float score,
|
||||
@Nullable Object[] sortValues, @Nullable Map<String, List<String>> highlightFields, T content) {
|
||||
this(index, id, routing, score, sortValues, highlightFields, null, null, null, content);
|
||||
this(index, id, routing, score, sortValues, highlightFields, null, null, null, null, content);
|
||||
}
|
||||
|
||||
public SearchHit(@Nullable String index, @Nullable String id, @Nullable String routing, float score,
|
||||
@Nullable Object[] sortValues, @Nullable Map<String, List<String>> highlightFields,
|
||||
@Nullable Map<String, SearchHits<?>> innerHits, @Nullable NestedMetaData nestedMetaData,
|
||||
@Nullable Explanation explanation, T content) {
|
||||
@Nullable Explanation explanation, @Nullable List<String> matchedQueries, T content) {
|
||||
this.index = index;
|
||||
this.id = id;
|
||||
this.routing = routing;
|
||||
@@ -74,6 +81,10 @@ public class SearchHit<T> {
|
||||
this.nestedMetaData = nestedMetaData;
|
||||
this.explanation = explanation;
|
||||
this.content = content;
|
||||
|
||||
if (matchedQueries != null) {
|
||||
this.matchedQueries.addAll(matchedQueries);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,7 +132,7 @@ public class SearchHit<T> {
|
||||
|
||||
/**
|
||||
* gets the highlight values for a field.
|
||||
*
|
||||
*
|
||||
* @param field must not be {@literal null}
|
||||
* @return possibly empty List, never null
|
||||
*/
|
||||
@@ -137,7 +148,7 @@ public class SearchHit<T> {
|
||||
* nested entity class, the returned data will be of this type, otherwise
|
||||
* {{@link org.springframework.data.elasticsearch.core.document.SearchDocument}} instances are returned in this
|
||||
* {@link SearchHits} object.
|
||||
*
|
||||
*
|
||||
* @param name the inner hits name
|
||||
* @return {@link SearchHits} if available, otherwise {@literal null}
|
||||
*/
|
||||
@@ -156,7 +167,7 @@ public class SearchHit<T> {
|
||||
|
||||
/**
|
||||
* If this is a nested inner hit, return the nested metadata information
|
||||
*
|
||||
*
|
||||
* @return {{@link NestedMetaData}
|
||||
* @since 4.1
|
||||
*/
|
||||
@@ -188,4 +199,12 @@ public class SearchHit<T> {
|
||||
public Explanation getExplanation() {
|
||||
return explanation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the matched queries for this SearchHit.
|
||||
*/
|
||||
@Nullable
|
||||
public List<String> getMatchedQueries() {
|
||||
return matchedQueries;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,7 @@ import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.elasticsearch.search.aggregations.Aggregations;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.data.elasticsearch.core.document.NestedMetaData;
|
||||
@@ -43,12 +42,12 @@ import org.springframework.util.Assert;
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Mark Paluch
|
||||
* @author Roman Puchkovskiy
|
||||
* @author Matt Gilene
|
||||
* @author Sascha Woo
|
||||
* @since 4.0
|
||||
*/
|
||||
class SearchHitMapping<T> {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SearchHitMapping.class);
|
||||
|
||||
private final Class<T> type;
|
||||
private final ElasticsearchConverter converter;
|
||||
private final MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext;
|
||||
@@ -114,6 +113,7 @@ class SearchHitMapping<T> {
|
||||
mapInnerHits(searchDocument), //
|
||||
searchDocument.getNestedMetaData(), //
|
||||
searchDocument.getExplanation(), //
|
||||
searchDocument.getMatchedQueries(), //
|
||||
content); //
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ class SearchHitMapping<T> {
|
||||
*/
|
||||
private SearchHits<?> mapInnerDocuments(SearchHits<SearchDocument> searchHits, Class<T> type) {
|
||||
|
||||
if (searchHits.getTotalHits() == 0) {
|
||||
if (searchHits.isEmpty()) {
|
||||
return searchHits;
|
||||
}
|
||||
|
||||
@@ -198,6 +198,7 @@ class SearchHitMapping<T> {
|
||||
searchHit.getInnerHits(), //
|
||||
persistentEntityWithNestedMetaData.nestedMetaData, //
|
||||
searchHit.getExplanation(), //
|
||||
searchHit.getMatchedQueries(), //
|
||||
targetObject));
|
||||
});
|
||||
|
||||
@@ -214,7 +215,7 @@ class SearchHitMapping<T> {
|
||||
searchHits.getAggregations());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("Could not map inner_hits", e);
|
||||
throw new UncategorizedElasticsearchException("Unable to convert inner hits.", e);
|
||||
}
|
||||
|
||||
return searchHits;
|
||||
|
||||
@@ -68,7 +68,7 @@ public interface SearchOperations {
|
||||
* Does a suggest query
|
||||
*
|
||||
* @param suggestion the query
|
||||
* @param the entity class
|
||||
* @param clazz the entity class
|
||||
* @return the suggest response
|
||||
* @since 4.1
|
||||
*/
|
||||
|
||||
@@ -66,10 +66,14 @@ abstract class StreamQueries {
|
||||
private volatile Iterator<SearchHit<T>> currentScrollHits = searchHits.iterator();
|
||||
private volatile boolean continueScroll = currentScrollHits.hasNext();
|
||||
private volatile ScrollState scrollState = new ScrollState(searchHits.getScrollId());
|
||||
private volatile boolean isClosed = false;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
clearScrollConsumer.accept(scrollState.getScrollIds());
|
||||
if (!isClosed) {
|
||||
clearScrollConsumer.accept(scrollState.getScrollIds());
|
||||
isClosed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,18 +100,24 @@ abstract class StreamQueries {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
|
||||
if (!continueScroll || (maxCount > 0 && currentCount.get() >= maxCount)) {
|
||||
return false;
|
||||
boolean hasNext = false;
|
||||
|
||||
if (!isClosed && continueScroll && (maxCount <= 0 || currentCount.get() < maxCount)) {
|
||||
|
||||
if (!currentScrollHits.hasNext()) {
|
||||
SearchScrollHits<T> nextPage = continueScrollFunction.apply(scrollState.getScrollId());
|
||||
currentScrollHits = nextPage.iterator();
|
||||
scrollState.updateScrollId(nextPage.getScrollId());
|
||||
continueScroll = currentScrollHits.hasNext();
|
||||
}
|
||||
hasNext = currentScrollHits.hasNext();
|
||||
}
|
||||
|
||||
if (!currentScrollHits.hasNext()) {
|
||||
SearchScrollHits<T> nextPage = continueScrollFunction.apply(scrollState.getScrollId());
|
||||
currentScrollHits = nextPage.iterator();
|
||||
scrollState.updateScrollId(nextPage.getScrollId());
|
||||
continueScroll = currentScrollHits.hasNext();
|
||||
if (!hasNext) {
|
||||
close();
|
||||
}
|
||||
|
||||
return currentScrollHits.hasNext();
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright 2021 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.cluster;
|
||||
|
||||
/**
|
||||
* Information about the cluster health. Contains currently only the top level elements returned from Elasticsearch.
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.2
|
||||
*/
|
||||
public class ClusterHealth {
|
||||
|
||||
private final String clusterName;
|
||||
private final String status;
|
||||
private final int numberOfNodes;
|
||||
private final int numberOfDataNodes;
|
||||
private final int activeShards;
|
||||
private final int relocatingShards;
|
||||
private final int activePrimaryShards;
|
||||
private final int initializingShards;
|
||||
private final int unassignedShards;
|
||||
private final double activeShardsPercent;
|
||||
private final int numberOfPendingTasks;
|
||||
private final boolean timedOut;
|
||||
private final int numberOfInFlightFetch;
|
||||
private final int delayedUnassignedShards;
|
||||
private final long taskMaxWaitingTimeMillis;
|
||||
|
||||
private ClusterHealth(String clusterName, String status, int numberOfNodes, int numberOfDataNodes, int activeShards,
|
||||
int relocatingShards, int activePrimaryShards, int initializingShards, int unassignedShards,
|
||||
double activeShardsPercent, int numberOfPendingTasks, boolean timedOut, int numberOfInFlightFetch,
|
||||
int delayedUnassignedShards, long taskMaxWaitingTimeMillis) {
|
||||
this.clusterName = clusterName;
|
||||
this.status = status;
|
||||
this.numberOfNodes = numberOfNodes;
|
||||
this.numberOfDataNodes = numberOfDataNodes;
|
||||
this.activeShards = activeShards;
|
||||
this.relocatingShards = relocatingShards;
|
||||
this.activePrimaryShards = activePrimaryShards;
|
||||
this.initializingShards = initializingShards;
|
||||
this.unassignedShards = unassignedShards;
|
||||
this.activeShardsPercent = activeShardsPercent;
|
||||
this.numberOfPendingTasks = numberOfPendingTasks;
|
||||
this.timedOut = timedOut;
|
||||
this.numberOfInFlightFetch = numberOfInFlightFetch;
|
||||
this.delayedUnassignedShards = delayedUnassignedShards;
|
||||
this.taskMaxWaitingTimeMillis = taskMaxWaitingTimeMillis;
|
||||
}
|
||||
|
||||
public String getClusterName() {
|
||||
return clusterName;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public int getNumberOfNodes() {
|
||||
return numberOfNodes;
|
||||
}
|
||||
|
||||
public int getNumberOfDataNodes() {
|
||||
return numberOfDataNodes;
|
||||
}
|
||||
|
||||
public int getActiveShards() {
|
||||
return activeShards;
|
||||
}
|
||||
|
||||
public int getRelocatingShards() {
|
||||
return relocatingShards;
|
||||
}
|
||||
|
||||
public int getActivePrimaryShards() {
|
||||
return activePrimaryShards;
|
||||
}
|
||||
|
||||
public int getInitializingShards() {
|
||||
return initializingShards;
|
||||
}
|
||||
|
||||
public int getUnassignedShards() {
|
||||
return unassignedShards;
|
||||
}
|
||||
|
||||
public double getActiveShardsPercent() {
|
||||
return activeShardsPercent;
|
||||
}
|
||||
|
||||
public int getNumberOfPendingTasks() {
|
||||
return numberOfPendingTasks;
|
||||
}
|
||||
|
||||
public boolean isTimedOut() {
|
||||
return timedOut;
|
||||
}
|
||||
|
||||
public int getNumberOfInFlightFetch() {
|
||||
return numberOfInFlightFetch;
|
||||
}
|
||||
|
||||
public int getDelayedUnassignedShards() {
|
||||
return delayedUnassignedShards;
|
||||
}
|
||||
|
||||
public long getTaskMaxWaitingTimeMillis() {
|
||||
return taskMaxWaitingTimeMillis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterHealth{" +
|
||||
"clusterName='" + clusterName + '\'' +
|
||||
", status='" + status + '\'' +
|
||||
", numberOfNodes=" + numberOfNodes +
|
||||
", numberOfDataNodes=" + numberOfDataNodes +
|
||||
", activeShards=" + activeShards +
|
||||
", relocatingShards=" + relocatingShards +
|
||||
", activePrimaryShards=" + activePrimaryShards +
|
||||
", initializingShards=" + initializingShards +
|
||||
", unassignedShards=" + unassignedShards +
|
||||
", activeShardsPercent=" + activeShardsPercent +
|
||||
", numberOfPendingTasks=" + numberOfPendingTasks +
|
||||
", timedOut=" + timedOut +
|
||||
", numberOfInFlightFetch=" + numberOfInFlightFetch +
|
||||
", delayedUnassignedShards=" + delayedUnassignedShards +
|
||||
", taskMaxWaitingTimeMillis=" + taskMaxWaitingTimeMillis +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static ClusterHealthBuilder builder() {
|
||||
return new ClusterHealthBuilder();
|
||||
}
|
||||
|
||||
public static final class ClusterHealthBuilder {
|
||||
private String clusterName = "";
|
||||
private String status = "";
|
||||
private int numberOfNodes;
|
||||
private int numberOfDataNodes;
|
||||
private int activeShards;
|
||||
private int relocatingShards;
|
||||
private int activePrimaryShards;
|
||||
private int initializingShards;
|
||||
private int unassignedShards;
|
||||
private double activeShardsPercent;
|
||||
private int numberOfPendingTasks;
|
||||
private boolean timedOut;
|
||||
private int numberOfInFlightFetch;
|
||||
private int delayedUnassignedShards;
|
||||
private long taskMaxWaitingTimeMillis;
|
||||
|
||||
private ClusterHealthBuilder() {}
|
||||
|
||||
public ClusterHealthBuilder withClusterName(String clusterName) {
|
||||
this.clusterName = clusterName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterHealthBuilder withStatus(String status) {
|
||||
this.status = status;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterHealthBuilder withNumberOfNodes(int numberOfNodes) {
|
||||
this.numberOfNodes = numberOfNodes;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterHealthBuilder withNumberOfDataNodes(int numberOfDataNodes) {
|
||||
this.numberOfDataNodes = numberOfDataNodes;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterHealthBuilder withActiveShards(int activeShards) {
|
||||
this.activeShards = activeShards;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterHealthBuilder withRelocatingShards(int relocatingShards) {
|
||||
this.relocatingShards = relocatingShards;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterHealthBuilder withActivePrimaryShards(int activePrimaryShards) {
|
||||
this.activePrimaryShards = activePrimaryShards;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterHealthBuilder withInitializingShards(int initializingShards) {
|
||||
this.initializingShards = initializingShards;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterHealthBuilder withUnassignedShards(int unassignedShards) {
|
||||
this.unassignedShards = unassignedShards;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterHealthBuilder withActiveShardsPercent(double activeShardsPercent) {
|
||||
this.activeShardsPercent = activeShardsPercent;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterHealthBuilder withNumberOfPendingTasks(int numberOfPendingTasks) {
|
||||
this.numberOfPendingTasks = numberOfPendingTasks;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterHealthBuilder withTimedOut(boolean timedOut) {
|
||||
this.timedOut = timedOut;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterHealthBuilder withNumberOfInFlightFetch(int numberOfInFlightFetch) {
|
||||
this.numberOfInFlightFetch = numberOfInFlightFetch;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterHealthBuilder withDelayedUnassignedShards(int delayedUnassignedShards) {
|
||||
this.delayedUnassignedShards = delayedUnassignedShards;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterHealthBuilder withTaskMaxWaitingTimeMillis(long taskMaxWaitingTimeMillis) {
|
||||
this.taskMaxWaitingTimeMillis = taskMaxWaitingTimeMillis;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterHealth build() {
|
||||
return new ClusterHealth(clusterName, status, numberOfNodes, numberOfDataNodes, activeShards, relocatingShards,
|
||||
activePrimaryShards, initializingShards, unassignedShards, activeShardsPercent, numberOfPendingTasks,
|
||||
timedOut, numberOfInFlightFetch, delayedUnassignedShards, taskMaxWaitingTimeMillis);
|
||||
}
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2021 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.cluster;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Elasticsearch operations on cluster level.
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.2
|
||||
*/
|
||||
public interface ClusterOperations {
|
||||
|
||||
/**
|
||||
* Creates a ClusterOperations for a {@link ElasticsearchRestTemplate}.
|
||||
*
|
||||
* @param template the template, must not be {@literal null}
|
||||
* @return ClusterOperations
|
||||
*/
|
||||
static ClusterOperations forTemplate(ElasticsearchRestTemplate template) {
|
||||
|
||||
Assert.notNull(template, "template must not be null");
|
||||
|
||||
return new DefaultClusterOperations(template);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ClusterOperations for a {@link ElasticsearchTemplate}.
|
||||
*
|
||||
* @param template the template, must not be {@literal null}
|
||||
* @return ClusterOperations
|
||||
*/
|
||||
static ClusterOperations forTemplate(ElasticsearchTemplate template) {
|
||||
|
||||
Assert.notNull(template, "template must not be null");
|
||||
|
||||
return new DefaultTransportClusterOperations(template);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the cluster's health status.
|
||||
*
|
||||
* @return health information for the cluster.
|
||||
*/
|
||||
ClusterHealth health();
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2021 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.cluster;
|
||||
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
|
||||
import org.springframework.data.elasticsearch.core.ResponseConverter;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link ClusterOperations} using the {@link ElasticsearchRestTemplate}.
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.2
|
||||
*/
|
||||
class DefaultClusterOperations implements ClusterOperations {
|
||||
|
||||
private final ElasticsearchRestTemplate template;
|
||||
|
||||
DefaultClusterOperations(ElasticsearchRestTemplate template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClusterHealth health() {
|
||||
|
||||
ClusterHealthResponse clusterHealthResponse = template
|
||||
.execute(client -> client.cluster().health(new ClusterHealthRequest(), RequestOptions.DEFAULT));
|
||||
return ResponseConverter.clusterHealth(clusterHealthResponse);
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2021 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.cluster;
|
||||
|
||||
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.ResponseConverter;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link ReactiveClusterOperations} using the {@link ReactiveElasticsearchOperations}.
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.2
|
||||
*/
|
||||
public class DefaultReactiveClusterOperations implements ReactiveClusterOperations {
|
||||
private final ReactiveElasticsearchOperations operations;
|
||||
|
||||
public DefaultReactiveClusterOperations(ReactiveElasticsearchOperations operations) {
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ClusterHealth> health() {
|
||||
return Mono.from(operations.executeWithClusterClient(
|
||||
client -> client.health(new ClusterHealthRequest()).map(ResponseConverter::clusterHealth)));
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2021 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.cluster;
|
||||
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.core.ResponseConverter;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link ClusterOperations} using the
|
||||
* {@link org.elasticsearch.client.transport.TransportClient}.
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.2
|
||||
*/
|
||||
public class DefaultTransportClusterOperations implements ClusterOperations {
|
||||
|
||||
private final ElasticsearchTemplate template;
|
||||
|
||||
public DefaultTransportClusterOperations(ElasticsearchTemplate template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClusterHealth health() {
|
||||
|
||||
ClusterHealthResponse clusterHealthResponse = template.getClient().admin().cluster()
|
||||
.health(new ClusterHealthRequest()).actionGet();
|
||||
return ResponseConverter.clusterHealth(clusterHealthResponse);
|
||||
}
|
||||
}
|
||||
+14
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2021 the original author or authors.
|
||||
* Copyright 2021 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.
|
||||
@@ -13,26 +13,22 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.immutable;
|
||||
package org.springframework.data.elasticsearch.core.cluster;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author Young Gu
|
||||
* @author Oliver Gierke
|
||||
* Reactive Elasticsearch operations on cluster level.
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.2
|
||||
*/
|
||||
@Document(indexName = "test-index-immutable")
|
||||
@NoArgsConstructor(force = true)
|
||||
@Getter
|
||||
public class ImmutableEntity {
|
||||
private final String id, name;
|
||||
public interface ReactiveClusterOperations {
|
||||
|
||||
public ImmutableEntity(String name) {
|
||||
|
||||
this.id = null;
|
||||
this.name = name;
|
||||
}
|
||||
/**
|
||||
* get the cluster's health status.
|
||||
*
|
||||
* @return a Mono emitting the health information for the cluster.
|
||||
*/
|
||||
Mono<ClusterHealth> health();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Interfaces and classes related to Elasticsearch cluster information and management.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.elasticsearch.core.cluster;
|
||||
+13
-25
@@ -19,7 +19,6 @@ import org.springframework.data.convert.EntityConverter;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||
@@ -64,7 +63,13 @@ public interface ElasticsearchConverter
|
||||
return idValue.toString();
|
||||
}
|
||||
|
||||
return getConversionService().convert(idValue, String.class);
|
||||
String converted = getConversionService().convert(idValue, String.class);
|
||||
|
||||
if (converted == null) {
|
||||
return idValue.toString();
|
||||
}
|
||||
|
||||
return converted;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,32 +91,15 @@ public interface ElasticsearchConverter
|
||||
|
||||
// region query
|
||||
/**
|
||||
* Updates a query by renaming the property names in the query to the correct mapped field names and the values to the
|
||||
* converted values if the {@link ElasticsearchPersistentProperty} for a property has a
|
||||
* Updates a {@link Query} by renaming the property names in the query to the correct mapped field names and the
|
||||
* values to the converted values if the {@link ElasticsearchPersistentProperty} for a property has a
|
||||
* {@link org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentPropertyConverter}. If
|
||||
* domainClass is null, it's a noop; handling null here eliminates null checks in the caller.
|
||||
*
|
||||
* @param query the query that is internally updated
|
||||
* @param domainClass the class of the object that is searched with the query
|
||||
*/
|
||||
default void updateQuery(Query query, @Nullable Class<?> domainClass) {
|
||||
|
||||
if (domainClass != null) {
|
||||
|
||||
if (query instanceof CriteriaQuery) {
|
||||
updateCriteriaQuery((CriteriaQuery) query, domainClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a {@link CriteriaQuery} by renaming the property names in the query to the correct mapped field names and
|
||||
* the values to the converted values if the {@link ElasticsearchPersistentProperty} for a property has a
|
||||
* {@link org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentPropertyConverter}.
|
||||
* domainClass is null it's a noop.
|
||||
*
|
||||
* @param criteriaQuery the query that is internally updated
|
||||
* @param query the query that is internally updated, must not be {@literal null}
|
||||
* @param domainClass the class of the object that is searched with the query
|
||||
*/
|
||||
void updateCriteriaQuery(CriteriaQuery criteriaQuery, Class<?> domainClass);
|
||||
void updateQuery(Query query, @Nullable Class<?> domainClass);
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
||||
+171
-51
@@ -23,7 +23,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -34,6 +33,7 @@ import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.data.convert.CustomConversions;
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||
import org.springframework.data.elasticsearch.annotations.ScriptedField;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.data.elasticsearch.core.document.SearchDocument;
|
||||
@@ -42,8 +42,11 @@ import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersiste
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentPropertyConverter;
|
||||
import org.springframework.data.elasticsearch.core.query.Criteria;
|
||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
|
||||
import org.springframework.data.elasticsearch.core.query.Field;
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm;
|
||||
import org.springframework.data.elasticsearch.core.query.SourceFilter;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
@@ -169,8 +172,15 @@ public class MappingElasticsearchConverter
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <R> R read(Class<R> type, Document source) {
|
||||
|
||||
TypeInformation<R> typeHint = ClassTypeInformation.from((Class<R>) ClassUtils.getUserClass(type));
|
||||
return read(typeHint, source);
|
||||
R r = read(typeHint, source);
|
||||
|
||||
if (r == null) {
|
||||
throw new ConversionException("could not convert into object of class " + type);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
protected <R> R readEntity(ElasticsearchPersistentEntity<?> entity, Map<String, Object> source) {
|
||||
@@ -189,7 +199,7 @@ public class MappingElasticsearchConverter
|
||||
|
||||
EntityInstantiator instantiator = instantiators.getInstantiatorFor(targetEntity);
|
||||
|
||||
@SuppressWarnings({ "unchecked", "ConstantConditions" })
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
R instance = (R) instantiator.createInstance(targetEntity, propertyValueProvider);
|
||||
|
||||
if (!targetEntity.requiresPropertyPopulation()) {
|
||||
@@ -247,6 +257,7 @@ public class MappingElasticsearchConverter
|
||||
ElasticsearchPropertyValueProvider provider = new ElasticsearchPropertyValueProvider(source, evaluator);
|
||||
|
||||
// TODO: Support for non-static inner classes via ObjectPath
|
||||
// noinspection ConstantConditions
|
||||
PersistentEntityParameterValueProvider<ElasticsearchPersistentProperty> parameterProvider = new PersistentEntityParameterValueProvider<>(
|
||||
entity, provider, null);
|
||||
|
||||
@@ -282,7 +293,6 @@ public class MappingElasticsearchConverter
|
||||
return accessor.getBean();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
protected <R> R readValue(@Nullable Object value, ElasticsearchPersistentProperty property, TypeInformation<?> type) {
|
||||
|
||||
@@ -350,7 +360,7 @@ public class MappingElasticsearchConverter
|
||||
}
|
||||
|
||||
if (typeToUse.isMap()) {
|
||||
return (R) readMap(typeToUse, source);
|
||||
return readMap(typeToUse, source);
|
||||
}
|
||||
|
||||
if (typeToUse.equals(ClassTypeInformation.OBJECT)) {
|
||||
@@ -550,25 +560,25 @@ public class MappingElasticsearchConverter
|
||||
}
|
||||
|
||||
Class<?> entityType = ClassUtils.getUserClass(source.getClass());
|
||||
TypeInformation<? extends Object> type = ClassTypeInformation.from(entityType);
|
||||
TypeInformation<?> typeInformation = ClassTypeInformation.from(entityType);
|
||||
|
||||
if (requiresTypeHint(entityType)) {
|
||||
typeMapper.writeType(type, sink);
|
||||
typeMapper.writeType(typeInformation, sink);
|
||||
}
|
||||
|
||||
writeInternal(source, sink, type);
|
||||
writeInternal(source, sink, typeInformation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal write conversion method which should be used for nested invocations.
|
||||
*
|
||||
* @param source
|
||||
* @param sink
|
||||
* @param typeHint
|
||||
* @param source the object to write
|
||||
* @param sink the write destination
|
||||
* @param typeInformation type information for the source
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void writeInternal(@Nullable Object source, Map<String, Object> sink,
|
||||
@Nullable TypeInformation<?> typeHint) {
|
||||
@Nullable TypeInformation<?> typeInformation) {
|
||||
|
||||
if (null == source) {
|
||||
return;
|
||||
@@ -579,7 +589,10 @@ public class MappingElasticsearchConverter
|
||||
|
||||
if (customTarget.isPresent()) {
|
||||
Map<String, Object> result = conversionService.convert(source, Map.class);
|
||||
sink.putAll(result);
|
||||
|
||||
if (result != null) {
|
||||
sink.putAll(result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -594,16 +607,16 @@ public class MappingElasticsearchConverter
|
||||
}
|
||||
|
||||
ElasticsearchPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(entityType);
|
||||
addCustomTypeKeyIfNecessary(typeHint, source, sink);
|
||||
addCustomTypeKeyIfNecessary(source, sink, typeInformation);
|
||||
writeInternal(source, sink, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal write conversion method which should be used for nested invocations.
|
||||
*
|
||||
* @param source
|
||||
* @param sink
|
||||
* @param typeHint
|
||||
* @param source the object to write
|
||||
* @param sink the write destination
|
||||
* @param entity entity for the source
|
||||
*/
|
||||
protected void writeInternal(@Nullable Object source, Map<String, Object> sink,
|
||||
@Nullable ElasticsearchPersistentEntity<?> entity) {
|
||||
@@ -725,7 +738,7 @@ public class MappingElasticsearchConverter
|
||||
Map<String, Object> document = existingValue instanceof Map ? (Map<String, Object>) existingValue
|
||||
: Document.create();
|
||||
|
||||
addCustomTypeKeyIfNecessary(ClassTypeInformation.from(property.getRawType()), value, document);
|
||||
addCustomTypeKeyIfNecessary(value, document, ClassTypeInformation.from(property.getRawType()));
|
||||
writeInternal(value, document, entity);
|
||||
sink.set(property, document);
|
||||
}
|
||||
@@ -735,7 +748,6 @@ public class MappingElasticsearchConverter
|
||||
*
|
||||
* @param collection must not be {@literal null}.
|
||||
* @param property must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected List<Object> createCollection(Collection<?> collection, ElasticsearchPersistentProperty property) {
|
||||
return writeCollectionInternal(collection, property.getTypeInformation(), new ArrayList<>(collection.size()));
|
||||
@@ -746,7 +758,6 @@ public class MappingElasticsearchConverter
|
||||
*
|
||||
* @param map must not {@literal null}.
|
||||
* @param property must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected Map<String, Object> createMap(Map<?, ?> map, ElasticsearchPersistentProperty property) {
|
||||
|
||||
@@ -762,7 +773,6 @@ public class MappingElasticsearchConverter
|
||||
* @param source must not be {@literal null}.
|
||||
* @param sink must not be {@literal null}.
|
||||
* @param propertyType must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected Map<String, Object> writeMapInternal(Map<?, ?> source, Map<String, Object> sink,
|
||||
TypeInformation<?> propertyType) {
|
||||
@@ -802,7 +812,6 @@ public class MappingElasticsearchConverter
|
||||
* @param source the collection to create a {@link Collection} for, must not be {@literal null}.
|
||||
* @param type the {@link TypeInformation} to consider or {@literal null} if unknown.
|
||||
* @param sink the {@link Collection} to write to.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<Object> writeCollectionInternal(Collection<?> source, @Nullable TypeInformation<?> type,
|
||||
@@ -838,8 +847,7 @@ public class MappingElasticsearchConverter
|
||||
/**
|
||||
* Returns a {@link String} representation of the given {@link Map} key
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
* @param key the key to convert
|
||||
*/
|
||||
private String potentiallyConvertMapKey(Object key) {
|
||||
|
||||
@@ -847,17 +855,22 @@ public class MappingElasticsearchConverter
|
||||
return (String) key;
|
||||
}
|
||||
|
||||
return conversions.hasCustomWriteTarget(key.getClass(), String.class)
|
||||
? (String) getPotentiallyConvertedSimpleWrite(key, Object.class)
|
||||
: key.toString();
|
||||
if (conversions.hasCustomWriteTarget(key.getClass(), String.class)) {
|
||||
Object potentiallyConvertedSimpleWrite = getPotentiallyConvertedSimpleWrite(key, Object.class);
|
||||
|
||||
if (potentiallyConvertedSimpleWrite == null) {
|
||||
return key.toString();
|
||||
}
|
||||
return (String) potentiallyConvertedSimpleWrite;
|
||||
}
|
||||
return key.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether we have a custom conversion registered for the given value into an arbitrary simple Elasticsearch
|
||||
* type. Returns the converted value if so. If not, we perform special enum handling or simply return the value as is.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
* @param value value to convert
|
||||
*/
|
||||
@Nullable
|
||||
private Object getPotentiallyConvertedSimpleWrite(@Nullable Object value, @Nullable Class<?> typeHint) {
|
||||
@@ -870,6 +883,10 @@ public class MappingElasticsearchConverter
|
||||
|
||||
if (conversionService.canConvert(value.getClass(), typeHint)) {
|
||||
value = conversionService.convert(value, typeHint);
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -909,8 +926,8 @@ public class MappingElasticsearchConverter
|
||||
* @deprecated since 4.2, use {@link #writeInternal(Object, Map, TypeInformation)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
protected Object getWriteComplexValue(ElasticsearchPersistentProperty property, TypeInformation<?> typeHint,
|
||||
Object value) {
|
||||
protected Object getWriteComplexValue(ElasticsearchPersistentProperty property,
|
||||
@SuppressWarnings("unused") TypeInformation<?> typeHint, Object value) {
|
||||
|
||||
Document document = Document.create();
|
||||
writeInternal(value, document, property.getTypeInformation());
|
||||
@@ -923,18 +940,26 @@ public class MappingElasticsearchConverter
|
||||
// region helper methods
|
||||
|
||||
/**
|
||||
* Adds custom type information to the given {@link Map} if necessary. That is if the value is not the same as the one
|
||||
* given. This is usually the case if you store a subtype of the actual declared type of the property.
|
||||
* Adds custom typeInformation information to the given {@link Map} if necessary. That is if the value is not the same
|
||||
* as the one given. This is usually the case if you store a subtype of the actual declared typeInformation of the
|
||||
* property.
|
||||
*
|
||||
* @param type
|
||||
* @param value must not be {@literal null}.
|
||||
* @param source must not be {@literal null}.
|
||||
* @param sink must not be {@literal null}.
|
||||
* @param type type to compare to
|
||||
*/
|
||||
protected void addCustomTypeKeyIfNecessary(@Nullable TypeInformation<?> type, Object value,
|
||||
Map<String, Object> sink) {
|
||||
protected void addCustomTypeKeyIfNecessary(Object source, Map<String, Object> sink,
|
||||
@Nullable TypeInformation<?> type) {
|
||||
|
||||
Class<?> reference = type != null ? type.getActualType().getType() : Object.class;
|
||||
Class<?> valueType = ClassUtils.getUserClass(value.getClass());
|
||||
Class<?> reference;
|
||||
|
||||
if (type == null) {
|
||||
reference = Object.class;
|
||||
} else {
|
||||
TypeInformation<?> actualType = type.getActualType();
|
||||
reference = actualType == null ? Object.class : actualType.getType();
|
||||
}
|
||||
Class<?> valueType = ClassUtils.getUserClass(source.getClass());
|
||||
|
||||
boolean notTheSameClass = !valueType.equals(reference);
|
||||
if (notTheSameClass) {
|
||||
@@ -948,7 +973,7 @@ public class MappingElasticsearchConverter
|
||||
* @param type must not be {@literal null}.
|
||||
* @return {@literal true} if not a simple type, {@link Collection} or type with custom write target.
|
||||
*/
|
||||
private boolean requiresTypeHint(Class<?> type) {
|
||||
public boolean requiresTypeHint(Class<?> type) {
|
||||
|
||||
return !isSimpleType(type) && !ClassUtils.isAssignable(Collection.class, type)
|
||||
&& !conversions.hasCustomWriteTarget(type, Document.class);
|
||||
@@ -988,8 +1013,7 @@ public class MappingElasticsearchConverter
|
||||
* {@link Collection} already, will convert an array into a {@link Collection} or simply create a single element
|
||||
* collection for everything else.
|
||||
*
|
||||
* @param source
|
||||
* @return
|
||||
* @param source object to convert
|
||||
*/
|
||||
private static Collection<?> asCollection(Object source) {
|
||||
|
||||
@@ -1003,7 +1027,64 @@ public class MappingElasticsearchConverter
|
||||
|
||||
// region queries
|
||||
@Override
|
||||
public void updateCriteriaQuery(CriteriaQuery criteriaQuery, Class<?> domainClass) {
|
||||
public void updateQuery(Query query, @Nullable Class<?> domainClass) {
|
||||
|
||||
Assert.notNull(query, "query must not be null");
|
||||
|
||||
if (domainClass != null) {
|
||||
|
||||
updateFieldsAndSourceFilter(query, domainClass);
|
||||
|
||||
if (query instanceof CriteriaQuery) {
|
||||
updateCriteriaQuery((CriteriaQuery) query, domainClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFieldsAndSourceFilter(Query query, Class<?> domainClass) {
|
||||
|
||||
ElasticsearchPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(domainClass);
|
||||
|
||||
if (persistentEntity != null) {
|
||||
List<String> fields = query.getFields();
|
||||
|
||||
if (!fields.isEmpty()) {
|
||||
query.setFields(updateFieldNames(fields, persistentEntity));
|
||||
}
|
||||
|
||||
SourceFilter sourceFilter = query.getSourceFilter();
|
||||
|
||||
if (sourceFilter != null) {
|
||||
|
||||
String[] includes = null;
|
||||
String[] excludes = null;
|
||||
|
||||
if (sourceFilter.getIncludes() != null) {
|
||||
includes = updateFieldNames(Arrays.asList(sourceFilter.getIncludes()), persistentEntity)
|
||||
.toArray(new String[] {});
|
||||
}
|
||||
|
||||
if (sourceFilter.getExcludes() != null) {
|
||||
excludes = updateFieldNames(Arrays.asList(sourceFilter.getExcludes()), persistentEntity)
|
||||
.toArray(new String[] {});
|
||||
}
|
||||
|
||||
query.addSourceFilter(new FetchSourceFilter(includes, excludes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> updateFieldNames(List<String> fields, ElasticsearchPersistentEntity<?> persistentEntity) {
|
||||
return fields.stream().map(fieldName -> {
|
||||
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getPersistentProperty(fieldName);
|
||||
return persistentProperty != null ? persistentProperty.getFieldName() : fieldName;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void updateCriteriaQuery(CriteriaQuery criteriaQuery, Class<?> domainClass) {
|
||||
|
||||
Assert.notNull(criteriaQuery, "criteriaQuery must not be null");
|
||||
Assert.notNull(domainClass, "domainClass must not be null");
|
||||
|
||||
ElasticsearchPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(domainClass);
|
||||
|
||||
@@ -1020,21 +1101,60 @@ public class MappingElasticsearchConverter
|
||||
}
|
||||
|
||||
private void updateCriteria(Criteria criteria, ElasticsearchPersistentEntity<?> persistentEntity) {
|
||||
|
||||
Field field = criteria.getField();
|
||||
|
||||
if (field == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String name = field.getName();
|
||||
ElasticsearchPersistentProperty property = persistentEntity.getPersistentProperty(name);
|
||||
String[] fieldNames = field.getName().split("\\.");
|
||||
|
||||
if (property != null && property.getName().equals(name)) {
|
||||
field.setName(property.getFieldName());
|
||||
ElasticsearchPersistentEntity<?> currentEntity = persistentEntity;
|
||||
ElasticsearchPersistentProperty persistentProperty = null;
|
||||
int propertyCount = 0;
|
||||
boolean isNested = false;
|
||||
|
||||
if (property.hasPropertyConverter()) {
|
||||
for (int i = 0; i < fieldNames.length; i++) {
|
||||
persistentProperty = currentEntity.getPersistentProperty(fieldNames[i]);
|
||||
|
||||
if (persistentProperty != null) {
|
||||
propertyCount++;
|
||||
fieldNames[i] = persistentProperty.getFieldName();
|
||||
|
||||
org.springframework.data.elasticsearch.annotations.Field fieldAnnotation = persistentProperty
|
||||
.findAnnotation(org.springframework.data.elasticsearch.annotations.Field.class);
|
||||
|
||||
if (fieldAnnotation != null && fieldAnnotation.type() == FieldType.Nested) {
|
||||
isNested = true;
|
||||
}
|
||||
|
||||
try {
|
||||
currentEntity = mappingContext.getPersistentEntity(persistentProperty.getActualType());
|
||||
} catch (Exception e) {
|
||||
// using system types like UUIDs will lead to java.lang.reflect.InaccessibleObjectException in JDK 16
|
||||
// so if we cannot get an entity here, bail out.
|
||||
currentEntity = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentEntity == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
field.setName(String.join(".", fieldNames));
|
||||
|
||||
if (propertyCount > 1 && isNested) {
|
||||
List<String> propertyNames = Arrays.asList(fieldNames);
|
||||
field.setPath(String.join(".", propertyNames.subList(0, propertyCount - 1)));
|
||||
}
|
||||
|
||||
if (persistentProperty != null) {
|
||||
|
||||
if (persistentProperty.hasPropertyConverter()) {
|
||||
ElasticsearchPersistentPropertyConverter propertyConverter = Objects
|
||||
.requireNonNull(property.getPropertyConverter());
|
||||
.requireNonNull(persistentProperty.getPropertyConverter());
|
||||
criteria.getQueryCriteriaEntries().forEach(criteriaEntry -> {
|
||||
Object value = criteriaEntry.getValue();
|
||||
if (value.getClass().isArray()) {
|
||||
@@ -1048,7 +1168,7 @@ public class MappingElasticsearchConverter
|
||||
});
|
||||
}
|
||||
|
||||
org.springframework.data.elasticsearch.annotations.Field fieldAnnotation = property
|
||||
org.springframework.data.elasticsearch.annotations.Field fieldAnnotation = persistentProperty
|
||||
.findAnnotation(org.springframework.data.elasticsearch.annotations.Field.class);
|
||||
|
||||
if (fieldAnnotation != null) {
|
||||
@@ -1056,6 +1176,7 @@ public class MappingElasticsearchConverter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
static class MapValueAccessor {
|
||||
@@ -1149,7 +1270,6 @@ public class MappingElasticsearchConverter
|
||||
this.evaluator = evaluator;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T getPropertyValue(ElasticsearchPersistentProperty property) {
|
||||
|
||||
|
||||
@@ -25,11 +25,12 @@ import java.util.function.LongSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.convert.ConversionException;
|
||||
import org.springframework.data.elasticsearch.support.StringObjectMap;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A representation of a Elasticsearch document as extended {@link Map} with {@link String} keys. All iterators preserve
|
||||
* A representation of a Elasticsearch document as extended {@link StringObjectMap Map}. All iterators preserve
|
||||
* original insertion order.
|
||||
* <p>
|
||||
* Document does not allow {@code null} keys. It allows {@literal null} values.
|
||||
@@ -42,7 +43,7 @@ import org.springframework.util.Assert;
|
||||
* @author Roman Puchkovskiy
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface Document extends Map<String, Object> {
|
||||
public interface Document extends StringObjectMap<Document> {
|
||||
|
||||
/**
|
||||
* Create a new mutable {@link Document}.
|
||||
@@ -80,25 +81,19 @@ public interface Document extends Map<String, Object> {
|
||||
|
||||
Assert.notNull(json, "JSON must not be null");
|
||||
|
||||
return new MapDocument().fromJson(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Document fromJson(String json) {
|
||||
Assert.notNull(json, "JSON must not be null");
|
||||
|
||||
clear();
|
||||
try {
|
||||
return new MapDocument(MapDocument.OBJECT_MAPPER.readerFor(Map.class).readValue(json));
|
||||
putAll(MapDocument.OBJECT_MAPPER.readerFor(Map.class).readValue(json));
|
||||
} catch (IOException e) {
|
||||
throw new ConversionException("Cannot parse JSON", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link #put(Object, Object)} the {@code key}/{@code value} tuple and return {@code this} {@link Document}.
|
||||
*
|
||||
* @param key key with which the specified value is to be associated. must not be {@literal null}.
|
||||
* @param value value to be associated with the specified key.
|
||||
* @return {@code this} {@link Document}.
|
||||
*/
|
||||
default Document append(String key, Object value) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
|
||||
put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -122,7 +117,7 @@ public interface Document extends Map<String, Object> {
|
||||
|
||||
/**
|
||||
* Sets the index name for this document
|
||||
*
|
||||
*
|
||||
* @param index index name
|
||||
* <p>
|
||||
* The default implementation throws {@link UnsupportedOperationException}.
|
||||
@@ -251,212 +246,6 @@ public interface Document extends Map<String, Object> {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified {@code key} is mapped, or {@literal null} if this document contains no
|
||||
* mapping for the key. The value is casted within the method which makes it useful for calling code as it does not
|
||||
* require casting on the calling side. If the value type is not assignable to {@code type}, then this method throws
|
||||
* {@link ClassCastException}.
|
||||
*
|
||||
* @param key the key whose associated value is to be returned
|
||||
* @param type the expected return value type.
|
||||
* @param <T> expected return type.
|
||||
* @return the value to which the specified key is mapped, or {@literal null} if this document contains no mapping for
|
||||
* the key.
|
||||
* @throws ClassCastException if the value of the given key is not of {@code type T}.
|
||||
*/
|
||||
@Nullable
|
||||
default <T> T get(Object key, Class<T> type) {
|
||||
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
|
||||
return type.cast(get(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified {@code key} is mapped, or {@literal null} if this document contains no
|
||||
* mapping for the key. If the value type is not a {@link Boolean}, then this method throws
|
||||
* {@link ClassCastException}.
|
||||
*
|
||||
* @param key the key whose associated value is to be returned
|
||||
* @return the value to which the specified key is mapped, or {@literal null} if this document contains no mapping for
|
||||
* the key.
|
||||
* @throws ClassCastException if the value of the given key is not a {@link Boolean}.
|
||||
*/
|
||||
@Nullable
|
||||
default Boolean getBoolean(String key) {
|
||||
return get(key, Boolean.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified {@code key} is mapped or {@code defaultValue} if this document contains no
|
||||
* mapping for the key. If the value type is not a {@link Boolean}, then this method throws
|
||||
* {@link ClassCastException}.
|
||||
*
|
||||
* @param key the key whose associated value is to be returned
|
||||
* @return the value to which the specified key is mapped or {@code defaultValue} if this document contains no mapping
|
||||
* for the key.
|
||||
* @throws ClassCastException if the value of the given key is not a {@link Boolean}.
|
||||
*/
|
||||
default boolean getBooleanOrDefault(String key, boolean defaultValue) {
|
||||
return getBooleanOrDefault(key, () -> defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified {@code key} is mapped or the value from {@code defaultValue} if this
|
||||
* document contains no mapping for the key. If the value type is not a {@link Boolean}, then this method throws
|
||||
* {@link ClassCastException}.
|
||||
*
|
||||
* @param key the key whose associated value is to be returned
|
||||
* @return the value to which the specified key is mapped or the value from {@code defaultValue} if this document
|
||||
* contains no mapping for the key.
|
||||
* @throws ClassCastException if the value of the given key is not a {@link Boolean}.
|
||||
* @see BooleanSupplier
|
||||
*/
|
||||
default boolean getBooleanOrDefault(String key, BooleanSupplier defaultValue) {
|
||||
|
||||
Boolean value = getBoolean(key);
|
||||
|
||||
return value == null ? defaultValue.getAsBoolean() : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified {@code key} is mapped, or {@literal null} if this document contains no
|
||||
* mapping for the key. If the value type is not a {@link Integer}, then this method throws
|
||||
* {@link ClassCastException}.
|
||||
*
|
||||
* @param key the key whose associated value is to be returned
|
||||
* @return the value to which the specified key is mapped, or {@literal null} if this document contains no mapping for
|
||||
* the key.
|
||||
* @throws ClassCastException if the value of the given key is not a {@link Integer}.
|
||||
*/
|
||||
@Nullable
|
||||
default Integer getInt(String key) {
|
||||
return get(key, Integer.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified {@code key} is mapped or {@code defaultValue} if this document contains no
|
||||
* mapping for the key. If the value type is not a {@link Integer}, then this method throws
|
||||
* {@link ClassCastException}.
|
||||
*
|
||||
* @param key the key whose associated value is to be returned
|
||||
* @return the value to which the specified key is mapped or {@code defaultValue} if this document contains no mapping
|
||||
* for the key.
|
||||
* @throws ClassCastException if the value of the given key is not a {@link Integer}.
|
||||
*/
|
||||
default int getIntOrDefault(String key, int defaultValue) {
|
||||
return getIntOrDefault(key, () -> defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified {@code key} is mapped or the value from {@code defaultValue} if this
|
||||
* document contains no mapping for the key. If the value type is not a {@link Integer}, then this method throws
|
||||
* {@link ClassCastException}.
|
||||
*
|
||||
* @param key the key whose associated value is to be returned
|
||||
* @return the value to which the specified key is mapped or the value from {@code defaultValue} if this document
|
||||
* contains no mapping for the key.
|
||||
* @throws ClassCastException if the value of the given key is not a {@link Integer}.
|
||||
* @see IntSupplier
|
||||
*/
|
||||
default int getIntOrDefault(String key, IntSupplier defaultValue) {
|
||||
|
||||
Integer value = getInt(key);
|
||||
|
||||
return value == null ? defaultValue.getAsInt() : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified {@code key} is mapped, or {@literal null} if this document contains no
|
||||
* mapping for the key. If the value type is not a {@link Long}, then this method throws {@link ClassCastException}.
|
||||
*
|
||||
* @param key the key whose associated value is to be returned
|
||||
* @return the value to which the specified key is mapped, or {@literal null} if this document contains no mapping for
|
||||
* the key.
|
||||
* @throws ClassCastException if the value of the given key is not a {@link Long}.
|
||||
*/
|
||||
@Nullable
|
||||
default Long getLong(String key) {
|
||||
return get(key, Long.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified {@code key} is mapped or {@code defaultValue} if this document contains no
|
||||
* mapping for the key. If the value type is not a {@link Long}, then this method throws {@link ClassCastException}.
|
||||
*
|
||||
* @param key the key whose associated value is to be returned
|
||||
* @return the value to which the specified key is mapped or {@code defaultValue} if this document contains no mapping
|
||||
* for the key.
|
||||
* @throws ClassCastException if the value of the given key is not a {@link Long}.
|
||||
*/
|
||||
default long getLongOrDefault(String key, long defaultValue) {
|
||||
return getLongOrDefault(key, () -> defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified {@code key} is mapped or the value from {@code defaultValue} if this
|
||||
* document contains no mapping for the key. If the value type is not a {@link Long}, then this method throws
|
||||
* {@link ClassCastException}.
|
||||
*
|
||||
* @param key the key whose associated value is to be returned
|
||||
* @return the value to which the specified key is mapped or the value from {@code defaultValue} if this document
|
||||
* contains no mapping for the key.
|
||||
* @throws ClassCastException if the value of the given key is not a {@link Long}.
|
||||
* @see LongSupplier
|
||||
*/
|
||||
default long getLongOrDefault(String key, LongSupplier defaultValue) {
|
||||
|
||||
Long value = getLong(key);
|
||||
|
||||
return value == null ? defaultValue.getAsLong() : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified {@code key} is mapped, or {@literal null} if this document contains no
|
||||
* mapping for the key. If the value type is not a {@link String}, then this method throws {@link ClassCastException}.
|
||||
*
|
||||
* @param key the key whose associated value is to be returned
|
||||
* @return the value to which the specified key is mapped, or {@literal null} if this document contains no mapping for
|
||||
* the key.
|
||||
* @throws ClassCastException if the value of the given key is not a {@link String}.
|
||||
*/
|
||||
@Nullable
|
||||
default String getString(String key) {
|
||||
return get(key, String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified {@code key} is mapped or {@code defaultValue} if this document contains no
|
||||
* mapping for the key. If the value type is not a {@link String}, then this method throws {@link ClassCastException}.
|
||||
*
|
||||
* @param key the key whose associated value is to be returned
|
||||
* @return the value to which the specified key is mapped or {@code defaultValue} if this document contains no mapping
|
||||
* for the key.
|
||||
* @throws ClassCastException if the value of the given key is not a {@link String}.
|
||||
*/
|
||||
default String getStringOrDefault(String key, String defaultValue) {
|
||||
return getStringOrDefault(key, () -> defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified {@code key} is mapped or the value from {@code defaultValue} if this
|
||||
* document contains no mapping for the key. If the value type is not a {@link String}, then this method throws
|
||||
* {@link ClassCastException}.
|
||||
*
|
||||
* @param key the key whose associated value is to be returned
|
||||
* @return the value to which the specified key is mapped or the value from {@code defaultValue} if this document
|
||||
* contains no mapping for the key.
|
||||
* @throws ClassCastException if the value of the given key is not a {@link String}.
|
||||
* @see Supplier
|
||||
*/
|
||||
default String getStringOrDefault(String key, Supplier<String> defaultValue) {
|
||||
|
||||
String value = getString(key);
|
||||
|
||||
return value == null ? defaultValue.get() : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method allows the application of a function to {@code this} {@link Document}. The function should expect a
|
||||
* single {@link Document} argument and produce an {@code R} result.
|
||||
@@ -474,13 +263,4 @@ public interface Document extends Map<String, Object> {
|
||||
|
||||
return transformer.apply(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render this {@link Document} to JSON. Auxiliary values such as Id and version are not considered within the JSON
|
||||
* representation.
|
||||
*
|
||||
* @return a JSON representation of this document.
|
||||
*/
|
||||
String toJson();
|
||||
|
||||
}
|
||||
|
||||
+39
-8
@@ -32,6 +32,7 @@ import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.action.get.MultiGetItemResponse;
|
||||
import org.elasticsearch.action.get.MultiGetResponse;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.document.DocumentField;
|
||||
@@ -39,6 +40,8 @@ import org.elasticsearch.common.text.Text;
|
||||
import org.elasticsearch.index.get.GetResult;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.search.SearchHits;
|
||||
import org.springframework.data.elasticsearch.core.MultiGetItem;
|
||||
import org.springframework.data.elasticsearch.core.ResponseConverter;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -57,6 +60,7 @@ import com.fasterxml.jackson.core.JsonGenerator;
|
||||
* @author Mark Paluch
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Roman Puchkovskiy
|
||||
* @author Matt Gilene
|
||||
* @since 4.0
|
||||
*/
|
||||
public class DocumentAdapters {
|
||||
@@ -126,21 +130,32 @@ public class DocumentAdapters {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a List of {@link Document}s from {@link MultiGetResponse}.
|
||||
*
|
||||
* Creates a List of {@link MultiGetItem<Document>}s from {@link MultiGetResponse}.
|
||||
*
|
||||
* @param source the source {@link MultiGetResponse}, not {@literal null}.
|
||||
* @return a list of Documents, contains null values for not found Documents.
|
||||
*/
|
||||
public static List<Document> from(MultiGetResponse source) {
|
||||
public static List<MultiGetItem<Document>> from(MultiGetResponse source) {
|
||||
|
||||
Assert.notNull(source, "MultiGetResponse must not be null");
|
||||
|
||||
// noinspection ReturnOfNull
|
||||
return Arrays.stream(source.getResponses()) //
|
||||
.map(itemResponse -> itemResponse.isFailed() ? null : DocumentAdapters.from(itemResponse.getResponse())) //
|
||||
.map(DocumentAdapters::from) //
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link MultiGetItem<Document>} from a {@link MultiGetItemResponse}.
|
||||
*
|
||||
* @param itemResponse the response, must not be {@literal null}
|
||||
* @return the MultiGetItem
|
||||
*/
|
||||
public static MultiGetItem<Document> from(MultiGetItemResponse itemResponse) {
|
||||
|
||||
MultiGetItem.Failure failure = ResponseConverter.getFailure(itemResponse);
|
||||
return MultiGetItem.of(itemResponse.isFailed() ? null : DocumentAdapters.from(itemResponse.getResponse()), failure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link SearchDocument} from {@link SearchHit}.
|
||||
* <p>
|
||||
@@ -167,6 +182,7 @@ public class DocumentAdapters {
|
||||
|
||||
NestedMetaData nestedMetaData = from(source.getNestedIdentity());
|
||||
Explanation explanation = from(source.getExplanation());
|
||||
List<String> matchedQueries = from(source.getMatchedQueries());
|
||||
|
||||
BytesReference sourceRef = source.getSourceRef();
|
||||
|
||||
@@ -174,7 +190,7 @@ public class DocumentAdapters {
|
||||
return new SearchDocumentAdapter(
|
||||
source.getScore(), source.getSortValues(), source.getFields(), highlightFields, fromDocumentFields(source,
|
||||
source.getIndex(), source.getId(), source.getVersion(), source.getSeqNo(), source.getPrimaryTerm()),
|
||||
innerHits, nestedMetaData, explanation);
|
||||
innerHits, nestedMetaData, explanation, matchedQueries);
|
||||
}
|
||||
|
||||
Document document = Document.from(source.getSourceAsMap());
|
||||
@@ -188,7 +204,7 @@ public class DocumentAdapters {
|
||||
document.setPrimaryTerm(source.getPrimaryTerm());
|
||||
|
||||
return new SearchDocumentAdapter(source.getScore(), source.getSortValues(), source.getFields(), highlightFields,
|
||||
document, innerHits, nestedMetaData, explanation);
|
||||
document, innerHits, nestedMetaData, explanation, matchedQueries);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -217,6 +233,11 @@ public class DocumentAdapters {
|
||||
return NestedMetaData.of(nestedIdentity.getField().string(), nestedIdentity.getOffset(), child);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static List<String> from(@Nullable String[] matchedQueries) {
|
||||
return matchedQueries == null ? null : Arrays.asList(matchedQueries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an unmodifiable {@link Document} from {@link Iterable} of {@link DocumentField}s.
|
||||
*
|
||||
@@ -437,6 +458,7 @@ public class DocumentAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + '@' + this.id + '#' + this.version + ' ' + toJson();
|
||||
@@ -470,10 +492,12 @@ public class DocumentAdapters {
|
||||
private final Map<String, SearchDocumentResponse> innerHits = new HashMap<>();
|
||||
@Nullable private final NestedMetaData nestedMetaData;
|
||||
@Nullable private final Explanation explanation;
|
||||
@Nullable private final List<String> matchedQueries;
|
||||
|
||||
SearchDocumentAdapter(float score, Object[] sortValues, Map<String, DocumentField> fields,
|
||||
Map<String, List<String>> highlightFields, Document delegate, Map<String, SearchDocumentResponse> innerHits,
|
||||
@Nullable NestedMetaData nestedMetaData, @Nullable Explanation explanation) {
|
||||
@Nullable NestedMetaData nestedMetaData, @Nullable Explanation explanation,
|
||||
@Nullable List<String> matchedQueries) {
|
||||
|
||||
this.score = score;
|
||||
this.sortValues = sortValues;
|
||||
@@ -483,6 +507,7 @@ public class DocumentAdapters {
|
||||
this.innerHits.putAll(innerHits);
|
||||
this.nestedMetaData = nestedMetaData;
|
||||
this.explanation = explanation;
|
||||
this.matchedQueries = matchedQueries;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -665,6 +690,12 @@ public class DocumentAdapters {
|
||||
return explanation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public List<String> getMatchedQueries() {
|
||||
return matchedQueries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
|
||||
@@ -21,6 +21,8 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.springframework.data.elasticsearch.support.DefaultStringObjectMap;
|
||||
import org.springframework.data.elasticsearch.support.StringObjectMap;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
@@ -38,7 +40,7 @@ class MapDocument implements Document {
|
||||
|
||||
static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
private final LinkedHashMap<String, Object> documentAsMap;
|
||||
private final DefaultStringObjectMap<?> documentAsMap;
|
||||
|
||||
private @Nullable String index;
|
||||
private @Nullable String id;
|
||||
@@ -50,8 +52,8 @@ class MapDocument implements Document {
|
||||
this(new LinkedHashMap<>());
|
||||
}
|
||||
|
||||
MapDocument(Map<String, ? extends Object> documentAsMap) {
|
||||
this.documentAsMap = new LinkedHashMap<>(documentAsMap);
|
||||
MapDocument(Map<String, ?> documentAsMap) {
|
||||
this.documentAsMap = new DefaultStringObjectMap<>(documentAsMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.lang.Nullable;
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Matt Gilene
|
||||
* @since 4.0
|
||||
* @see Document
|
||||
*/
|
||||
@@ -105,4 +106,10 @@ public interface SearchDocument extends Document {
|
||||
*/
|
||||
@Nullable
|
||||
Explanation getExplanation();
|
||||
|
||||
/**
|
||||
* @return the matched queries for the SearchHit.
|
||||
*/
|
||||
@Nullable
|
||||
List<String> getMatchedQueries();
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.springframework.data.elasticsearch.core.convert.GeoConverters;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
|
||||
/**
|
||||
* Interface definition for structures defined in <a href="https://geojson.org/>GeoJSON</a> format. copied from Spring
|
||||
* Interface definition for structures defined in <a href="https://geojson.org/">GeoJSON</a> format. copied from Spring
|
||||
* Data Mongodb
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
|
||||
+31
-9
@@ -81,6 +81,8 @@ public class MappingBuilder {
|
||||
private static final String COMPLETION_MAX_INPUT_LENGTH = "max_input_length";
|
||||
private static final String COMPLETION_CONTEXTS = "contexts";
|
||||
|
||||
private static final String TYPEHINT_PROPERTY = "_class";
|
||||
|
||||
private static final String TYPE_DYNAMIC = "dynamic";
|
||||
private static final String TYPE_VALUE_KEYWORD = "keyword";
|
||||
private static final String TYPE_VALUE_GEO_POINT = "geo_point";
|
||||
@@ -131,6 +133,14 @@ public class MappingBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private void writeTypeHintMapping(XContentBuilder builder) throws IOException {
|
||||
builder.startObject(TYPEHINT_PROPERTY) //
|
||||
.field(FIELD_PARAM_TYPE, TYPE_VALUE_KEYWORD) //
|
||||
.field(FIELD_PARAM_INDEX, false) //
|
||||
.field(FIELD_PARAM_DOC_VALUES, false) //
|
||||
.endObject();
|
||||
}
|
||||
|
||||
private void mapEntity(XContentBuilder builder, @Nullable ElasticsearchPersistentEntity<?> entity,
|
||||
boolean isRootObject, String nestedObjectFieldName, boolean nestedOrObjectField, FieldType fieldType,
|
||||
@Nullable Field parentFieldAnnotation, @Nullable DynamicMapping dynamicMapping) throws IOException {
|
||||
@@ -146,10 +156,9 @@ public class MappingBuilder {
|
||||
boolean writeNestedProperties = !isRootObject && (isAnyPropertyAnnotatedWithField(entity) || nestedOrObjectField);
|
||||
if (writeNestedProperties) {
|
||||
|
||||
String type = nestedOrObjectField ? fieldType.toString().toLowerCase()
|
||||
: FieldType.Object.toString().toLowerCase();
|
||||
builder.startObject(nestedObjectFieldName).field(FIELD_PARAM_TYPE, type);
|
||||
String type = nestedOrObjectField ? fieldType.getMappedName() : FieldType.Object.getMappedName();
|
||||
|
||||
builder.startObject(nestedObjectFieldName).field(FIELD_PARAM_TYPE, type);
|
||||
if (nestedOrObjectField && FieldType.Nested == fieldType && parentFieldAnnotation != null
|
||||
&& parentFieldAnnotation.includeInParent()) {
|
||||
builder.field("include_in_parent", true);
|
||||
@@ -162,6 +171,8 @@ public class MappingBuilder {
|
||||
|
||||
builder.startObject(FIELD_PROPERTIES);
|
||||
|
||||
writeTypeHintMapping(builder);
|
||||
|
||||
if (entity != null) {
|
||||
entity.doWithProperties((PropertyHandler<ElasticsearchPersistentProperty>) property -> {
|
||||
try {
|
||||
@@ -233,6 +244,7 @@ public class MappingBuilder {
|
||||
Field fieldAnnotation = property.findAnnotation(Field.class);
|
||||
boolean isCompletionProperty = property.isCompletionProperty();
|
||||
boolean isNestedOrObjectProperty = isNestedOrObjectProperty(property);
|
||||
DynamicMapping dynamicMapping = property.findAnnotation(DynamicMapping.class);
|
||||
|
||||
if (!isCompletionProperty && property.isEntity() && hasRelevantAnnotation(property)) {
|
||||
|
||||
@@ -247,7 +259,7 @@ public class MappingBuilder {
|
||||
: null;
|
||||
|
||||
mapEntity(builder, persistentEntity, false, property.getFieldName(), true, fieldAnnotation.type(),
|
||||
fieldAnnotation, property.findAnnotation(DynamicMapping.class));
|
||||
fieldAnnotation, dynamicMapping);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -262,9 +274,9 @@ public class MappingBuilder {
|
||||
if (isRootObject && fieldAnnotation != null && property.isIdProperty()) {
|
||||
applyDefaultIdFieldMapping(builder, property);
|
||||
} else if (multiField != null) {
|
||||
addMultiFieldMapping(builder, property, multiField, isNestedOrObjectProperty);
|
||||
addMultiFieldMapping(builder, property, multiField, isNestedOrObjectProperty, dynamicMapping);
|
||||
} else if (fieldAnnotation != null) {
|
||||
addSingleFieldMapping(builder, property, fieldAnnotation, isNestedOrObjectProperty);
|
||||
addSingleFieldMapping(builder, property, fieldAnnotation, isNestedOrObjectProperty, dynamicMapping);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,7 +363,7 @@ public class MappingBuilder {
|
||||
}
|
||||
|
||||
builder.startObject(property.getFieldName()) //
|
||||
.field(FIELD_PARAM_TYPE, field.type().name().toLowerCase()) //
|
||||
.field(FIELD_PARAM_TYPE, field.type().getMappedName()) //
|
||||
.field(MAPPING_ENABLED, false) //
|
||||
.endObject(); //
|
||||
} catch (Exception e) {
|
||||
@@ -365,7 +377,7 @@ public class MappingBuilder {
|
||||
* @throws IOException
|
||||
*/
|
||||
private void addSingleFieldMapping(XContentBuilder builder, ElasticsearchPersistentProperty property,
|
||||
Field annotation, boolean nestedOrObjectField) throws IOException {
|
||||
Field annotation, boolean nestedOrObjectField, @Nullable DynamicMapping dynamicMapping) throws IOException {
|
||||
|
||||
// build the property json, if empty skip it as this is no valid mapping
|
||||
XContentBuilder propertyBuilder = jsonBuilder().startObject();
|
||||
@@ -377,6 +389,11 @@ public class MappingBuilder {
|
||||
}
|
||||
|
||||
builder.startObject(property.getFieldName());
|
||||
|
||||
if (nestedOrObjectField && dynamicMapping != null) {
|
||||
builder.field(TYPE_DYNAMIC, dynamicMapping.value().getMappedName());
|
||||
}
|
||||
|
||||
addFieldMappingParameters(builder, annotation, nestedOrObjectField);
|
||||
builder.endObject();
|
||||
}
|
||||
@@ -417,10 +434,15 @@ public class MappingBuilder {
|
||||
* @throws IOException
|
||||
*/
|
||||
private void addMultiFieldMapping(XContentBuilder builder, ElasticsearchPersistentProperty property,
|
||||
MultiField annotation, boolean nestedOrObjectField) throws IOException {
|
||||
MultiField annotation, boolean nestedOrObjectField, @Nullable DynamicMapping dynamicMapping) throws IOException {
|
||||
|
||||
// main field
|
||||
builder.startObject(property.getFieldName());
|
||||
|
||||
if (nestedOrObjectField && dynamicMapping != null) {
|
||||
builder.field(TYPE_DYNAMIC, dynamicMapping.value().getMappedName());
|
||||
}
|
||||
|
||||
addFieldMappingParameters(builder, annotation.mainField(), nestedOrObjectField);
|
||||
|
||||
// inner fields
|
||||
|
||||
+47
-9
@@ -17,6 +17,9 @@ package org.springframework.data.elasticsearch.core.index;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
@@ -39,6 +42,9 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Aleksei Arsenev
|
||||
* @author Brian Kimmig
|
||||
* @author Morgan Lutz
|
||||
* @author Sascha Woo
|
||||
* @since 4.0
|
||||
*/
|
||||
public final class MappingParameters {
|
||||
@@ -65,6 +71,7 @@ public final class MappingParameters {
|
||||
static final String FIELD_PARAM_NULL_VALUE = "null_value";
|
||||
static final String FIELD_PARAM_POSITION_INCREMENT_GAP = "position_increment_gap";
|
||||
static final String FIELD_PARAM_POSITIVE_SCORE_IMPACT = "positive_score_impact";
|
||||
static final String FIELD_PARAM_DIMS = "dims";
|
||||
static final String FIELD_PARAM_SCALING_FACTOR = "scaling_factor";
|
||||
static final String FIELD_PARAM_SEARCH_ANALYZER = "search_analyzer";
|
||||
static final String FIELD_PARAM_STORE = "store";
|
||||
@@ -75,12 +82,12 @@ public final class MappingParameters {
|
||||
private final String analyzer;
|
||||
private final boolean coerce;
|
||||
@Nullable private final String[] copyTo;
|
||||
private final String datePattern;
|
||||
private final DateFormat[] dateFormats;
|
||||
private final String[] dateFormatPatterns;
|
||||
private final boolean docValues;
|
||||
private final boolean eagerGlobalOrdinals;
|
||||
private final boolean enabled;
|
||||
private final boolean fielddata;
|
||||
private final DateFormat format;
|
||||
@Nullable private final Integer ignoreAbove;
|
||||
private final boolean ignoreMalformed;
|
||||
private final boolean index;
|
||||
@@ -94,6 +101,7 @@ public final class MappingParameters {
|
||||
private final NullValueType nullValueType;
|
||||
private final Integer positionIncrementGap;
|
||||
private final boolean positiveScoreImpact;
|
||||
private final Integer dims;
|
||||
private final String searchAnalyzer;
|
||||
private final double scalingFactor;
|
||||
private final Similarity similarity;
|
||||
@@ -125,8 +133,8 @@ public final class MappingParameters {
|
||||
store = field.store();
|
||||
fielddata = field.fielddata();
|
||||
type = field.type();
|
||||
format = field.format();
|
||||
datePattern = field.pattern();
|
||||
dateFormats = field.format();
|
||||
dateFormatPatterns = field.pattern();
|
||||
analyzer = field.analyzer();
|
||||
searchAnalyzer = field.searchAnalyzer();
|
||||
normalizer = field.normalizer();
|
||||
@@ -153,6 +161,11 @@ public final class MappingParameters {
|
||||
|| (maxShingleSize >= 2 && maxShingleSize <= 4), //
|
||||
"maxShingleSize must be in inclusive range from 2 to 4 for field type search_as_you_type");
|
||||
positiveScoreImpact = field.positiveScoreImpact();
|
||||
dims = field.dims();
|
||||
if (type == FieldType.Dense_Vector) {
|
||||
Assert.isTrue(dims >= 1 && dims <= 2048,
|
||||
"Invalid required parameter! Dense_Vector value \"dims\" must be between 1 and 2048.");
|
||||
}
|
||||
Assert.isTrue(field.enabled() || type == FieldType.Object, "enabled false is only allowed for field type object");
|
||||
enabled = field.enabled();
|
||||
eagerGlobalOrdinals = field.eagerGlobalOrdinals();
|
||||
@@ -163,8 +176,8 @@ public final class MappingParameters {
|
||||
store = field.store();
|
||||
fielddata = field.fielddata();
|
||||
type = field.type();
|
||||
format = field.format();
|
||||
datePattern = field.pattern();
|
||||
dateFormats = field.format();
|
||||
dateFormatPatterns = field.pattern();
|
||||
analyzer = field.analyzer();
|
||||
searchAnalyzer = field.searchAnalyzer();
|
||||
normalizer = field.normalizer();
|
||||
@@ -191,6 +204,11 @@ public final class MappingParameters {
|
||||
|| (maxShingleSize >= 2 && maxShingleSize <= 4), //
|
||||
"maxShingleSize must be in inclusive range from 2 to 4 for field type search_as_you_type");
|
||||
positiveScoreImpact = field.positiveScoreImpact();
|
||||
dims = field.dims();
|
||||
if (type == FieldType.Dense_Vector) {
|
||||
Assert.isTrue(dims >= 1 && dims <= 2048,
|
||||
"Invalid required parameter! Dense_Vector value \"dims\" must be between 1 and 2048.");
|
||||
}
|
||||
enabled = true;
|
||||
eagerGlobalOrdinals = field.eagerGlobalOrdinals();
|
||||
}
|
||||
@@ -213,9 +231,25 @@ public final class MappingParameters {
|
||||
}
|
||||
|
||||
if (type != FieldType.Auto) {
|
||||
builder.field(FIELD_PARAM_TYPE, type.name().toLowerCase());
|
||||
if (type == FieldType.Date && format != DateFormat.none) {
|
||||
builder.field(FIELD_PARAM_FORMAT, format == DateFormat.custom ? datePattern : format.toString());
|
||||
builder.field(FIELD_PARAM_TYPE, type.getMappedName());
|
||||
|
||||
if (type == FieldType.Date) {
|
||||
List<String> formats = new ArrayList<>();
|
||||
|
||||
// built-in formats
|
||||
for (DateFormat dateFormat : dateFormats) {
|
||||
if (dateFormat == DateFormat.none || dateFormat == DateFormat.custom) {
|
||||
continue;
|
||||
}
|
||||
formats.add(dateFormat.toString());
|
||||
}
|
||||
|
||||
// custom date formats
|
||||
Collections.addAll(formats, dateFormatPatterns);
|
||||
|
||||
if (!formats.isEmpty()) {
|
||||
builder.field(FIELD_PARAM_FORMAT, String.join("||", formats));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,6 +357,10 @@ public final class MappingParameters {
|
||||
builder.field(FIELD_PARAM_POSITIVE_SCORE_IMPACT, positiveScoreImpact);
|
||||
}
|
||||
|
||||
if (type == FieldType.Dense_Vector) {
|
||||
builder.field(FIELD_PARAM_DIMS, dims);
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
builder.field(FIELD_PARAM_ENABLED, enabled);
|
||||
}
|
||||
|
||||
+8
-6
@@ -19,6 +19,8 @@ import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Request to create an index template. This is to create legacy templates (@see
|
||||
* https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates-v1.html)
|
||||
@@ -29,13 +31,13 @@ import org.springframework.util.Assert;
|
||||
public class PutTemplateRequest {
|
||||
private final String name;
|
||||
private final String[] indexPatterns;
|
||||
@Nullable final private Document settings;
|
||||
@Nullable final private Settings settings;
|
||||
@Nullable final private Document mappings;
|
||||
@Nullable final AliasActions aliasActions;
|
||||
private final int order;
|
||||
@Nullable final Integer version;
|
||||
|
||||
private PutTemplateRequest(String name, String[] indexPatterns, @Nullable Document settings,
|
||||
private PutTemplateRequest(String name, String[] indexPatterns, @Nullable Settings settings,
|
||||
@Nullable Document mappings, @Nullable AliasActions aliasActions, int order, @Nullable Integer version) {
|
||||
this.name = name;
|
||||
this.indexPatterns = indexPatterns;
|
||||
@@ -55,7 +57,7 @@ public class PutTemplateRequest {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Document getSettings() {
|
||||
public Settings getSettings() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
@@ -85,7 +87,7 @@ public class PutTemplateRequest {
|
||||
public static final class TemplateRequestBuilder {
|
||||
private final String name;
|
||||
private final String[] indexPatterns;
|
||||
@Nullable private Document settings;
|
||||
@Nullable private Settings settings;
|
||||
@Nullable private Document mappings;
|
||||
@Nullable AliasActions aliasActions;
|
||||
private int order = 0;
|
||||
@@ -100,8 +102,8 @@ public class PutTemplateRequest {
|
||||
this.indexPatterns = indexPatterns;
|
||||
}
|
||||
|
||||
public TemplateRequestBuilder withSettings(Document settings) {
|
||||
this.settings = settings;
|
||||
public TemplateRequestBuilder withSettings(Map<String, Object> settings) {
|
||||
this.settings = new Settings(settings);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2021 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.data.elasticsearch.support.DefaultStringObjectMap;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* class defining the settings for an index.
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.2
|
||||
*/
|
||||
public class Settings extends DefaultStringObjectMap<Settings> {
|
||||
|
||||
public Settings() {
|
||||
}
|
||||
|
||||
public Settings(Map<String, Object> map) {
|
||||
super(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Settings} object from the given JSON String
|
||||
* @param json must not be {@literal null}
|
||||
* @return Settings object
|
||||
*/
|
||||
public static Settings parse(String json) {
|
||||
return new Settings().fromJson(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Settings: " + toJson();
|
||||
}
|
||||
}
|
||||
@@ -27,13 +27,13 @@ import org.springframework.lang.Nullable;
|
||||
*/
|
||||
public class TemplateData {
|
||||
@Nullable private final String[] indexPatterns;
|
||||
@Nullable Document settings;
|
||||
@Nullable Settings settings;
|
||||
@Nullable Document mapping;
|
||||
@Nullable private final Map<String, AliasData> aliases;
|
||||
int order;
|
||||
@Nullable Integer version;
|
||||
|
||||
private TemplateData(@Nullable String[] indexPatterns, @Nullable Document settings, @Nullable Document mapping,
|
||||
private TemplateData(@Nullable String[] indexPatterns, @Nullable Settings settings, @Nullable Document mapping,
|
||||
@Nullable Map<String, AliasData> aliases, int order, @Nullable Integer version) {
|
||||
this.indexPatterns = indexPatterns;
|
||||
this.settings = settings;
|
||||
@@ -53,7 +53,7 @@ public class TemplateData {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Document getSettings() {
|
||||
public Settings getSettings() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public class TemplateData {
|
||||
}
|
||||
|
||||
public static final class TemplateDataBuilder {
|
||||
@Nullable Document settings;
|
||||
@Nullable Settings settings;
|
||||
@Nullable Document mapping;
|
||||
int order;
|
||||
@Nullable Integer version;
|
||||
@@ -91,8 +91,8 @@ public class TemplateData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public TemplateDataBuilder withSettings(Document settings) {
|
||||
this.settings = settings;
|
||||
public TemplateDataBuilder withSettings(Map<String, Object> settings) {
|
||||
this.settings = new Settings(settings);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,10 +15,14 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.join;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Subhobrata Dey
|
||||
* @author Sascha Woo
|
||||
* @since 4.1
|
||||
*/
|
||||
public class JoinField<ID> {
|
||||
@@ -35,6 +39,7 @@ public class JoinField<ID> {
|
||||
this(name, null);
|
||||
}
|
||||
|
||||
@PersistenceConstructor
|
||||
public JoinField(String name, @Nullable ID parent) {
|
||||
this.name = name;
|
||||
this.parent = parent;
|
||||
@@ -52,4 +57,21 @@ public class JoinField<ID> {
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof JoinField)) {
|
||||
return false;
|
||||
}
|
||||
JoinField other = (JoinField) obj;
|
||||
return Objects.equals(name, other.name) && Objects.equals(parent, other.parent);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -18,6 +18,7 @@ package org.springframework.data.elasticsearch.core.mapping;
|
||||
import org.elasticsearch.index.VersionType;
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.data.elasticsearch.core.index.Settings;
|
||||
import org.springframework.data.elasticsearch.core.join.JoinField;
|
||||
import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
@@ -148,14 +149,14 @@ public interface ElasticsearchPersistentEntity<T> extends PersistentEntity<T, El
|
||||
/**
|
||||
* returns the default settings for an index.
|
||||
*
|
||||
* @return settings as {@link Document}
|
||||
* @return settings
|
||||
* @since 4.1
|
||||
*/
|
||||
Document getDefaultSettings();
|
||||
Settings getDefaultSettings();
|
||||
|
||||
/**
|
||||
* Resolves the routing for a bean.
|
||||
*
|
||||
*
|
||||
* @param bean the bean to resolve the routing for
|
||||
* @return routing value, may be {@literal null}
|
||||
*/
|
||||
|
||||
+176
-38
@@ -19,16 +19,18 @@ import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.elasticsearch.common.collect.MapBuilder;
|
||||
import org.elasticsearch.index.VersionType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||
import org.springframework.data.elasticsearch.annotations.Parent;
|
||||
import org.springframework.data.elasticsearch.annotations.Routing;
|
||||
import org.springframework.data.elasticsearch.annotations.Setting;
|
||||
import org.springframework.data.elasticsearch.core.document.Document;
|
||||
import org.springframework.data.elasticsearch.core.index.Settings;
|
||||
import org.springframework.data.elasticsearch.core.join.JoinField;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
@@ -66,16 +68,11 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
||||
private static final SpelExpressionParser PARSER = new SpelExpressionParser();
|
||||
|
||||
private @Nullable String indexName;
|
||||
private boolean useServerConfiguration;
|
||||
private short shards;
|
||||
private short replicas;
|
||||
private @Nullable String refreshInterval;
|
||||
private @Nullable String indexStoreType;
|
||||
private final Lazy<SettingsParameter> settingsParameter;
|
||||
@Deprecated private @Nullable String parentType;
|
||||
@Deprecated private @Nullable ElasticsearchPersistentProperty parentIdProperty;
|
||||
private @Nullable ElasticsearchPersistentProperty seqNoPrimaryTermProperty;
|
||||
private @Nullable ElasticsearchPersistentProperty joinFieldProperty;
|
||||
private @Nullable String settingPath;
|
||||
private @Nullable VersionType versionType;
|
||||
private boolean createIndexAndMapping;
|
||||
private final Map<String, ElasticsearchPersistentProperty> fieldNamePropertyCache = new ConcurrentHashMap<>();
|
||||
@@ -90,27 +87,20 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
||||
super(typeInformation);
|
||||
|
||||
Class<T> clazz = typeInformation.getType();
|
||||
|
||||
org.springframework.data.elasticsearch.annotations.Document document = AnnotatedElementUtils
|
||||
.findMergedAnnotation(clazz, org.springframework.data.elasticsearch.annotations.Document.class);
|
||||
|
||||
// need a Lazy here, because we need the persistent properties available
|
||||
this.settingsParameter = Lazy.of(() -> buildSettingsParameter(clazz));
|
||||
|
||||
if (document != null) {
|
||||
|
||||
Assert.hasText(document.indexName(),
|
||||
" Unknown indexName. Make sure the indexName is defined. e.g @Document(indexName=\"foo\")");
|
||||
this.indexName = document.indexName();
|
||||
this.useServerConfiguration = document.useServerConfiguration();
|
||||
this.shards = document.shards();
|
||||
this.replicas = document.replicas();
|
||||
this.refreshInterval = document.refreshInterval();
|
||||
this.indexStoreType = document.indexStoreType();
|
||||
this.versionType = document.versionType();
|
||||
this.createIndexAndMapping = document.createIndex();
|
||||
|
||||
Setting setting = AnnotatedElementUtils.getMergedAnnotation(clazz, Setting.class);
|
||||
|
||||
if (setting != null) {
|
||||
this.settingPath = setting.settingPath();
|
||||
}
|
||||
}
|
||||
|
||||
Routing routingAnnotation = AnnotatedElementUtils.findMergedAnnotation(clazz, Routing.class);
|
||||
@@ -135,28 +125,28 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
||||
@Nullable
|
||||
@Override
|
||||
public String getIndexStoreType() {
|
||||
return indexStoreType;
|
||||
return settingsParameter.get().indexStoreType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShards() {
|
||||
return shards;
|
||||
return settingsParameter.get().shards;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getReplicas() {
|
||||
return replicas;
|
||||
return settingsParameter.get().replicas;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseServerConfiguration() {
|
||||
return useServerConfiguration;
|
||||
return settingsParameter.get().useServerConfiguration;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getRefreshInterval() {
|
||||
return refreshInterval;
|
||||
return settingsParameter.get().refreshIntervall;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -179,11 +169,6 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
||||
return versionType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String settingPath() {
|
||||
return settingPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateIndexAndMapping() {
|
||||
return createIndexAndMapping;
|
||||
@@ -207,7 +192,10 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
||||
|
||||
Parent parentAnnotation = property.findAnnotation(Parent.class);
|
||||
this.parentIdProperty = property;
|
||||
this.parentType = parentAnnotation.type();
|
||||
|
||||
if (parentAnnotation != null) {
|
||||
this.parentType = parentAnnotation.type();
|
||||
}
|
||||
}
|
||||
|
||||
if (property.isSeqNoPrimaryTermProperty()) {
|
||||
@@ -407,17 +395,167 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
||||
|
||||
// endregion
|
||||
|
||||
// region index settings
|
||||
@Override
|
||||
public Document getDefaultSettings() {
|
||||
public String settingPath() {
|
||||
return settingsParameter.get().settingPath;
|
||||
}
|
||||
|
||||
if (isUseServerConfiguration()) {
|
||||
return Document.create();
|
||||
@Override
|
||||
public Settings getDefaultSettings() {
|
||||
return settingsParameter.get().toSettings(); //
|
||||
}
|
||||
|
||||
private SettingsParameter buildSettingsParameter(Class<?> clazz) {
|
||||
|
||||
SettingsParameter settingsParameter = new SettingsParameter();
|
||||
Document documentAnnotation = AnnotatedElementUtils.findMergedAnnotation(clazz, Document.class);
|
||||
Setting settingAnnotation = AnnotatedElementUtils.findMergedAnnotation(clazz, Setting.class);
|
||||
|
||||
if (documentAnnotation != null) {
|
||||
settingsParameter.useServerConfiguration = documentAnnotation.useServerConfiguration();
|
||||
settingsParameter.shards = documentAnnotation.shards();
|
||||
settingsParameter.replicas = documentAnnotation.replicas();
|
||||
settingsParameter.refreshIntervall = documentAnnotation.refreshInterval();
|
||||
settingsParameter.indexStoreType = documentAnnotation.indexStoreType();
|
||||
}
|
||||
|
||||
Map<String, String> map = new MapBuilder<String, String>()
|
||||
.put("index.number_of_shards", String.valueOf(getShards()))
|
||||
.put("index.number_of_replicas", String.valueOf(getReplicas()))
|
||||
.put("index.refresh_interval", getRefreshInterval()).put("index.store.type", getIndexStoreType()).map();
|
||||
return Document.from(map);
|
||||
if (settingAnnotation != null) {
|
||||
processSettingAnnotation(settingAnnotation, settingsParameter);
|
||||
}
|
||||
|
||||
return settingsParameter;
|
||||
}
|
||||
|
||||
private void processSettingAnnotation(Setting settingAnnotation, SettingsParameter settingsParameter) {
|
||||
settingsParameter.useServerConfiguration = settingAnnotation.useServerConfiguration();
|
||||
settingsParameter.settingPath = settingAnnotation.settingPath();
|
||||
settingsParameter.shards = settingAnnotation.shards();
|
||||
settingsParameter.replicas = settingAnnotation.replicas();
|
||||
settingsParameter.refreshIntervall = settingAnnotation.refreshInterval();
|
||||
settingsParameter.indexStoreType = settingAnnotation.indexStoreType();
|
||||
|
||||
String[] sortFields = settingAnnotation.sortFields();
|
||||
|
||||
if (sortFields.length > 0) {
|
||||
String[] fieldNames = new String[sortFields.length];
|
||||
int index = 0;
|
||||
for (String propertyName : sortFields) {
|
||||
ElasticsearchPersistentProperty property = getPersistentProperty(propertyName);
|
||||
|
||||
if (property == null) {
|
||||
throw new IllegalArgumentException("sortField property " + propertyName + " not found");
|
||||
}
|
||||
Field fieldAnnotation = property.getRequiredAnnotation(Field.class);
|
||||
|
||||
FieldType fieldType = fieldAnnotation.type();
|
||||
switch (fieldType) {
|
||||
case Boolean:
|
||||
case Long:
|
||||
case Integer:
|
||||
case Short:
|
||||
case Byte:
|
||||
case Float:
|
||||
case Half_Float:
|
||||
case Scaled_Float:
|
||||
case Date:
|
||||
case Date_Nanos:
|
||||
case Keyword:
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("field type " + fieldType + " not allowed for sortField");
|
||||
}
|
||||
|
||||
if (!fieldAnnotation.docValues()) {
|
||||
throw new IllegalArgumentException("doc_values must be set to true for sortField");
|
||||
}
|
||||
fieldNames[index++] = property.getFieldName();
|
||||
}
|
||||
settingsParameter.sortFields = fieldNames;
|
||||
|
||||
Setting.SortOrder[] sortOrders = settingAnnotation.sortOrders();
|
||||
if (sortOrders.length > 0) {
|
||||
|
||||
if (sortOrders.length != sortFields.length) {
|
||||
throw new IllegalArgumentException("@Settings parameter sortFields and sortOrders must have the same size");
|
||||
}
|
||||
settingsParameter.sortOrders = sortOrders;
|
||||
}
|
||||
|
||||
Setting.SortMode[] sortModes = settingAnnotation.sortModes();
|
||||
if (sortModes.length > 0) {
|
||||
|
||||
if (sortModes.length != sortFields.length) {
|
||||
throw new IllegalArgumentException("@Settings parameter sortFields and sortModes must have the same size");
|
||||
}
|
||||
settingsParameter.sortModes = sortModes;
|
||||
}
|
||||
|
||||
Setting.SortMissing[] sortMissingValues = settingAnnotation.sortMissingValues();
|
||||
if (sortMissingValues.length > 0) {
|
||||
|
||||
if (sortMissingValues.length != sortFields.length) {
|
||||
throw new IllegalArgumentException(
|
||||
"@Settings parameter sortFields and sortMissingValues must have the same size");
|
||||
}
|
||||
settingsParameter.sortMissingValues = sortMissingValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* internal class to collect settings values from the {@link Document} and {@link Setting} annotations-
|
||||
*/
|
||||
private static class SettingsParameter {
|
||||
boolean useServerConfiguration = false;
|
||||
@Nullable String settingPath;
|
||||
short shards;
|
||||
short replicas;
|
||||
@Nullable String refreshIntervall;
|
||||
@Nullable String indexStoreType;
|
||||
@Nullable private String[] sortFields;
|
||||
@Nullable private Setting.SortOrder[] sortOrders;
|
||||
@Nullable private Setting.SortMode[] sortModes;
|
||||
@Nullable private Setting.SortMissing[] sortMissingValues;
|
||||
|
||||
Settings toSettings() {
|
||||
|
||||
if (useServerConfiguration) {
|
||||
return new Settings();
|
||||
}
|
||||
|
||||
Settings settings = new Settings() //
|
||||
.append("index.number_of_shards", String.valueOf(shards))
|
||||
.append("index.number_of_replicas", String.valueOf(replicas));
|
||||
|
||||
if (refreshIntervall != null) {
|
||||
settings.append("index.refresh_interval", refreshIntervall);
|
||||
}
|
||||
|
||||
if (indexStoreType != null) {
|
||||
settings.append("index.store.type", indexStoreType);
|
||||
}
|
||||
|
||||
if (sortFields != null && sortFields.length > 0) {
|
||||
settings.append("index.sort.field", sortFields);
|
||||
|
||||
if (sortOrders != null && sortOrders.length > 0) {
|
||||
settings.append("index.sort.order", sortOrders);
|
||||
}
|
||||
|
||||
if (sortModes != null && sortModes.length > 0) {
|
||||
settings.append("index.sort.mode", sortModes);
|
||||
}
|
||||
|
||||
if (sortMissingValues != null && sortMissingValues.length > 0) {
|
||||
settings.append("index.sort.missing", sortMissingValues);
|
||||
}
|
||||
}
|
||||
|
||||
return settings; //
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
||||
+47
-33
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.elasticsearch.core.mapping;
|
||||
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -30,6 +31,7 @@ import org.springframework.data.elasticsearch.annotations.GeoShapeField;
|
||||
import org.springframework.data.elasticsearch.annotations.MultiField;
|
||||
import org.springframework.data.elasticsearch.annotations.Parent;
|
||||
import org.springframework.data.elasticsearch.core.completion.Completion;
|
||||
import org.springframework.data.elasticsearch.core.convert.ConversionException;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchDateConverter;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoJson;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
||||
@@ -154,51 +156,73 @@ public class SimpleElasticsearchPersistentProperty extends
|
||||
|
||||
if (field != null && (field.type() == FieldType.Date || field.type() == FieldType.Date_Nanos)
|
||||
&& (isTemporalAccessor || isDate)) {
|
||||
DateFormat dateFormat = field.format();
|
||||
|
||||
DateFormat[] dateFormats = field.format();
|
||||
String[] dateFormatPatterns = field.pattern();
|
||||
|
||||
String property = getOwner().getType().getSimpleName() + "." + getName();
|
||||
|
||||
if (dateFormat == DateFormat.none) {
|
||||
if (dateFormats.length == 0 && dateFormatPatterns.length == 0) {
|
||||
LOGGER.warn(
|
||||
String.format("No DateFormat defined for property %s. Make sure you have a Converter registered for %s",
|
||||
property, actualType.getSimpleName()));
|
||||
"Property '{}' has @Field type '{}' but has no built-in format or custom date pattern defined. Make sure you have a converter registered for type {}.",
|
||||
property, field.type().name(), actualType.getSimpleName());
|
||||
return;
|
||||
}
|
||||
|
||||
ElasticsearchDateConverter converter = null;
|
||||
|
||||
if (dateFormat == DateFormat.custom) {
|
||||
String pattern = field.pattern();
|
||||
|
||||
if (!StringUtils.hasLength(pattern)) {
|
||||
throw new MappingException(
|
||||
String.format("Property %s is annotated with FieldType.%s and a custom format but has no pattern defined",
|
||||
property, field.type().name()));
|
||||
}
|
||||
|
||||
converter = ElasticsearchDateConverter.of(pattern);
|
||||
} else {
|
||||
List<ElasticsearchDateConverter> converters = new ArrayList<>();
|
||||
|
||||
// register converters for built-in formats
|
||||
for (DateFormat dateFormat : dateFormats) {
|
||||
switch (dateFormat) {
|
||||
case none:
|
||||
case custom:
|
||||
break;
|
||||
case weekyear:
|
||||
case weekyear_week:
|
||||
case weekyear_week_day:
|
||||
LOGGER.warn("no Converter available for " + actualType.getName() + " and date format " + dateFormat.name()
|
||||
+ ". Use a custom converter instead");
|
||||
LOGGER.warn("No default converter available for '{}' and date format '{}'. Use a custom converter instead.",
|
||||
actualType.getName(), dateFormat.name());
|
||||
break;
|
||||
default:
|
||||
converter = ElasticsearchDateConverter.of(dateFormat);
|
||||
converters.add(ElasticsearchDateConverter.of(dateFormat));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (converter != null) {
|
||||
ElasticsearchDateConverter finalConverter = converter;
|
||||
// register converters for custom formats
|
||||
for (String dateFormatPattern : dateFormatPatterns) {
|
||||
if (!StringUtils.hasText(dateFormatPattern)) {
|
||||
throw new MappingException(String.format("Date pattern of property '%s' must not be empty", property));
|
||||
}
|
||||
converters.add(ElasticsearchDateConverter.of(dateFormatPattern));
|
||||
}
|
||||
|
||||
if (!converters.isEmpty()) {
|
||||
propertyConverter = new ElasticsearchPersistentPropertyConverter() {
|
||||
final ElasticsearchDateConverter dateConverter = finalConverter;
|
||||
final List<ElasticsearchDateConverter> dateConverters = converters;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object read(String s) {
|
||||
for (ElasticsearchDateConverter dateConverter : dateConverters) {
|
||||
try {
|
||||
if (isTemporalAccessor) {
|
||||
return dateConverter.parse(s, (Class<? extends TemporalAccessor>) actualType);
|
||||
} else { // must be date
|
||||
return dateConverter.parse(s);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.trace(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
throw new ConversionException(String
|
||||
.format("Unable to parse date value '%s' of property '%s' with configured converters", s, property));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String write(Object property) {
|
||||
ElasticsearchDateConverter dateConverter = dateConverters.get(0);
|
||||
if (isTemporalAccessor && TemporalAccessor.class.isAssignableFrom(property.getClass())) {
|
||||
return dateConverter.format((TemporalAccessor) property);
|
||||
} else if (isDate && Date.class.isAssignableFrom(property.getClass())) {
|
||||
@@ -207,16 +231,6 @@ public class SimpleElasticsearchPersistentProperty extends
|
||||
return property.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object read(String s) {
|
||||
if (isTemporalAccessor) {
|
||||
return dateConverter.parse(s, (Class<? extends TemporalAccessor>) actualType);
|
||||
} else { // must be date
|
||||
return dateConverter.parse(s);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.springframework.util.Assert;
|
||||
* @author Sascha Woo
|
||||
* @author Farid Azaza
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Peer Mueller
|
||||
*/
|
||||
abstract class AbstractQuery implements Query {
|
||||
|
||||
@@ -63,6 +64,7 @@ abstract class AbstractQuery implements Query {
|
||||
@Nullable private TimeValue timeout;
|
||||
private boolean explain = false;
|
||||
@Nullable private List<Object> searchAfter;
|
||||
protected List<RescorerQuery> rescorerQueries = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
@@ -94,6 +96,15 @@ abstract class AbstractQuery implements Query {
|
||||
return fields;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFields(List<String> fields) {
|
||||
|
||||
Assert.notNull(fields, "fields must not be null");
|
||||
|
||||
this.fields.clear();
|
||||
this.fields.addAll(fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSourceFilter(SourceFilter sourceFilter) {
|
||||
this.sourceFilter = sourceFilter;
|
||||
@@ -295,4 +306,26 @@ abstract class AbstractQuery implements Query {
|
||||
public List<Object> getSearchAfter() {
|
||||
return searchAfter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRescorerQuery(RescorerQuery rescorerQuery) {
|
||||
|
||||
Assert.notNull(rescorerQuery, "rescorerQuery must not be null");
|
||||
|
||||
this.rescorerQueries.add(rescorerQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRescorerQueries(List<RescorerQuery> rescorerQueryList) {
|
||||
|
||||
Assert.notNull(rescorerQueries, "rescorerQueries must not be null");
|
||||
|
||||
this.rescorerQueries.clear();
|
||||
this.rescorerQueries.addAll(rescorerQueryList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RescorerQuery> getRescorerQueries() {
|
||||
return rescorerQueries;
|
||||
}
|
||||
}
|
||||
|
||||
+137
-6
@@ -21,6 +21,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.elasticsearch.action.bulk.BulkItemResponse;
|
||||
import org.elasticsearch.index.reindex.BulkByScrollResponse;
|
||||
import org.elasticsearch.index.reindex.ScrollableHitSource;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
@@ -43,10 +44,11 @@ public class ByQueryResponse {
|
||||
private final long searchRetries;
|
||||
@Nullable private final String reasonCancelled;
|
||||
private final List<Failure> failures;
|
||||
private final List<SearchFailure> searchFailures;
|
||||
|
||||
private ByQueryResponse(long took, boolean timedOut, long total, long updated, long deleted, int batches,
|
||||
long versionConflicts, long noops, long bulkRetries, long searchRetries, @Nullable String reasonCancelled,
|
||||
List<Failure> failures) {
|
||||
long versionConflicts, long noops, long bulkRetries, long searchRetries,
|
||||
@Nullable String reasonCancelled, List<Failure> failures, List<SearchFailure> searchFailures) {
|
||||
this.took = took;
|
||||
this.timedOut = timedOut;
|
||||
this.total = total;
|
||||
@@ -59,7 +61,8 @@ public class ByQueryResponse {
|
||||
this.searchRetries = searchRetries;
|
||||
this.reasonCancelled = reasonCancelled;
|
||||
this.failures = failures;
|
||||
}
|
||||
this.searchFailures = searchFailures;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of milliseconds from start to end of the whole operation.
|
||||
@@ -148,7 +151,14 @@ public class ByQueryResponse {
|
||||
return failures;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Failures during search phase
|
||||
*/
|
||||
public List<SearchFailure> getSearchFailures() {
|
||||
return searchFailures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ByQueryResponseBuilder} to build {@link ByQueryResponse}
|
||||
*
|
||||
* @return a new {@link ByQueryResponseBuilder} to build {@link ByQueryResponse}
|
||||
@@ -163,7 +173,12 @@ public class ByQueryResponse {
|
||||
.map(Failure::of) //
|
||||
.collect(Collectors.toList()); //
|
||||
|
||||
return ByQueryResponse.builder() //
|
||||
final List<SearchFailure> searchFailures = bulkByScrollResponse.getSearchFailures() //
|
||||
.stream() //
|
||||
.map(SearchFailure::of) //
|
||||
.collect(Collectors.toList());//
|
||||
|
||||
return ByQueryResponse.builder() //
|
||||
.withTook(bulkByScrollResponse.getTook().getMillis()) //
|
||||
.withTimedOut(bulkByScrollResponse.isTimedOut()) //
|
||||
.withTotal(bulkByScrollResponse.getTotal()) //
|
||||
@@ -176,6 +191,7 @@ public class ByQueryResponse {
|
||||
.withSearchRetries(bulkByScrollResponse.getSearchRetries()) //
|
||||
.withReasonCancelled(bulkByScrollResponse.getReasonCancelled()) //
|
||||
.withFailures(failures) //
|
||||
.withSearchFailure(searchFailures) //
|
||||
.build(); //
|
||||
}
|
||||
|
||||
@@ -331,6 +347,115 @@ public class ByQueryResponse {
|
||||
}
|
||||
}
|
||||
|
||||
public static class SearchFailure {
|
||||
private final Throwable reason;
|
||||
@Nullable private final Integer status;
|
||||
@Nullable private final String index;
|
||||
@Nullable private final Integer shardId;
|
||||
@Nullable private final String nodeId;
|
||||
|
||||
private SearchFailure(Throwable reason, @Nullable Integer status, @Nullable String index,
|
||||
@Nullable Integer shardId, @Nullable String nodeId) {
|
||||
this.reason = reason;
|
||||
this.status = status;
|
||||
this.index = index;
|
||||
this.shardId = shardId;
|
||||
this.nodeId = nodeId;
|
||||
}
|
||||
|
||||
public Throwable getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getShardId() {
|
||||
return shardId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getNodeId() {
|
||||
return nodeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link SearchFailureBuilder} to build {@link SearchFailure}
|
||||
*
|
||||
* @return a new {@link SearchFailureBuilder} to build {@link SearchFailure}
|
||||
*/
|
||||
public static SearchFailureBuilder builder() {
|
||||
return new SearchFailureBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link SearchFailure} from {@link ScrollableHitSource.SearchFailure}
|
||||
*
|
||||
* @param searchFailure {@link ScrollableHitSource.SearchFailure} to translate
|
||||
* @return a new {@link SearchFailure}
|
||||
*/
|
||||
public static SearchFailure of(ScrollableHitSource.SearchFailure searchFailure) {
|
||||
return builder() //
|
||||
.withReason(searchFailure.getReason()) //
|
||||
.withIndex(searchFailure.getIndex()) //
|
||||
.withNodeId(searchFailure.getNodeId()) //
|
||||
.withShardId(searchFailure.getShardId()) //
|
||||
.withStatus(searchFailure.getStatus().getStatus()) //
|
||||
.build(); //
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for {@link SearchFailure}
|
||||
*/
|
||||
public static final class SearchFailureBuilder {
|
||||
private Throwable reason;
|
||||
@Nullable private Integer status;
|
||||
@Nullable private String index;
|
||||
@Nullable private Integer shardId;
|
||||
@Nullable private String nodeId;
|
||||
|
||||
private SearchFailureBuilder() {}
|
||||
|
||||
public SearchFailureBuilder withReason(Throwable reason) {
|
||||
this.reason = reason;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SearchFailureBuilder withStatus(Integer status) {
|
||||
this.status = status;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SearchFailureBuilder withIndex(String index) {
|
||||
this.index = index;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SearchFailureBuilder withShardId(Integer shardId) {
|
||||
this.shardId = shardId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SearchFailureBuilder withNodeId(String nodeId) {
|
||||
this.nodeId = nodeId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SearchFailure build() {
|
||||
return new SearchFailure(reason, status, index, shardId, nodeId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final class ByQueryResponseBuilder {
|
||||
private long took;
|
||||
private boolean timedOut;
|
||||
@@ -344,6 +469,7 @@ public class ByQueryResponse {
|
||||
private long searchRetries;
|
||||
@Nullable private String reasonCancelled;
|
||||
private List<Failure> failures = Collections.emptyList();
|
||||
private List<SearchFailure> searchFailures = Collections.emptyList();
|
||||
|
||||
private ByQueryResponseBuilder() {}
|
||||
|
||||
@@ -407,9 +533,14 @@ public class ByQueryResponse {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ByQueryResponseBuilder withSearchFailure(List<SearchFailure> searchFailures) {
|
||||
this.searchFailures = searchFailures;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ByQueryResponse build() {
|
||||
return new ByQueryResponse(took, timedOut, total, updated, deleted, batches, versionConflicts, noops, bulkRetries,
|
||||
searchRetries, reasonCancelled, failures);
|
||||
searchRetries, reasonCancelled, failures, searchFailures);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,4 +41,17 @@ public interface Field {
|
||||
*/
|
||||
@Nullable
|
||||
FieldType getFieldType();
|
||||
|
||||
/**
|
||||
* Sets the path if this field has a multi-part name that should be used in a nested query.
|
||||
* @param path the value to set
|
||||
* @since 4.2
|
||||
*/
|
||||
void setPath(@Nullable String path);
|
||||
|
||||
/**
|
||||
* @return the path if this is a field for a nested query
|
||||
* @since 4.2
|
||||
*/
|
||||
@Nullable String getPath();
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.List;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* MoreLikeThisQuery
|
||||
@@ -176,6 +177,9 @@ public class MoreLikeThisQuery {
|
||||
}
|
||||
|
||||
public void setPageable(Pageable pageable) {
|
||||
|
||||
Assert.notNull(pageable, "pageable must not be null");
|
||||
|
||||
this.pageable = pageable;
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -20,6 +20,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.script.mustache.SearchTemplateRequestBuilder;
|
||||
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
|
||||
import org.elasticsearch.search.collapse.CollapseBuilder;
|
||||
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
|
||||
@@ -50,6 +51,7 @@ public class NativeSearchQuery extends AbstractQuery {
|
||||
@Nullable private HighlightBuilder highlightBuilder;
|
||||
@Nullable private HighlightBuilder.Field[] highlightFields;
|
||||
@Nullable private List<IndexBoost> indicesBoost;
|
||||
@Nullable private SearchTemplateRequestBuilder searchTemplate;
|
||||
|
||||
public NativeSearchQuery(@Nullable QueryBuilder query) {
|
||||
|
||||
@@ -163,4 +165,12 @@ public class NativeSearchQuery extends AbstractQuery {
|
||||
this.indicesBoost = indicesBoost;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SearchTemplateRequestBuilder getSearchTemplate() {
|
||||
return searchTemplate;
|
||||
}
|
||||
|
||||
public void setSearchTemplate(@Nullable SearchTemplateRequestBuilder searchTemplate) {
|
||||
this.searchTemplate = searchTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
+25
-3
@@ -25,6 +25,7 @@ import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.script.mustache.SearchTemplateRequestBuilder;
|
||||
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
|
||||
import org.elasticsearch.search.collapse.CollapseBuilder;
|
||||
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
|
||||
@@ -45,6 +46,7 @@ import org.springframework.lang.Nullable;
|
||||
* @author Martin Choraine
|
||||
* @author Farid Azaza
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Peer Mueller
|
||||
*/
|
||||
public class NativeSearchQueryBuilder {
|
||||
|
||||
@@ -60,6 +62,7 @@ public class NativeSearchQueryBuilder {
|
||||
@Nullable private SourceFilter sourceFilter;
|
||||
@Nullable private CollapseBuilder collapseBuilder;
|
||||
@Nullable private List<IndexBoost> indicesBoost;
|
||||
@Nullable private SearchTemplateRequestBuilder searchTemplateBuilder;
|
||||
private float minScore;
|
||||
private boolean trackScores;
|
||||
@Nullable private Collection<String> ids;
|
||||
@@ -70,6 +73,7 @@ public class NativeSearchQueryBuilder {
|
||||
@Nullable private Integer maxResults;
|
||||
@Nullable private Boolean trackTotalHits;
|
||||
@Nullable private TimeValue timeout;
|
||||
private final List<RescorerQuery> rescorerQueries = new ArrayList<>();
|
||||
|
||||
public NativeSearchQueryBuilder withQuery(QueryBuilder queryBuilder) {
|
||||
this.queryBuilder = queryBuilder;
|
||||
@@ -116,6 +120,11 @@ public class NativeSearchQueryBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder withSearchTemplate(SearchTemplateRequestBuilder searchTemplateBuilder) {
|
||||
this.searchTemplateBuilder = searchTemplateBuilder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder withPageable(Pageable pageable) {
|
||||
this.pageable = pageable;
|
||||
return this;
|
||||
@@ -183,12 +192,17 @@ public class NativeSearchQueryBuilder {
|
||||
this.trackTotalHits = trackTotalHits;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder withTimeout(TimeValue timeout) {
|
||||
|
||||
public NativeSearchQueryBuilder withTimeout(TimeValue timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder withRescorerQuery(RescorerQuery rescorerQuery) {
|
||||
this.rescorerQueries.add(rescorerQuery);
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQuery build() {
|
||||
|
||||
NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(queryBuilder, filterBuilder, sortBuilders,
|
||||
@@ -209,6 +223,10 @@ public class NativeSearchQueryBuilder {
|
||||
nativeSearchQuery.setIndicesBoost(indicesBoost);
|
||||
}
|
||||
|
||||
if (searchTemplateBuilder != null) {
|
||||
nativeSearchQuery.setSearchTemplate(searchTemplateBuilder);
|
||||
}
|
||||
|
||||
if (!isEmpty(scriptFields)) {
|
||||
nativeSearchQuery.setScriptFields(scriptFields);
|
||||
}
|
||||
@@ -250,11 +268,15 @@ public class NativeSearchQueryBuilder {
|
||||
}
|
||||
|
||||
nativeSearchQuery.setTrackTotalHits(trackTotalHits);
|
||||
|
||||
|
||||
if (timeout != null) {
|
||||
nativeSearchQuery.setTimeout(timeout);
|
||||
}
|
||||
|
||||
if (!isEmpty(rescorerQueries)) {
|
||||
nativeSearchQuery.setRescorerQueries(rescorerQueries);
|
||||
}
|
||||
|
||||
return nativeSearchQuery;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -41,6 +42,7 @@ import org.springframework.lang.Nullable;
|
||||
* @author Christoph Strobl
|
||||
* @author Farid Azaza
|
||||
* @author Peter-Josef Meisch
|
||||
* @author Peer Mueller
|
||||
*/
|
||||
public interface Query {
|
||||
|
||||
@@ -101,6 +103,13 @@ public interface Query {
|
||||
*/
|
||||
List<String> getFields();
|
||||
|
||||
/**
|
||||
* Set fields to be returned as part of search request
|
||||
* @param fields must not be {@literal null}
|
||||
* @since 4.2.1
|
||||
*/
|
||||
void setFields(List<String> fields);
|
||||
|
||||
/**
|
||||
* Add source filter to be added as part of search request
|
||||
*
|
||||
@@ -297,7 +306,7 @@ public interface Query {
|
||||
|
||||
/**
|
||||
* Sets the setSearchAfter objects for this query.
|
||||
*
|
||||
*
|
||||
* @param searchAfter the setSearchAfter objects. These are obtained with {@link SearchHit#getSortValues()} from a
|
||||
* search result.
|
||||
* @since 4.2
|
||||
@@ -310,4 +319,29 @@ public interface Query {
|
||||
*/
|
||||
@Nullable
|
||||
List<Object> getSearchAfter();
|
||||
|
||||
/**
|
||||
* Adds a {@link RescorerQuery}.
|
||||
*
|
||||
* @param rescorerQuery the query to add to the list of rescorer queries, must not be {@literal null}
|
||||
* @since 4.2
|
||||
*/
|
||||
void addRescorerQuery(RescorerQuery rescorerQuery);
|
||||
|
||||
/**
|
||||
* Sets the {@link RescorerQuery}.
|
||||
*
|
||||
* @param rescorerQueryList list of rescorer queries set, must not be {@literal null}.
|
||||
* @since 4.2
|
||||
*/
|
||||
void setRescorerQueries(List<RescorerQuery> rescorerQueryList);
|
||||
|
||||
/**
|
||||
* get the list of {@link RescorerQuery}s
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
default List<RescorerQuery> getRescorerQueries() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2021 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;
|
||||
|
||||
/**
|
||||
* Implementation of RescorerQuery to be used for rescoring filtered search results.
|
||||
*
|
||||
* @author Peer Mueller
|
||||
* @since 4.2
|
||||
*/
|
||||
public class RescorerQuery {
|
||||
|
||||
private final Query query;
|
||||
private ScoreMode scoreMode = ScoreMode.Default;
|
||||
@Nullable private Integer windowSize;
|
||||
@Nullable private Float queryWeight;
|
||||
@Nullable private Float rescoreQueryWeight;
|
||||
|
||||
public RescorerQuery(Query query) {
|
||||
|
||||
Assert.notNull(query, "query must not be null");
|
||||
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
public Query getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
public ScoreMode getScoreMode() {
|
||||
return scoreMode;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getWindowSize() {
|
||||
return windowSize;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getQueryWeight() {
|
||||
return queryWeight;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getRescoreQueryWeight() {
|
||||
return rescoreQueryWeight;
|
||||
}
|
||||
|
||||
public RescorerQuery withScoreMode(ScoreMode scoreMode) {
|
||||
|
||||
Assert.notNull(scoreMode, "scoreMode must not be null");
|
||||
|
||||
this.scoreMode = scoreMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RescorerQuery withWindowSize(int windowSize) {
|
||||
this.windowSize = windowSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RescorerQuery withQueryWeight(float queryWeight) {
|
||||
this.queryWeight = queryWeight;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RescorerQuery withRescoreQueryWeight(float rescoreQueryWeight) {
|
||||
this.rescoreQueryWeight = rescoreQueryWeight;
|
||||
return this;
|
||||
}
|
||||
|
||||
public enum ScoreMode {
|
||||
Default, Avg, Max, Min, Total, Multiply
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,6 +31,7 @@ public class SimpleField implements Field {
|
||||
|
||||
private String name;
|
||||
@Nullable private FieldType fieldType;
|
||||
@Nullable private String path;
|
||||
|
||||
public SimpleField(String name) {
|
||||
|
||||
@@ -63,6 +64,17 @@ public class SimpleField implements Field {
|
||||
return fieldType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPath(@Nullable String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user