-
Notifications
You must be signed in to change notification settings - Fork 211
Description
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
}