From 045c805eb58a166f55888d27a0358d184f117761 Mon Sep 17 00:00:00 2001 From: Russ Cam Date: Tue, 27 Feb 2024 14:12:52 +1000 Subject: [PATCH] Support optional function score variant (#880) * Support optional function score variant This commit supports function score functions with an optional function variant. The function is optional as it is perfectly valid to have a function with only a weight e.g. a function score query with multiple functions and a score mode of "first", where the last weight function acts as some default value. Closes opensearch-project/opensearch-java#820 Signed-off-by: Russ Cam * Address CI build issues Signed-off-by: Russ Cam * remove changelog entry for 3.0 Signed-off-by: Russ Cam --------- Signed-off-by: Russ Cam --- CHANGELOG.md | 1 + .../_types/query_dsl/FunctionScore.java | 40 ++++++++++++------- .../query_dsl/FunctionScoreQueryTest.java | 31 ++++++++++++++ 3 files changed, 58 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c255d2b37c..1b339212a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ This section is for maintaining a changelog for all breaking changes for the cli ### Fixed - Fix integer overflow for variables in indices stats response ([#877](https://github.com/opensearch-project/opensearch-java/pull/877)) +- Support weight function in function score query ([#880](https://github.com/opensearch-project/opensearch-java/pull/880)) ### Security diff --git a/java-client/src/main/java/org/opensearch/client/opensearch/_types/query_dsl/FunctionScore.java b/java-client/src/main/java/org/opensearch/client/opensearch/_types/query_dsl/FunctionScore.java index 7b77683800..2b5fcd2d0e 100644 --- a/java-client/src/main/java/org/opensearch/client/opensearch/_types/query_dsl/FunctionScore.java +++ b/java-client/src/main/java/org/opensearch/client/opensearch/_types/query_dsl/FunctionScore.java @@ -106,10 +106,14 @@ public final Object _get() { @Nullable private final Double weight; - public FunctionScore(FunctionScoreVariant value) { - - this._kind = ApiTypeHelper.requireNonNull(value._functionScoreKind(), this, ""); - this._value = ApiTypeHelper.requireNonNull(value, this, ""); + public FunctionScore(@Nullable FunctionScoreVariant value) { + if (value != null) { + this._kind = ApiTypeHelper.requireNonNull(value._functionScoreKind(), this, ""); + this._value = ApiTypeHelper.requireNonNull(value, this, ""); + } else { + this._kind = null; + this._value = null; + } this.filter = null; this.weight = null; @@ -117,9 +121,13 @@ public FunctionScore(FunctionScoreVariant value) { } private FunctionScore(Builder builder) { - - this._kind = ApiTypeHelper.requireNonNull(builder._kind, builder, ""); - this._value = ApiTypeHelper.requireNonNull(builder._value, builder, ""); + if (builder._value != null) { + this._kind = ApiTypeHelper.requireNonNull(builder._kind, builder, ""); + this._value = ApiTypeHelper.requireNonNull(builder._value, builder, ""); + } else { + this._kind = null; + this._value = null; + } this.filter = builder.filter; this.weight = builder.weight; @@ -266,9 +274,11 @@ public void serialize(JsonGenerator generator, JsonpMapper mapper) { } - generator.writeKey(_kind.jsonValue()); - if (_value instanceof JsonpSerializable) { - ((JsonpSerializable) _value).serialize(generator, mapper); + if (_value != null) { + generator.writeKey(_kind.jsonValue()); + if (_value instanceof JsonpSerializable) { + ((JsonpSerializable) _value).serialize(generator, mapper); + } } generator.writeEnd(); @@ -279,8 +289,10 @@ public Builder toBuilder() { return new Builder()._kind(_kind)._value(_value).filter(filter).weight(weight); } - public static class Builder extends ObjectBuilderBase { + public static class Builder extends ObjectBuilderBase implements ObjectBuilder { + @Nullable private Kind _kind; + @Nullable private Object _value; @Nullable @@ -289,12 +301,12 @@ public static class Builder extends ObjectBuilderBase { @Nullable private Double weight; - protected final Builder _kind(Kind v) { + protected final Builder _kind(@Nullable Kind v) { this._kind = v; return this; } - protected final Builder _value(Object v) { + protected final Builder _value(@Nullable Object v) { this._value = v; return this; } @@ -384,7 +396,7 @@ public ContainerBuilder scriptScore(Function fs.functions(f -> f.weight(5d)))._toQuery(); + + String json = "{\"function_score\":{\"functions\":[{\"weight\":5.0}]}}"; + + assertEquals(json, toJson(functionScoreQuery)); + + Query roundtripQuery = checkJsonRoundtrip(functionScoreQuery, json); + + assertNull(roundtripQuery.functionScore().functions().get(0)._kind()); + assertEquals(5.0, roundtripQuery.functionScore().functions().get(0).weight(), 0.001); + } + + @Test + public void canSupportFunctionVariant() { + Query functionScoreQuery = FunctionScoreQuery.of( + fs -> fs.functions(f -> f.weight(3d).linear(l -> l.field("field").placement(p -> p.decay(8.0)))) + )._toQuery(); + + String json = "{\"function_score\":{\"functions\":[{\"weight\":3.0,\"linear\":{\"field\":{\"decay\":8.0}}}]}}"; + + assertEquals(json, toJson(functionScoreQuery)); + + Query roundtripQuery = checkJsonRoundtrip(functionScoreQuery, json); + + assertEquals(FunctionScore.Kind.Linear, roundtripQuery.functionScore().functions().get(0)._kind()); + assertEquals(3.0, roundtripQuery.functionScore().functions().get(0).weight(), 0.001); + assertEquals(8.0, roundtripQuery.functionScore().functions().get(0).linear().placement().decay(), 0.001); + } }