@Override
  public Operator visitAlignedSeriesScan(
      AlignedSeriesScanNode node, LocalExecutionPlanContext context) {
    AlignedFullPath seriesPath =
        (AlignedFullPath) IFullPath.convertToIFullPath(node.getAlignedPath());

    SeriesScanOptions.Builder scanOptionsBuilder = getSeriesScanOptionsBuilder(context);
    scanOptionsBuilder.withAllSensors(
        new HashSet<>(
            context.isBuildPlanUseTemplate()
                ? context.getTemplatedInfo().getMeasurementList()
                : seriesPath.getMeasurementList()));

    Expression pushDownPredicate = node.getPushDownPredicate();
    boolean predicateCanPushIntoScan = canPushIntoScan(pushDownPredicate);
    if (pushDownPredicate != null && predicateCanPushIntoScan) {
      scanOptionsBuilder.withPushDownFilter(
          convertPredicateToFilter(
              pushDownPredicate,
              node.getAlignedPath().getMeasurementList(),
              context.getTypeProvider().getTemplatedInfo() != null,
              context.getTypeProvider(),
              context.getZoneId()));
    }
    if (pushDownPredicate == null || predicateCanPushIntoScan) {
      scanOptionsBuilder.withPushDownLimit(node.getPushDownLimit());
      scanOptionsBuilder.withPushDownOffset(node.getPushDownOffset());
    }

    OperatorContext operatorContext =
        context
            .getDriverContext()
            .addOperatorContext(
                context.getNextOperatorId(),
                node.getPlanNodeId(),
                AlignedSeriesScanOperator.class.getSimpleName());

    int maxTsBlockLineNum = TSFileDescriptor.getInstance().getConfig().getMaxTsBlockLineNumber();
    if (context.getTypeProvider().getTemplatedInfo() != null) {
      maxTsBlockLineNum =
          (int)
              Math.min(
                  context.getTypeProvider().getTemplatedInfo().getLimitValue(), maxTsBlockLineNum);
    }

    AlignedSeriesScanOperator seriesScanOperator =
        new AlignedSeriesScanOperator(
            operatorContext,
            node.getPlanNodeId(),
            seriesPath,
            node.getScanOrder(),
            scanOptionsBuilder.build(),
            node.isQueryAllSensors(),
            context.getTypeProvider().getTemplatedInfo() != null
                ? context.getTypeProvider().getTemplatedInfo().getDataTypes()
                : null,
            maxTsBlockLineNum);

    ((DataDriverContext) context.getDriverContext()).addSourceOperator(seriesScanOperator);
    ((DataDriverContext) context.getDriverContext()).addPath(seriesPath);
    context.getDriverContext().setInputDriver(true);

    if (!predicateCanPushIntoScan) {
      if (context.isBuildPlanUseTemplate()) {
        TemplatedInfo templatedInfo = context.getTemplatedInfo();
        return constructFilterOperator(
            pushDownPredicate,
            seriesScanOperator,
            templatedInfo.getProjectExpressions(),
            templatedInfo.getDataTypes(),
            templatedInfo.getFilterLayoutMap(),
            templatedInfo.isKeepNull(),
            node.getPlanNodeId(),
            templatedInfo.getScanOrder(),
            context);
      }

      AlignedPath alignedPath = node.getAlignedPath();
      List<Expression> expressions = new ArrayList<>();
      List<TSDataType> dataTypes = new ArrayList<>();
      for (int i = 0; i < alignedPath.getMeasurementList().size(); i++) {
        expressions.add(ExpressionFactory.timeSeries(alignedPath.getSubMeasurementPath(i)));
        dataTypes.add(alignedPath.getSubMeasurementDataType(i));
      }

      Operator rootOperator =
          constructFilterOperator(
              pushDownPredicate,
              seriesScanOperator,
              expressions.toArray(new Expression[0]),
              dataTypes,
              makeLayout(Collections.singletonList(node)),
              false,
              node.getPlanNodeId(),
              node.getScanOrder(),
              context);

      if (node.getPushDownOffset() > 0) {
        rootOperator =
            new OffsetOperator(
                context
                    .getDriverContext()
                    .addOperatorContext(
                        context.getNextOperatorId(),
                        node.getPlanNodeId(),
                        OffsetOperator.class.getSimpleName()),
                node.getPushDownOffset(),
                rootOperator);
      }
      if (node.getPushDownLimit() > 0) {
        rootOperator =
            new LimitOperator(
                context
                    .getDriverContext()
                    .addOperatorContext(
                        context.getNextOperatorId(),
                        node.getPlanNodeId(),
                        LimitOperator.class.getSimpleName()),
                node.getPushDownLimit(),
                rootOperator);
      }
      return rootOperator;
    }
    return seriesScanOperator;
  }
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