@Override
  public Operator visitPatternRecognition(
      PatternRecognitionNode node, LocalExecutionPlanContext context) {
    OperatorContext operatorContext =
        context
            .getDriverContext()
            .addOperatorContext(
                context.getNextOperatorId(),
                node.getPlanNodeId(),
                PatternRecognitionOperator.class.getSimpleName());

    Operator child = node.getChild().accept(this, context);

    Map<Symbol, Integer> childLayout =
        makeLayoutFromOutputSymbols(node.getChild().getOutputSymbols());

    List<Symbol> partitionBySymbols = node.getPartitionBy();
    List<Integer> partitionChannels =
        ImmutableList.copyOf(getChannelsForSymbols(partitionBySymbols, childLayout));

    List<Integer> sortChannels = ImmutableList.of();
    List<SortOrder> sortOrder = ImmutableList.of();

    if (node.getOrderingScheme().isPresent()) {
      OrderingScheme orderingScheme = node.getOrderingScheme().get();
      sortChannels = getChannelsForSymbols(orderingScheme.getOrderBy(), childLayout);
      sortOrder = orderingScheme.getOrderingList();
    }

    // The output order for pattern recognition operation is defined as follows:
    // - for ONE ROW PER MATCH: partition by symbols, then measures,
    // - for ALL ROWS PER MATCH: partition by symbols, order by symbols, measures, remaining input
    // symbols.

    // all output column types of the input table
    List<TSDataType> inputDataTypes =
        getOutputColumnTypes(node.getChild(), context.getTypeProvider());

    // input channels to be passed directly to output, excluding MEASURES columns
    ImmutableList.Builder<Integer> outputChannels = ImmutableList.builder();
    // output dataTypes, used to construct the output TsBlock, including MEASURES columns
    ImmutableList.Builder<TSDataType> outputDataTypes = ImmutableList.builder();

    if (node.getRowsPerMatch() == ONE) {
      // ONE ROW PER MATCH: partition columns, MEASURES

      // add all partition columns
      outputChannels.addAll(partitionChannels);
      for (int i = 0; i < partitionBySymbols.size(); i++) {
        Symbol symbol = partitionBySymbols.get(i);
        // obtain the absolute index of the symbol in the base table through `childLayout`
        outputDataTypes.add(inputDataTypes.get(childLayout.get(symbol)));
      }
    } else {
      // ALL ROWS PER MATCH: all input columns, MEASURES

      outputChannels.addAll(
          IntStream.range(0, inputDataTypes.size()).boxed().collect(toImmutableList()));
      outputDataTypes.addAll(inputDataTypes);
    }

    // add MEASURES columns
    for (Map.Entry<Symbol, Measure> measure : node.getMeasures().entrySet()) {
      outputDataTypes.add(getTSDataType(measure.getValue().getType()));
    }

    // prepare structures specific to PatternRecognitionNode
    // 1. establish a two-way mapping of IrLabels to `int`
    List<IrLabel> primaryLabels = ImmutableList.copyOf(node.getVariableDefinitions().keySet());
    ImmutableList.Builder<String> labelNamesBuilder = ImmutableList.builder();
    ImmutableMap.Builder<IrLabel, Integer> mappingBuilder = ImmutableMap.builder();
    for (int i = 0; i < primaryLabels.size(); i++) {
      IrLabel label = primaryLabels.get(i);
      labelNamesBuilder.add(label.getName());
      mappingBuilder.put(label, i);
    }
    Map<IrLabel, Integer> mapping = mappingBuilder.buildOrThrow();
    List<String> labelNames = labelNamesBuilder.build();

    // 2. rewrite pattern to program
    Program program = IrRowPatternToProgramRewriter.rewrite(node.getPattern(), mapping);

    // 3. DEFINE: prepare patternVariableComputation (PatternVariableRecognizer is to be
    // instantiated once per partition)
    ImmutableList.Builder<PatternVariableRecognizer.PatternVariableComputation> evaluationsBuilder =
        ImmutableList.builder();

    for (Map.Entry<IrLabel, ExpressionAndValuePointers> entry :
        node.getVariableDefinitions().entrySet()) {
      String variableName = entry.getKey().getName();
      ExpressionAndValuePointers expressionAndValuePointers = entry.getValue();

      // convert the `ValuePointer` in the `Assignment` to `PhysicalValueAccessor`
      List<PhysicalValueAccessor> valueAccessors = new ArrayList<>();
      for (ExpressionAndValuePointers.Assignment assignment :
          expressionAndValuePointers.getAssignments()) {
        ValuePointer pointer = assignment.getValuePointer();
        if (pointer instanceof MatchNumberValuePointer) {
          valueAccessors.add(
              new PhysicalValuePointer(MATCH_NUMBER, INT64, LogicalIndexNavigation.NO_OP));
        } else if (pointer instanceof ClassifierValuePointer) {
          ClassifierValuePointer classifierPointer = (ClassifierValuePointer) pointer;
          valueAccessors.add(
              new PhysicalValuePointer(
                  CLASSIFIER,
                  STRING,
                  classifierPointer.getLogicalIndexPointer().toLogicalIndexNavigation(mapping)));
        } else if (pointer instanceof ScalarValuePointer) {
          ScalarValuePointer scalarPointer = (ScalarValuePointer) pointer;
          valueAccessors.add(
              new PhysicalValuePointer(
                  getOnlyElement(
                      getChannelsForSymbols(
                          ImmutableList.of(scalarPointer.getInputSymbol()), childLayout)),
                  context.getTypeProvider().getTableModelType(scalarPointer.getInputSymbol()),
                  scalarPointer.getLogicalIndexPointer().toLogicalIndexNavigation(mapping)));
        }
      }

      // transform the symbolic expression tree in the logical planning stage into a parametric
      // expression tree
      Computation computation =
          Computation.ComputationParser.parse(expressionAndValuePointers.getExpression());

      // construct a `PatternVariableComputation` object, where valueAccessors is a parameter list
      // and computation is a parametric expression tree, encapsulating the computation logic
      PatternVariableRecognizer.PatternVariableComputation patternVariableComputation =
          new PatternVariableRecognizer.PatternVariableComputation(
              valueAccessors, computation, labelNames);

      evaluationsBuilder.add(patternVariableComputation);
    }

    // 4. MEASURES: prepare measures computations
    ImmutableList.Builder<PatternExpressionComputation> measureComputationsBuilder =
        ImmutableList.builder();

    for (Measure measure : node.getMeasures().values()) {
      ExpressionAndValuePointers expressionAndValuePointers =
          measure.getExpressionAndValuePointers();

      // convert the `ValuePointer` in the `Assignment` to `PhysicalValueAccessor`
      List<PhysicalValueAccessor> valueAccessors = new ArrayList<>();
      for (ExpressionAndValuePointers.Assignment assignment :
          expressionAndValuePointers.getAssignments()) {
        ValuePointer pointer = assignment.getValuePointer();
        if (pointer instanceof MatchNumberValuePointer) {
          valueAccessors.add(
              new PhysicalValuePointer(MATCH_NUMBER, INT64, LogicalIndexNavigation.NO_OP));
        } else if (pointer instanceof ClassifierValuePointer) {
          ClassifierValuePointer classifierPointer = (ClassifierValuePointer) pointer;
          valueAccessors.add(
              new PhysicalValuePointer(
                  CLASSIFIER,
                  STRING,
                  classifierPointer.getLogicalIndexPointer().toLogicalIndexNavigation(mapping)));
        } else if (pointer instanceof ScalarValuePointer) {
          ScalarValuePointer scalarPointer = (ScalarValuePointer) pointer;
          valueAccessors.add(
              new PhysicalValuePointer(
                  getOnlyElement(
                      getChannelsForSymbols(
                          ImmutableList.of(scalarPointer.getInputSymbol()), childLayout)),
                  context.getTypeProvider().getTableModelType(scalarPointer.getInputSymbol()),
                  scalarPointer.getLogicalIndexPointer().toLogicalIndexNavigation(mapping)));
        }
      }

      // transform the symbolic expression tree in the logical planning stage into a parametric
      // expression tree
      Computation computation =
          Computation.ComputationParser.parse(expressionAndValuePointers.getExpression());

      // construct a `PatternExpressionComputation` object, where valueAccessors is a parameter
      // list
      // and computation is a parametric expression tree, encapsulating the computation logic
      PatternExpressionComputation measureComputation =
          new PatternExpressionComputation(valueAccessors, computation);

      measureComputationsBuilder.add(measureComputation);
    }

    // 5. prepare SKIP TO navigation
    Optional<LogicalIndexNavigation> skipToNavigation = Optional.empty();
    if (!node.getSkipToLabels().isEmpty()) {
      boolean last = node.getSkipToPosition().equals(LAST);
      skipToNavigation =
          Optional.of(
              new LogicalIndexPointer(node.getSkipToLabels(), last, false, 0, 0)
                  .toLogicalIndexNavigation(mapping));
    }

    return new PatternRecognitionOperator(
        operatorContext,
        child,
        inputDataTypes,
        outputDataTypes.build(),
        outputChannels.build(),
        partitionChannels,
        sortChannels,
        node.getRowsPerMatch(),
        node.getSkipToPosition(),
        skipToNavigation,
        new Matcher(program),
        evaluationsBuilder.build(),
        measureComputationsBuilder.build(),
        labelNames);
  }
This Visitor is responsible for transferring Table PlanNode Tree to Table Operator Tree.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/TableOperatorGenerator.java