Skip to content

[BUG] Getting 0 results with filter_path fails to deserialize #1729

@adnang

Description

@adnang

What is the bug?

Not 100% sure this is a bug or a missing feature, or if theres an known workaround, but when filter_path is provided on /_search to omit any fields in the _source, an empty query result will fail to deserialize with org.opensearch.client.util.MissingRequiredPropertyException: Missing required property 'HitsMetadata.hits' because the hits.hits array is missing from the response

How can one reproduce the bug?

Make a query to {indexName}/_search?filter_path=*,-hits.hits._source.someField to only exclude someField on the _source doc, with a query body that results in no hits. The client is constructed as:

new OpenSearchClient(ApacheHttpClient5TransportBuilder
                .builder(HttpHost.create(endpoint))
                .build())

Presumably using the default JSON mapper (JacksonJsonpMapper)

The opensearch response I'm getting is:

{
  "took": 6,
  "timed_out": false,
  "_shards": {
    "total": 2,
    "successful": 2,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 0,
      "relation": "eq"
    },
    "max_score": null
  }
}

Which fails to deserialize with org.opensearch.client.util.MissingRequiredPropertyException: Missing required property 'HitsMetadata.hits'

What is the expected behavior?

Ideally the missing array property would be deserialized into an empty array, is there a workaround for this?

What is your host/environment?

Client version: org.opensearch.client:opensearch-java:3.2.0, on Java 21

Opensearch is running in a docker container: opensearchproject/opensearch:3.2.0

Do you have any screenshots?

Do you have any additional context?

This is the calling code (in Kotlin) - the query is contructed as a string, but there's no issue deserializing when there are some results

    val jsonpMapper = client._transport().jsonpMapper()

    val searchResponseDeserializer = SearchResponse.createSearchResponseDeserializer(
        JsonpDeserializer.of(MySearchDocument::class.java)
    )
    
    val request = Requests.builder()
        .endpoint("/$indexName/_search?typed_keys=true&filter_path=-hits.hits._source.omittedField")
        .method("POST")
        .json(finalQuery)
        .build()

    val responseBody: Body? = client.generic().execute(request).body.getOrNull()

    try {
        val searchResponse: SearchResponse<MySearchDocument> = responseBody
            ?.let { b -> Bodies.json(b, searchResponseDeserializer, jsonpMapper) }
            ?: throw RuntimeException("Failed to parse search response")
        return searchResponse
    } catch (e: RuntimeException) {
        logger.error(e) { "OpenSearch: Failed to search: ${responseBody?.bodyAsString()}" }
        throw e
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions