public Result fieldTerms(
      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);
      FieldTermsResponse terms = search.fieldTerms(field);

      Map<String, Object> result = Maps.newHashMap();
      result.put("total", terms.total);
      result.put("missing", terms.missing);
      result.put("time", terms.time);
      result.put("other", terms.other);
      result.put("terms", terms.terms);

      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);
    }
  }