private AggregationBuilder<?> updateAggIfNested(AggregationBuilder<?> lastAgg, Field field) {
   if (field.isNested()) {
     lastAgg =
         AggregationBuilders.nested(field.getName() + "Nested")
             .path(field.getNestedPath())
             .subAggregation(lastAgg);
   }
   return lastAgg;
 }
 private AggregationBuilder createNestedAggregation(Field field) {
   AggregationBuilder nestedBuilder;
   String nestedPath = field.getNestedPath();
   if (field.isReverseNested()) {
     if (nestedPath == null || !nestedPath.startsWith("~"))
       return AggregationBuilders.reverseNested(getNestedAggName(field)).path(nestedPath);
     nestedPath = nestedPath.substring(1);
   }
   nestedBuilder = AggregationBuilders.nested(getNestedAggName(field)).path(nestedPath);
   return nestedBuilder;
 }
  private void setFields(List<Field> fields) {
    if (select.getFields().size() > 0) {
      ArrayList<String> includeFields = new ArrayList<>();

      for (Field field : fields) {
        if (field != null) {
          includeFields.add(field.getName());
        }
      }

      request.setFetchSource(includeFields.toArray(new String[includeFields.size()]), null);
    }
  }
 private String getNestedAggName(Field field) {
   String prefix;
   if (field instanceof MethodField) {
     String nestedPath = field.getNestedPath();
     if (nestedPath != null) {
       prefix = nestedPath;
     } else {
       prefix = field.getAlias();
     }
   } else {
     prefix = field.getName();
   }
   return prefix + "@NESTED";
 }
  /**
   * 分组查的聚合函数
   *
   * @param field
   * @return
   * @throws SqlParseException
   */
  public AggregationBuilder<?> makeGroupAgg(Field field) throws SqlParseException {
    if (field instanceof MethodField) {

      MethodField methodField = (MethodField) field;
      if (methodField.getName().equals("filter")) {
        Map<String, Object> paramsAsMap = methodField.getParamsAsMap();
        Where where = (Where) paramsAsMap.get("where");
        return AggregationBuilders.filter(paramsAsMap.get("alias").toString())
            .filter(FilterMaker.explan(where));
      }
      return makeRangeGroup(methodField);
    } else {
      TermsBuilder termsBuilder = AggregationBuilders.terms(field.getName()).field(field.getName());
      groupMap.put(field.getName(), new KVValue("KEY", termsBuilder));
      return termsBuilder;
    }
  }
 private void explanFields(
     SearchRequestBuilder request, List<Field> fields, AggregationBuilder<?> groupByAgg)
     throws SqlParseException {
   for (Field field : fields) {
     if (field instanceof MethodField) {
       AbstractAggregationBuilder makeAgg = aggMaker.makeFieldAgg((MethodField) field, groupByAgg);
       if (groupByAgg != null) {
         groupByAgg.subAggregation(makeAgg);
       } else {
         request.addAggregation(makeAgg);
       }
     } else if (field instanceof Field) {
       request.addField(field.getName());
     } else {
       throw new SqlParseException("it did not support this field method " + field);
     }
   }
 }
  @Override
  public SqlElasticSearchRequestBuilder explain() throws SqlParseException {
    this.request = client.prepareSearch();
    request.setListenerThreaded(false);
    setIndicesAndTypes();

    setWhere(select.getWhere());
    AggregationBuilder<?> lastAgg = null;

    for (List<Field> groupBy : select.getGroupBys()) {
      if (!groupBy.isEmpty()) {
        Field field = groupBy.get(0);
        lastAgg = aggMaker.makeGroupAgg(field);

        if (lastAgg != null && lastAgg instanceof TermsBuilder && !(field instanceof MethodField)) {
          ((TermsBuilder) lastAgg).size(select.getRowCount());
        }

        if (field.isNested()) {

          AggregationBuilder nestedBuilder = createNestedAggregation(field);
          if (insertFilterIfExistsAfter(lastAgg, groupBy, nestedBuilder, 1)) {
            groupBy.remove(1);
          } else {
            nestedBuilder.subAggregation(lastAgg);
          }
          request.addAggregation(wrapNestedIfNeeded(nestedBuilder, field.isReverseNested()));
        } else {
          request.addAggregation(lastAgg);
        }

        for (int i = 1; i < groupBy.size(); i++) {
          field = groupBy.get(i);
          AggregationBuilder<?> subAgg = aggMaker.makeGroupAgg(field);
          if (subAgg instanceof TermsBuilder && !(field instanceof MethodField)) {
            ((TermsBuilder) subAgg).size(0);
          }

          if (field.isNested()) {
            AggregationBuilder nestedBuilder = createNestedAggregation(field);
            if (insertFilterIfExistsAfter(subAgg, groupBy, nestedBuilder, i + 1)) {
              groupBy.remove(i + 1);
              i++;
            } else {
              nestedBuilder.subAggregation(subAgg);
            }
            lastAgg.subAggregation(wrapNestedIfNeeded(nestedBuilder, field.isReverseNested()));

          } else {
            lastAgg.subAggregation(subAgg);
          }

          lastAgg = subAgg;
        }
      }
    }

    Map<String, KVValue> groupMap = aggMaker.getGroupMap();
    // add field
    if (select.getFields().size() > 0) {
      setFields(select.getFields());
      explanFields(request, select.getFields(), lastAgg);
    }

    // add order
    if (lastAgg != null && select.getOrderBys().size() > 0) {
      for (Order order : select.getOrderBys()) {
        KVValue temp = groupMap.get(order.getName());
        if (temp != null) {
          TermsBuilder termsBuilder = (TermsBuilder) temp.value;
          switch (temp.key) {
            case "COUNT":
              termsBuilder.order(Terms.Order.count(isASC(order)));
              break;
            case "KEY":
              termsBuilder.order(Terms.Order.term(isASC(order)));
              // add the sort to the request also so the results get sorted as well
              request.addSort(order.getName(), SortOrder.valueOf(order.getType()));
              break;
            case "FIELD":
              termsBuilder.order(Terms.Order.aggregation(order.getName(), isASC(order)));
              break;
            default:
              throw new SqlParseException(order.getName() + " can not to order");
          }
        } else {
          request.addSort(order.getName(), SortOrder.valueOf(order.getType()));
        }
      }
    }

    setLimitFromHint(this.select.getHints());

    request.setSearchType(SearchType.DEFAULT);
    updateRequestWithIndexAndRoutingOptions(select, request);
    SqlElasticSearchRequestBuilder sqlElasticRequestBuilder =
        new SqlElasticSearchRequestBuilder(request);
    return sqlElasticRequestBuilder;
  }