mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-06-14 16:12:11 +00:00
Add support for parameters for runtime fields.
Original Pull Request #2677 Closes #2303
This commit is contained in:
parent
ed898431ab
commit
922c7dd4a7
@ -19,7 +19,7 @@ public record FailureDetails(Integer status, String errorMessage) {
|
|||||||
|
|
||||||
The classes `org.springframework.data.elasticsearch.core.RuntimeField` and `org.springframework.data.elasticsearch.core.query.ScriptType` have been moved to the subpackage `org.springframework.data.elasticsearch.core.query`.
|
The classes `org.springframework.data.elasticsearch.core.RuntimeField` and `org.springframework.data.elasticsearch.core.query.ScriptType` have been moved to the subpackage `org.springframework.data.elasticsearch.core.query`.
|
||||||
|
|
||||||
The `type` parameter of the `ScriptData` constructir is not nullable any longer.
|
The `type` parameter of the `ScriptData` constructor is not nullable any longer.
|
||||||
|
|
||||||
[[elasticsearch-migration-guide-5.1-5.2.deprecations]]
|
[[elasticsearch-migration-guide-5.1-5.2.deprecations]]
|
||||||
== Deprecations
|
== Deprecations
|
||||||
|
@ -67,7 +67,6 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.data.elasticsearch.core.RefreshPolicy;
|
import org.springframework.data.elasticsearch.core.RefreshPolicy;
|
||||||
import org.springframework.data.elasticsearch.core.query.ScriptType;
|
|
||||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||||
import org.springframework.data.elasticsearch.core.document.Document;
|
import org.springframework.data.elasticsearch.core.document.Document;
|
||||||
import org.springframework.data.elasticsearch.core.index.*;
|
import org.springframework.data.elasticsearch.core.index.*;
|
||||||
@ -1237,14 +1236,23 @@ class RequestConverter {
|
|||||||
Map<String, RuntimeField> runtimeMappings = new HashMap<>();
|
Map<String, RuntimeField> runtimeMappings = new HashMap<>();
|
||||||
query.getRuntimeFields().forEach(runtimeField -> {
|
query.getRuntimeFields().forEach(runtimeField -> {
|
||||||
RuntimeField esRuntimeField = RuntimeField.of(rt -> {
|
RuntimeField esRuntimeField = RuntimeField.of(rt -> {
|
||||||
RuntimeField.Builder builder = rt
|
RuntimeField.Builder rfb = rt
|
||||||
.type(RuntimeFieldType._DESERIALIZER.parse(runtimeField.getType()));
|
.type(RuntimeFieldType._DESERIALIZER.parse(runtimeField.getType()));
|
||||||
String script = runtimeField.getScript();
|
String script = runtimeField.getScript();
|
||||||
|
|
||||||
if (script != null) {
|
if (script != null) {
|
||||||
builder = builder.script(s -> s.inline(is -> is.source(script)));
|
rfb
|
||||||
|
.script(s -> s
|
||||||
|
.inline(is -> {
|
||||||
|
is.source(script);
|
||||||
|
|
||||||
|
if (runtimeField.getParams() != null) {
|
||||||
|
is.params(TypeUtils.paramsMap(runtimeField.getParams()));
|
||||||
}
|
}
|
||||||
return builder;
|
return is;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return rfb;
|
||||||
});
|
});
|
||||||
runtimeMappings.put(runtimeField.getName(), esRuntimeField);
|
runtimeMappings.put(runtimeField.getName(), esRuntimeField);
|
||||||
});
|
});
|
||||||
@ -1393,14 +1401,23 @@ class RequestConverter {
|
|||||||
|
|
||||||
Map<String, RuntimeField> runtimeMappings = new HashMap<>();
|
Map<String, RuntimeField> runtimeMappings = new HashMap<>();
|
||||||
query.getRuntimeFields()
|
query.getRuntimeFields()
|
||||||
.forEach(runtimeField -> runtimeMappings.put(runtimeField.getName(), RuntimeField.of(runtimeFieldBuilder -> {
|
.forEach(runtimeField -> runtimeMappings.put(runtimeField.getName(), RuntimeField.of(rfb -> {
|
||||||
runtimeFieldBuilder.type(RuntimeFieldType._DESERIALIZER.parse(runtimeField.getType()));
|
rfb.type(RuntimeFieldType._DESERIALIZER.parse(runtimeField.getType()));
|
||||||
String script = runtimeField.getScript();
|
String script = runtimeField.getScript();
|
||||||
|
|
||||||
if (script != null) {
|
if (script != null) {
|
||||||
runtimeFieldBuilder.script(s -> s.inline(is -> is.source(script)));
|
rfb
|
||||||
|
.script(s -> s
|
||||||
|
.inline(is -> {
|
||||||
|
is.source(script);
|
||||||
|
|
||||||
|
if (runtimeField.getParams() != null) {
|
||||||
|
is.params(TypeUtils.paramsMap(runtimeField.getParams()));
|
||||||
}
|
}
|
||||||
return runtimeFieldBuilder;
|
return is;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return rfb;
|
||||||
})));
|
})));
|
||||||
builder.runtimeMappings(runtimeMappings);
|
builder.runtimeMappings(runtimeMappings);
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,20 @@ package org.springframework.data.elasticsearch.client.elc;
|
|||||||
import co.elastic.clients.elasticsearch._types.*;
|
import co.elastic.clients.elasticsearch._types.*;
|
||||||
import co.elastic.clients.elasticsearch._types.mapping.FieldType;
|
import co.elastic.clients.elasticsearch._types.mapping.FieldType;
|
||||||
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
|
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
|
||||||
import co.elastic.clients.elasticsearch.core.search.*;
|
import co.elastic.clients.elasticsearch.core.search.BoundaryScanner;
|
||||||
|
import co.elastic.clients.elasticsearch.core.search.HighlighterEncoder;
|
||||||
|
import co.elastic.clients.elasticsearch.core.search.HighlighterFragmenter;
|
||||||
|
import co.elastic.clients.elasticsearch.core.search.HighlighterOrder;
|
||||||
|
import co.elastic.clients.elasticsearch.core.search.HighlighterTagsSchema;
|
||||||
|
import co.elastic.clients.elasticsearch.core.search.HighlighterType;
|
||||||
|
import co.elastic.clients.elasticsearch.core.search.ScoreMode;
|
||||||
import co.elastic.clients.elasticsearch.indices.IndexSettings;
|
import co.elastic.clients.elasticsearch.indices.IndexSettings;
|
||||||
|
import co.elastic.clients.json.JsonData;
|
||||||
|
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -31,10 +39,16 @@ import java.util.stream.Collectors;
|
|||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.data.elasticsearch.core.RefreshPolicy;
|
import org.springframework.data.elasticsearch.core.RefreshPolicy;
|
||||||
import org.springframework.data.elasticsearch.core.document.Document;
|
import org.springframework.data.elasticsearch.core.document.Document;
|
||||||
import org.springframework.data.elasticsearch.core.query.*;
|
import org.springframework.data.elasticsearch.core.query.GeoDistanceOrder;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.IndicesOptions;
|
import org.springframework.data.elasticsearch.core.query.IndicesOptions;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.Order;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.Query;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.RescorerQuery;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.UpdateResponse;
|
||||||
import org.springframework.data.elasticsearch.core.reindex.ReindexRequest;
|
import org.springframework.data.elasticsearch.core.reindex.ReindexRequest;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility to handle new Elasticsearch client type values.
|
* Utility to handle new Elasticsearch client type values.
|
||||||
@ -438,4 +452,18 @@ final class TypeUtils {
|
|||||||
return settings != null ? IndexSettings.of(b -> b.withJson(new StringReader(Document.from(settings).toJson())))
|
return settings != null ? IndexSettings.of(b -> b.withJson(new StringReader(Document.from(settings).toJson())))
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 5.2
|
||||||
|
*/
|
||||||
|
static Map<String, JsonData> paramsMap(Map<String, Object> params) {
|
||||||
|
|
||||||
|
Assert.notNull(params, "params must not be null");
|
||||||
|
|
||||||
|
Map<String, JsonData> mappedParams = new LinkedHashMap<>();
|
||||||
|
params.forEach((key, value) -> {
|
||||||
|
mappedParams.put(key, JsonData.of(value));
|
||||||
|
});
|
||||||
|
return mappedParams;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,14 +31,26 @@ import org.springframework.util.Assert;
|
|||||||
public class RuntimeField {
|
public class RuntimeField {
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
/**
|
||||||
|
* the type of the runtime field (long, keyword, etc.)
|
||||||
|
*/
|
||||||
private final String type;
|
private final String type;
|
||||||
@Nullable private final String script;
|
@Nullable private final String script;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 5.2
|
||||||
|
*/
|
||||||
|
@Nullable Map<String, Object> params;
|
||||||
|
|
||||||
public RuntimeField(String name, String type) {
|
public RuntimeField(String name, String type) {
|
||||||
this(name, type, null);
|
this(name, type, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RuntimeField(String name, String type, @Nullable String script) {
|
public RuntimeField(String name, String type, String script) {
|
||||||
|
this(name, type, script, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RuntimeField(String name, String type, @Nullable String script, @Nullable Map<String, Object> params) {
|
||||||
|
|
||||||
Assert.notNull(name, "name must not be null");
|
Assert.notNull(name, "name must not be null");
|
||||||
Assert.notNull(type, "type must not be null");
|
Assert.notNull(type, "type must not be null");
|
||||||
@ -46,6 +58,7 @@ public class RuntimeField {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.script = script;
|
this.script = script;
|
||||||
|
this.params = params;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@ -78,4 +91,12 @@ public class RuntimeField {
|
|||||||
public @Nullable String getScript() {
|
public @Nullable String getScript() {
|
||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 5.2
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public Map<String, Object> getParams() {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package org.springframework.data.elasticsearch.core.query.scriptedandruntimefiel
|
|||||||
import static org.assertj.core.api.Assertions.*;
|
import static org.assertj.core.api.Assertions.*;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -251,6 +252,29 @@ public abstract class ScriptedAndRuntimeFieldsIntegrationTests {
|
|||||||
operations.save(entity);
|
operations.save(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // #2303
|
||||||
|
@DisplayName("should use parameters for runtime fields in search queries")
|
||||||
|
void shouldUseParametersForRuntimeFieldsInSearchQueries() {
|
||||||
|
|
||||||
|
insert("1", "item 1", 80.0);
|
||||||
|
insert("2", "item 2", 90.0);
|
||||||
|
|
||||||
|
RuntimeField runtimeField = new RuntimeField(
|
||||||
|
"priceWithTax",
|
||||||
|
"double",
|
||||||
|
"emit(doc['price'].value * params.tax)",
|
||||||
|
Map.of("tax", 1.19)
|
||||||
|
);
|
||||||
|
var query = CriteriaQuery.builder(
|
||||||
|
Criteria.where("priceWithTax").greaterThan(100.0))
|
||||||
|
.withRuntimeFields(List.of(runtimeField))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var searchHits = operations.search(query, SomethingToBuy.class);
|
||||||
|
|
||||||
|
assertThat(searchHits).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Document(indexName = "#{@indexNameProvider.indexName()}-something-to-by")
|
@Document(indexName = "#{@indexNameProvider.indexName()}-something-to-by")
|
||||||
private static class SomethingToBuy {
|
private static class SomethingToBuy {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user