opensearch-java icon indicating copy to clipboard operation
opensearch-java copied to clipboard

[BUG] Deserializing MatchQuery ZeroTermsQuery field fails if the source JSON comes from OpenSearch MatchQuery

Open dbwiddis opened this issue 1 year ago • 4 comments

What is the bug?

The enum defined for the client uses lower case values for the ZeroTermsQuery enum: https://github.com/opensearch-project/opensearch-java/blob/08e7e6504d4e6029640940f4bb4670e5e183c700/java-client/src/main/java/org/opensearch/client/opensearch/_types/query_dsl/ZeroTermsQuery.java#L38-L42

However, this enum is defined on OpenSearch with traditional all-caps enum names:

public enum ZeroTermsQuery implements Writeable {
    NONE(0),
    ALL(1),

As a result, a search query generated on OpenSearch can not simply transform its JSON into a client search request.

How can one reproduce the bug?

  1. Generate a Search Query on OpenSearch, for example:
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.matchQuery(CONNECTOR_ID_FIELD, connectorId));
  1. Add that query into a SearchSourceBuilder:
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(boolQueryBuilder);
  1. Transform that SearchSourceBuilder to JSON:
String json = sourceBuilder.toString();

Note the value of zero_terms_query is all upper case.

{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "connector_id": {
              "query": "Jm_4dpEBnn49655wiz2Y",
              "operator": "OR",
              "prefix_length": 0,
              "max_expansions": 50,
              "fuzzy_transpositions": true,
              "lenient": false,
              "zero_terms_query": "NONE",
              "auto_generate_synonyms_phrase_query": true,
              "boost": 1
            }
          }
        },
        {
          "ids": {
            "values": [],
            "boost": 1
          }
        }
      ],
      "adjust_pure_negative": true,
      "boost": 1
    }
  }
}
  1. Create a parser with that JSON:
JsonpMapper mapper = openSearchClient._transport().jsonpMapper();
JsonParser parser = mapper.jsonProvider().createParser(new StringReader(json));
  1. Attempt to deserialize that JSON into a OpenSearch Java Client SearchRequest object:
SearchRequest searchRequest = SearchRequest._DESERIALIZER.deserialize(parser, mapper);
  1. Observe exception:
2024-08-21 15:04:46 jakarta.json.stream.JsonParsingException: Invalid enum 'NONE'
2024-08-21 15:04:46     at org.opensearch.client.json.JsonEnum$Deserializer.deserialize(JsonEnum.java:116) ~[?:?]
2024-08-21 15:04:46     at org.opensearch.client.json.JsonEnum$Deserializer.deserialize(JsonEnum.java:102) ~[?:?]
2024-08-21 15:04:46     at org.opensearch.client.json.JsonEnum$Deserializer.deserialize(JsonEnum.java:61) ~[?:?]
2024-08-21 15:04:46     at org.opensearch.client.json.JsonpDeserializer.deserialize(JsonpDeserializer.java:87) ~[?:?]
2024-08-21 15:04:46     at org.opensearch.client.json.ObjectDeserializer$FieldObjectDeserializer.deserialize(ObjectDeserializer.java:81) ~[?:?]
2024-08-21 15:04:46     at org.opensearch.client.json.ObjectDeserializer.deserialize(ObjectDeserializer.java:185) ~[?:?]
2024-08-21 15:04:46     at org.opensearch.client.json.ObjectDeserializer.deserialize(ObjectDeserializer.java:146) ~[?:?]
2024-08-21 15:04:46     at org.opensearch.client.json.JsonpDeserializer.deserialize(JsonpDeserializer.java:87) ~[?:?]
2024-08-21 15:04:46     at org.opensearch.client.json.ObjectBuilderDeserializer.deserialize(ObjectBuilderDeserializer.java:91) ~[?:?]
<snip>

What is the expected behavior?

In general, an OpenSearch SearchSourceBuilder can be serialized into JSON and then deserialized into an OpenSearch Java Client SearchRequest.

In this particular case, the all-caps enum name should match case-insensitively rather than throwing an exception.

See, for example, how logical operators (such as the OR in this query) accept either all-upper or all-lower case: https://github.com/opensearch-project/opensearch-java/blob/08e7e6504d4e6029640940f4bb4670e5e183c700/java-client/src/main/java/org/opensearch/client/opensearch/_types/query_dsl/Operator.java#L39-L42

What is your host/environment?

Running this on OpenSearch 2.15 code, but it has not changed since pre-fork.

Do you have any additional context?

Relevant code block causing the issue on a feature branch: https://github.com/opensearch-project/ml-commons/blob/feature/multi_tenancy/plugin/src/main/java/org/opensearch/ml/sdkclient/RemoteClusterIndicesClient.java#L230-L232

dbwiddis avatar Aug 21 '24 22:08 dbwiddis