public Result fieldStats(
      String q,
      String field,
      String rangeType,
      int relative,
      String from,
      String to,
      String keyword,
      String streamId) {
    if (q == null || q.isEmpty()) {
      q = "*";
    }

    // Determine timerange type.
    TimeRange timerange;
    try {
      timerange = TimeRange.factory(rangeType, relative, from, to, keyword);
    } catch (InvalidRangeParametersException e2) {
      return status(
          400, views.html.errors.error.render("Invalid range parameters provided.", e2, request()));
    } catch (IllegalArgumentException e1) {
      return status(
          400, views.html.errors.error.render("Invalid range type provided.", e1, request()));
    }

    String filter = null;
    if (streamId != null && !streamId.isEmpty()) {
      filter = "streams:" + streamId;
    }

    try {
      UniversalSearch search = searchFactory.queryWithRangeAndFilter(q, timerange, filter);
      FieldStatsResponse stats = search.fieldStats(field);

      Map<String, Object> result = Maps.newHashMap();
      result.put("count", stats.count);
      result.put("sum", stats.sum);
      result.put("mean", stats.mean);
      result.put("min", stats.min);
      result.put("max", stats.max);
      result.put("variance", stats.variance);
      result.put("sum_of_squares", stats.sumOfSquares);
      result.put("std_deviation", stats.stdDeviation);
      result.put("cardinality", stats.cardinality);

      return ok(Json.toJson(result));
    } catch (IOException e) {
      return internalServerError("io exception");
    } catch (APIException e) {
      if (e.getHttpCode() == 400) {
        // This usually means the field does not have a numeric type. Pass through!
        return badRequest();
      }

      return internalServerError("api exception " + e);
    }
  }
  public Result histogram(
      String q,
      String rangeType,
      int relative,
      String from,
      String to,
      String keyword,
      String interval,
      String streamId,
      int maxDataPoints) {
    if (q == null || q.isEmpty()) {
      q = "*";
    }

    // Interval.
    if (interval == null
        || interval.isEmpty()
        || !SearchTools.isAllowedDateHistogramInterval(interval)) {
      interval = "minute";
    }

    // Determine timerange type.
    TimeRange timerange;
    try {
      timerange = TimeRange.factory(rangeType, relative, from, to, keyword);
    } catch (InvalidRangeParametersException e2) {
      return status(
          400, views.html.errors.error.render("Invalid range parameters provided.", e2, request()));
    } catch (IllegalArgumentException e1) {
      return status(
          400, views.html.errors.error.render("Invalid range type provided.", e1, request()));
    }

    String filter = null;
    if (streamId != null && !streamId.isEmpty()) {
      filter = "streams:" + streamId;
    }

    try {
      UniversalSearch search = searchFactory.queryWithRangeAndFilter(q, timerange, filter);
      DateHistogramResult histogram = search.dateHistogram(interval);
      List<Map<String, Long>> results =
          formatHistogramResults(histogram, maxDataPoints, relative == 0);

      Map<String, Object> result = Maps.newHashMap();
      AbsoluteRange boundaries = histogram.getHistogramBoundaries();
      result.put("time", histogram.getTookMs());
      result.put("interval", histogram.getInterval());
      result.put("values", results);
      result.put("from", boundaries.getFrom());
      result.put("to", boundaries.getTo());

      return ok(Json.toJson(result));
    } catch (IOException e) {
      return internalServerError("io exception");
    } catch (APIException e) {
      if (e.getHttpCode() == 400) {
        // This usually means the field does not have a numeric type. Pass through!
        return badRequest();
      }

      return internalServerError("api exception " + e);
    }
  }