jillesvangurp / kt-search

Multi platform kotlin client for Elasticsearch & Opensearch with easily extendable Kotlin DSLs for queries, mappings, bulk, and more.
MIT License
95 stars 23 forks source link

[BUG] multi-search is not correctly parsed #57

Closed NikkyAI closed 1 year ago

NikkyAI commented 1 year ago

Describe the bug

A clear and concise description of what the bug is.

elasticsearch responds to <target?_msearch with a json object, but kt-search is trying to parse nd-json

also.. kt-search is currently dropping the content-header even if it is set using rawBody(body, contentType)

To Fix

the response needs to be parsed with

@Serializable
data class MultiSearchResponse(
    val took: Long,
    val responses: List<SearchResponse>
)

suspend fun SearchClient.msearch(
    target: String?=null,
    body: String?,
    allowNoIndices: Boolean? = null,
    cssMinimizeRoundtrips: Boolean? = null,
    expandWildcards: ExpandWildCards? = null,
    ignoreThrottled: Boolean? = null,
    ignoreUnavailable: Boolean? = null,
    maxConcurrentSearches: Int? = null,
    maxConcurrentShardRequests: Int? = null,
    preFilterShardSize: Int? = null,
    routing: String? = null,
    searchType: SearchType? = null,
    typedKeys: Boolean? = null,
): MultiSearchResponse {
    return restClient.post {
        path(*listOfNotNull(target.takeIf { !it.isNullOrBlank() }, "_msearch").toTypedArray())

        parameter("allow_no_indices", allowNoIndices)
        parameter("ccs_minimize_roundtrips", cssMinimizeRoundtrips)
        parameter("expand_wildcards", expandWildcards)
        parameter("ignore_throttled", ignoreThrottled)
        parameter("ignore_unavailable", ignoreUnavailable)
        parameter("max_concurrent_searches", maxConcurrentSearches)
        parameter("max_concurrent_shard_requests", maxConcurrentShardRequests)
        parameter("max_concurrent_shard_requests", maxConcurrentShardRequests)
        parameter("pre_filter_shard_size", preFilterShardSize)
        parameter("routing", routing)
        parameter("search_type", searchType)
        parameter("typed_keys", typedKeys)

        body?.let {
            rawBody(
                body = body,
                contentType = ContentType("application", "x-ndjson")
            )
        }
    }.parse(MultiSearchResponse.serializer())
}

and to fix the content-type not being passed along (although it works without it anyways.. just not quite like the elasticsearch docs say)

suspend fun RestClient.get(block: SearchAPIRequest.() -> Unit): Result<RestResponse.Status2XX> {
    val request = SearchAPIRequest()
    block.invoke(request)
    return doRequest(
        pathComponents = listOf("/" + request.pathComponents.joinToString("/")),
        payload = request.body,
        contentType = request.contentType,
        httpMethod = HttpMethod.Get,
        parameters = request.parameters,
        headers = request.headers
    ).asResult()
}

Expected behavior

A clear and concise description of what you expected to happen.

Your context

Will you be able to help with a pull request?

yes, ofc