From 032ad99ad510eb48de11d108829fa4fb0f56cd3b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 26 Jan 2023 00:17:17 +0000 Subject: [PATCH] Fix issue with completion suggester being parsed as term suggester. (#347) * Fix issue with completion suggester being parsed as term suggester. This commit fixes the issue where a completion suggester search request was being parsed as a term suggester and failing due to "Missing required property 'TermSuggestOption.score'" This solution was originally proposed by Github user @apatrida Signed-off-by: Dan Hart * Remove commented code Signed-off-by: Dan Hart * Fix format of changelog item Signed-off-by: Dan Hart Signed-off-by: Dan Hart (cherry picked from commit 013d8d7f3e8746ab526e2be5822f52b94aa363de) Signed-off-by: github-actions[bot] --- CHANGELOG.md | 1 + .../client/json/UnionDeserializer.java | 22 ++++--- .../integTest/AbstractRequestIT.java | 60 +++++++++++++++++++ 3 files changed, 75 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc2913554b..9515dc5a3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Update maintainers, admins and documentation ([#248](https://github.com/opensearch-project/opensearch-java/pull/248)) - Update Gradle to 7.6 ([#311](https://github.com/opensearch-project/opensearch-java/pull/311)) - Add support for OpenSearch Serverless ([#339](https://github.com/opensearch-project/opensearch-java/pull/339)) +- Fix issue where completion suggestions were failing, due to being parsed as term suggestions ([#107](https://github.com/opensearch-project/opensearch-java/issues/107)) ### Deprecated diff --git a/java-client/src/main/java/org/opensearch/client/json/UnionDeserializer.java b/java-client/src/main/java/org/opensearch/client/json/UnionDeserializer.java index dc54bf43e6..3905139a80 100644 --- a/java-client/src/main/java/org/opensearch/client/json/UnionDeserializer.java +++ b/java-client/src/main/java/org/opensearch/client/json/UnionDeserializer.java @@ -48,6 +48,8 @@ import java.util.Map; import java.util.Set; import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; public class UnionDeserializer implements JsonpDeserializer { @@ -169,14 +171,8 @@ public Builder addMember(Kind tag, JsonpDeserializer unwrapped = DelegatingDeserializer.unwrap(deserializer); if (unwrapped instanceof ObjectDeserializer) { ObjectDeserializer od = (ObjectDeserializer) unwrapped; - Set allFields = od.fieldNames(); - Set fields = new HashSet<>(allFields); // copy to update - for (UnionDeserializer.SingleMemberHandler member: objectMembers) { - // Remove respective fields on both sides to keep specific ones - fields.removeAll(member.fields); - member.fields.removeAll(allFields); - } - UnionDeserializer.SingleMemberHandler member = new SingleMemberHandler<>(tag, deserializer, fields); + UnionDeserializer.SingleMemberHandler member = + new SingleMemberHandler<>(tag, deserializer, new HashSet<>(od.fieldNames())); objectMembers.add(member); if (od.shortcutProperty() != null) { // also add it as a string @@ -194,6 +190,16 @@ public Builder addMember(Kind tag, JsonpDeserializer build() { + Map fieldFrequencies = objectMembers.stream().flatMap(m -> m.fields.stream()) + .collect( Collectors.groupingBy(Function.identity(), Collectors.counting())); + Set duplicateFields = fieldFrequencies.entrySet().stream() + .filter(entry -> entry.getValue() > 1) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); + for (UnionDeserializer.SingleMemberHandler member: objectMembers) { + member.fields.removeAll(duplicateFields); + } + // Check that no object member had all its fields removed for (UnionDeserializer.SingleMemberHandler member: objectMembers) { if (member.fields.isEmpty()) { diff --git a/java-client/src/test/java/org/opensearch/client/opensearch/integTest/AbstractRequestIT.java b/java-client/src/test/java/org/opensearch/client/opensearch/integTest/AbstractRequestIT.java index 374b3d1fc3..08ec63b009 100644 --- a/java-client/src/test/java/org/opensearch/client/opensearch/integTest/AbstractRequestIT.java +++ b/java-client/src/test/java/org/opensearch/client/opensearch/integTest/AbstractRequestIT.java @@ -55,6 +55,10 @@ import org.opensearch.client.opensearch.core.SearchRequest; import org.opensearch.client.opensearch.core.bulk.OperationType; import org.opensearch.client.opensearch.core.msearch.RequestItem; +import org.opensearch.client.opensearch.core.search.CompletionSuggester; +import org.opensearch.client.opensearch.core.search.FieldSuggester; +import org.opensearch.client.opensearch.core.search.FieldSuggesterBuilders; +import org.opensearch.client.opensearch.core.search.Suggester; import org.opensearch.client.opensearch.indices.CreateIndexResponse; import org.opensearch.client.opensearch.indices.GetIndexResponse; import org.opensearch.client.opensearch.indices.GetIndicesSettingsResponse; @@ -433,6 +437,62 @@ public void testDefaultIndexSettings() throws IOException { assertNull(settings.get(index).defaults()); } + @Test + public void testCompletionSuggester() throws IOException { + + String index = "test-completion-suggester"; + + Property intValueProp = new Property.Builder() + .long_(v -> v) + .build(); + Property msgCompletionProp = new Property.Builder() + .completion(c -> c) + .build(); + javaClient().indices().create(c -> c + .index(index) + .mappings(m -> m + .properties("intValue", intValueProp) + .properties("msg", msgCompletionProp))); + + AppData appData = new AppData(); + appData.setIntValue(1337); + appData.setMsg("foo"); + + javaClient().index(b -> b + .index(index) + .id("1") + .document(appData) + .refresh(Refresh.True)); + + appData.setIntValue(1338); + appData.setMsg("bar"); + + javaClient().index(b -> b + .index(index) + .id("2") + .document(appData) + .refresh(Refresh.True)); + + CompletionSuggester completionSuggester = FieldSuggesterBuilders.completion() + .field("msg") + .size(1) + .build(); + FieldSuggester fieldSuggester = new FieldSuggester.Builder() + .completion(completionSuggester) + .build(); + Suggester suggester = new Suggester.Builder() + .suggesters(Collections.singletonMap("msgSuggester", fieldSuggester)) + .text("foo") + .build(); + SearchRequest searchRequest = new SearchRequest.Builder() + .index(index) + .suggest(suggester) + .build(); + + SearchResponse response = javaClient().search(searchRequest, AppData.class); + assertTrue(response.suggest().size() > 0); + } + // @Test // public void testValueBodyResponse() throws Exception { // DiskUsageResponse resp = highLevelClient().indices().diskUsage(b -> b