package com.github.obourgain.elasticsearch.http.handler.search.search; import static org.elasticsearch.action.search.SearchType.DEFAULT; import java.io.ByteArrayOutputStream; import java.io.IOException; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.search.MultiSearchRequest; import org.elasticsearch.action.search.SearchAction; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.github.obourgain.elasticsearch.http.client.HttpClient; import com.github.obourgain.elasticsearch.http.concurrent.ListenerCompleterObserver; import com.github.obourgain.elasticsearch.http.request.RequestUriBuilder; import com.github.obourgain.elasticsearch.http.response.ErrorHandler; import io.netty.buffer.ByteBuf; import io.reactivex.netty.protocol.http.client.HttpClientRequest; import io.reactivex.netty.protocol.http.client.HttpClientResponse; import rx.Observable; import rx.functions.Func1; /** * @author olivier bourgain */ public class MultiSearchActionHandler { private static final Logger logger = LoggerFactory.getLogger(MultiSearchActionHandler.class); public static final byte[] LINE_FEED = "\n".getBytes(); private final HttpClient httpClient; public MultiSearchActionHandler(HttpClient httpClient) { this.httpClient = httpClient; } public SearchAction getAction() { return SearchAction.INSTANCE; } public void execute(MultiSearchRequest request, final ActionListener<MultiSearchResponse> listener) { logger.debug("multi search request {}", request); try { RequestUriBuilder uriBuilder = new RequestUriBuilder(); uriBuilder.addEndpoint("_msearch"); uriBuilder.addIndicesOptions(request.indicesOptions()); // TODO convert lazily ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); for (SearchRequest searchRequest : request.requests()) { writeHeader(searchRequest, outputStream); outputStream.write(LINE_FEED); outputStream.write(searchRequest.source().toBytes()); outputStream.write(LINE_FEED); } httpClient.getHttpClient().submit(HttpClientRequest.createPost(uriBuilder.toString()) .withContent(outputStream.toByteArray())) .flatMap(ErrorHandler.AS_FUNC) .flatMap(new Func1<HttpClientResponse<ByteBuf>, Observable<MultiSearchResponse>>() { @Override public Observable<MultiSearchResponse> call(HttpClientResponse<ByteBuf> response) { return response.getContent().flatMap(new Func1<ByteBuf, Observable<MultiSearchResponse>>() { @Override public Observable<MultiSearchResponse> call(ByteBuf byteBuf) { return MultiSearchResponse.parse(byteBuf); } }); } }) .single() .subscribe(new ListenerCompleterObserver<>(listener)); } catch (Exception e) { listener.onFailure(e); } } private void writeHeader(SearchRequest request, ByteArrayOutputStream outputStream) { try (XContentBuilder builder = XContentFactory.jsonBuilder(outputStream)) { builder.startObject(); builder.field("index", request.indices()); if(request.types() != null && request.types().length != 0) { builder.field("type", request.types()); } if(request.searchType() != DEFAULT) { builder.field("search_type", request.searchType().name().toLowerCase()); } if(request.preference() != null) { builder.field("preference", request.preference()); } if(request.routing() != null) { builder.field("routing", request.routing()); } builder.endObject(); } catch (IOException e) { throw new RuntimeException(e); } } }