@Override
  public Operator visitRegionMerge(
      ActiveRegionScanMergeNode node, LocalExecutionPlanContext context) {
    List<Operator> operatorList =
        node.getChildren().stream()
            .map(child -> child.accept(this, context))
            .filter(Objects::nonNull)
            .collect(Collectors.toList());
    OperatorContext operatorContext =
        context
            .getDriverContext()
            .addOperatorContext(
                context.getNextOperatorId(),
                node.getPlanNodeId(),
                ActiveRegionScanMergeOperator.class.getName());

    List<TSDataType> dataTypes;
    if (node.isOutputCount()) {
      dataTypes = new ArrayList<>(Collections.singleton(TSDataType.INT64));
    } else {
      dataTypes =
          generateRepeatTsDataType(
              node.getChildren().get(0).getOutputColumnNames().size(), TSDataType.TEXT);
    }
    return new ActiveRegionScanMergeOperator(
        operatorContext,
        operatorList,
        dataTypes,
        node.isOutputCount(),
        node.isNeedMerge(),
        node.getEstimatedSize());
  }
Now, we allocate children to each pipeline as average as possible. For example, 5 children with
3 dop, the children group will be [1, 2, 2]. After we can estimate the workload of each
operator, maybe we can allocate based on workload rather than child number.

<p>If child is ExchangeNode, it won't affect the children number of current group.

<p>This method can only be invoked when dop <= localChildrenSize.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java