@Override
  public void handleRequest(final RestRequest request, final RestChannel channel) {
    MultiSearchRequest multiSearchRequest = new MultiSearchRequest();
    multiSearchRequest.listenerThreaded(false);

    String[] indices = Strings.splitStringByCommaToArray(request.param("index"));
    String[] types = Strings.splitStringByCommaToArray(request.param("type"));
    IndicesOptions indicesOptions =
        IndicesOptions.fromRequest(request, multiSearchRequest.indicesOptions());

    try {
      multiSearchRequest.add(
          request.content(),
          request.contentUnsafe(),
          indices,
          types,
          request.param("search_type"),
          request.param("routing"),
          indicesOptions,
          allowExplicitIndex);
    } catch (Exception e) {
      try {
        XContentBuilder builder = restContentBuilder(request);
        channel.sendResponse(
            new XContentRestResponse(
                request,
                BAD_REQUEST,
                builder.startObject().field("error", e.getMessage()).endObject()));
      } catch (IOException e1) {
        logger.error("Failed to send failure response", e1);
      }
      return;
    }

    client.multiSearch(
        multiSearchRequest,
        new ActionListener<MultiSearchResponse>() {
          @Override
          public void onResponse(MultiSearchResponse response) {
            try {
              XContentBuilder builder = restContentBuilder(request);
              builder.startObject();
              response.toXContent(builder, request);
              builder.endObject();
              channel.sendResponse(new XContentRestResponse(request, OK, builder));
            } catch (Throwable e) {
              onFailure(e);
            }
          }

          @Override
          public void onFailure(Throwable e) {
            try {
              channel.sendResponse(new XContentThrowableRestResponse(request, e));
            } catch (IOException e1) {
              logger.error("Failed to send failure response", e1);
            }
          }
        });
  }
 @Override
 public void handleRequest(final RestRequest request, final RestChannel channel) {
   PutWarmerRequest putWarmerRequest = new PutWarmerRequest(request.param("name"));
   putWarmerRequest.listenerThreaded(false);
   SearchRequest searchRequest =
       new SearchRequest(Strings.splitStringByCommaToArray(request.param("index")))
           .types(Strings.splitStringByCommaToArray(request.param("type")))
           .source(request.content(), request.contentUnsafe());
   searchRequest.indicesOptions(
       IndicesOptions.fromRequest(request, searchRequest.indicesOptions()));
   putWarmerRequest.searchRequest(searchRequest);
   putWarmerRequest.timeout(request.paramAsTime("timeout", putWarmerRequest.timeout()));
   putWarmerRequest.masterNodeTimeout(
       request.paramAsTime("master_timeout", putWarmerRequest.masterNodeTimeout()));
   client
       .admin()
       .indices()
       .putWarmer(
           putWarmerRequest, new AcknowledgedRestResponseActionListener(request, channel, logger));
 }
  @Override
  public void handleRequest(final RestRequest request, final RestChannel channel) {
    PutWarmerRequest putWarmerRequest = new PutWarmerRequest(request.param("name"));
    putWarmerRequest.listenerThreaded(false);
    SearchRequest searchRequest =
        new SearchRequest(RestActions.splitIndices(request.param("index")))
            .types(RestActions.splitTypes(request.param("type")))
            .source(request.content(), request.contentUnsafe());
    putWarmerRequest.searchRequest(searchRequest);
    client
        .admin()
        .indices()
        .putWarmer(
            putWarmerRequest,
            new ActionListener<PutWarmerResponse>() {
              @Override
              public void onResponse(PutWarmerResponse response) {
                try {
                  XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
                  builder
                      .startObject()
                      .field("ok", true)
                      .field("acknowledged", response.isAcknowledged());
                  builder.endObject();
                  channel.sendResponse(new XContentRestResponse(request, OK, builder));
                } catch (IOException e) {
                  onFailure(e);
                }
              }

              @Override
              public void onFailure(Throwable e) {
                try {
                  channel.sendResponse(new XContentThrowableRestResponse(request, e));
                } catch (IOException e1) {
                  logger.error("Failed to send failure response", e1);
                }
              }
            });
  }
  @Override
  public void handleRequest(final RestRequest request, final RestChannel channel) {
    final ExplainRequest explainRequest =
        new ExplainRequest(request.param("index"), request.param("type"), request.param("id"));
    explainRequest.parent(request.param("parent"));
    explainRequest.routing(request.param("routing"));
    explainRequest.preference(request.param("preference"));
    String sourceString = request.param("source");
    String queryString = request.param("q");
    if (request.hasContent()) {
      explainRequest.source(request.content(), request.contentUnsafe());
    } else if (sourceString != null) {
      explainRequest.source(new BytesArray(request.param("source")), false);
    } else if (queryString != null) {
      QueryStringQueryBuilder queryStringBuilder = QueryBuilders.queryString(queryString);
      queryStringBuilder.defaultField(request.param("df"));
      queryStringBuilder.analyzer(request.param("analyzer"));
      queryStringBuilder.analyzeWildcard(request.paramAsBoolean("analyze_wildcard", false));
      queryStringBuilder.lowercaseExpandedTerms(
          request.paramAsBoolean("lowercase_expanded_terms", true));
      queryStringBuilder.lenient(request.paramAsBooleanOptional("lenient", null));
      String defaultOperator = request.param("default_operator");
      if (defaultOperator != null) {
        if ("OR".equals(defaultOperator)) {
          queryStringBuilder.defaultOperator(QueryStringQueryBuilder.Operator.OR);
        } else if ("AND".equals(defaultOperator)) {
          queryStringBuilder.defaultOperator(QueryStringQueryBuilder.Operator.AND);
        } else {
          throw new ElasticSearchIllegalArgumentException(
              "Unsupported defaultOperator [" + defaultOperator + "], can either be [OR] or [AND]");
        }
      }

      ExplainSourceBuilder explainSourceBuilder = new ExplainSourceBuilder();
      explainSourceBuilder.query(queryStringBuilder);
      explainRequest.source(explainSourceBuilder);
    }

    client.explain(
        explainRequest,
        new ActionListener<ExplainResponse>() {

          @Override
          public void onResponse(ExplainResponse response) {
            try {
              XContentBuilder builder = restContentBuilder(request);
              builder.startObject();
              builder.field(Fields.OK, response.exists());
              builder.field(Fields.MATCHES, response.match());
              if (response.hasExplanation()) {
                builder.startObject(Fields.EXPLANATION);
                buildExplanation(builder, response.explanation());
                builder.endObject();
              }
              builder.endObject();
              channel.sendResponse(
                  new XContentRestResponse(request, response.exists() ? OK : NOT_FOUND, builder));
            } catch (Exception e) {
              onFailure(e);
            }
          }

          private void buildExplanation(XContentBuilder builder, Explanation explanation)
              throws IOException {
            builder.field(Fields.VALUE, explanation.getValue());
            builder.field(Fields.DESCRIPTION, explanation.getDescription());
            Explanation[] innerExps = explanation.getDetails();
            if (innerExps != null) {
              builder.startArray(Fields.DETAILS);
              for (Explanation exp : innerExps) {
                builder.startObject();
                buildExplanation(builder, exp);
                builder.endObject();
              }
              builder.endArray();
            }
          }

          @Override
          public void onFailure(Throwable e) {
            try {
              channel.sendResponse(new XContentThrowableRestResponse(request, e));
            } catch (IOException e1) {
              logger.error("Failed to send failure response", e1);
            }
          }
        });
  }