@Override
  public Operator visitGroupByLevel(GroupByLevelNode node, LocalExecutionPlanContext context) {
    checkArgument(
        !node.getGroupByLevelDescriptors().isEmpty(),
        "GroupByLevel descriptorList cannot be empty");
    List<Operator> children = dealWithConsumeAllChildrenPipelineBreaker(node, context);
    boolean ascending = node.getScanOrder() == ASC;
    List<TreeAggregator> aggregators = new ArrayList<>();
    Map<String, List<InputLocation>> layout = makeLayout(node);
    List<CrossSeriesAggregationDescriptor> aggregationDescriptors =
        node.getGroupByLevelDescriptors();
    for (CrossSeriesAggregationDescriptor descriptor : aggregationDescriptors) {
      List<InputLocation[]> inputLocationList = calcInputLocationList(descriptor, layout);
      // Use the first set of InputExpression
      List<TSDataType> inputDataTypes =
          IntStream.range(0, descriptor.getExpressionNumOfOneInput())
              .mapToObj(
                  x ->
                      context
                          .getTypeProvider()
                          .getTreeModelType(
                              descriptor.getInputExpressions().get(x).getExpressionString()))
              .collect(Collectors.toList());
      aggregators.add(
          new TreeAggregator(
              AccumulatorFactory.createAccumulator(
                  descriptor.getAggregationFuncName(),
                  descriptor.getAggregationType(),
                  inputDataTypes,
                  descriptor.getInputExpressions(),
                  descriptor.getInputAttributes(),
                  ascending,
                  descriptor.getStep().isInputRaw()),
              descriptor.getStep(),
              inputLocationList));
    }
    OperatorContext operatorContext =
        context
            .getDriverContext()
            .addOperatorContext(
                context.getNextOperatorId(),
                node.getPlanNodeId(),
                AggregationOperator.class.getSimpleName());

    GroupByTimeParameter groupByTimeParameter = node.getGroupByTimeParameter();
    ITimeRangeIterator timeRangeIterator =
        initTimeRangeIterator(groupByTimeParameter, ascending, false, context.getZoneId());
    long maxReturnSize =
        calculateMaxAggregationResultSize(
            aggregationDescriptors, timeRangeIterator, context.getTypeProvider());

    return new AggregationOperator(
        operatorContext, aggregators, timeRangeIterator, children, false, maxReturnSize);
  }
This Visitor is responsible for transferring PlanNode Tree to Operator Tree.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java