All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.flink.table.plan.optimize.FlinkMiniBatchAnalyseProgram.scala Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.flink.table.plan.optimize

import org.apache.calcite.plan.hep.HepMatchOrder
import org.apache.calcite.rel.{RelNode, RelVisitor}
import org.apache.calcite.tools.RuleSets
import org.apache.flink.table.api.{TableConfig, TableConfigOptions, TableException}
import org.apache.flink.table.calcite.FlinkTypeFactory
import org.apache.flink.table.expressions.ExpressionUtils.{isRowtimeAttribute, isTimeIntervalLiteral}
import org.apache.flink.table.plan.logical.{SessionGroupWindow, SlidingGroupWindow, TumblingGroupWindow}
import org.apache.flink.table.plan.nodes.physical.stream._
import org.apache.flink.table.plan.rules.physical.stream.MiniBatchAssignerRules

import scala.collection.JavaConverters._

/**
  * A FlinkMiniBatchAnalyseProgram analyses MiniBatch configs through the entire rel tree, to
  * determine whether the to enable MiniBatch and the size of MiniBatch.
  */
class FlinkMiniBatchAnalyseProgram[OC <: OptimizeContext] extends FlinkOptimizeProgram[OC] {

  override def optimize(input: RelNode, context: OC): RelNode = {
    val config = context.getContext.unwrap(classOf[TableConfig])
    if (config.getConf.contains(TableConfigOptions.SQL_EXEC_MINIBATCH_ALLOW_LATENCY) &&
      config.getConf.getLong(TableConfigOptions.SQL_EXEC_MINIBATCH_ALLOW_LATENCY) > 0) {
      // step1: validation
      val validation = new MiniBatchValidation
      validation.go(input)

      // step2: add minibatch assigner node
      val hepProgram = FlinkHepRuleSetProgramBuilder
        .newBuilder[OC]
        .add(RuleSets.ofList(
          MiniBatchAssignerRules.UNARY,
          MiniBatchAssignerRules.BINARY,
          MiniBatchAssignerRules.UNION))
        .setHepRulesExecutionType(HEP_RULES_EXECUTION_TYPE.RULE_COLLECTION)
        .setHepMatchOrder(HepMatchOrder.TOP_DOWN)
        .build()

      hepProgram.optimize(input, context)
    } else {
      input
    }
  }

  /** The MiniBatchValidation will check whether Event-Time Node is in the query, otherwise
    * throw an unsupported exception.
    * In the future, we will support MiniBatch for EventTime Node */
  class MiniBatchValidation extends RelVisitor {
    override def visit(node: RelNode, ordinal: Int, parent: RelNode): Unit = {
      node match {
        case _: StreamExecWatermarkAssigner =>
          throw new TableException("MiniBatch is not supported when watermark is defined.")

        case w: StreamExecGroupWindowAggregate =>
          val isEventTime = w.window match {
            case TumblingGroupWindow(_, timeField, size)
              if isRowtimeAttribute(timeField) && isTimeIntervalLiteral(size) => true
            case SlidingGroupWindow(_, timeField, size, _)
              if isRowtimeAttribute(timeField) && isTimeIntervalLiteral(size) => true
            case SessionGroupWindow(_, timeField, _)
              if isRowtimeAttribute(timeField) => true
            case _ => false
          }
          if (isEventTime) {
            throw new TableException("MiniBatch is not supported when Window Aggregate is used.")
          }

        case m: StreamExecMatch =>
          val rowtimeFields = m.getInput.getRowType
            .getFieldList.asScala
            .filter(f => FlinkTypeFactory.isRowtimeIndicatorType(f.getType))
          // when the event-time field is set, the CEP node is event-time-mode
          if (rowtimeFields.nonEmpty) {
            throw new TableException("MiniBatch is not supported when Event-Time CEP is used.")
          }

        case wj: StreamExecWindowJoin =>
          if (wj.isRowTime) {
            throw new TableException(
              "MiniBatch is not supported when Event-Time WindowedJoin is used.")
          }

        case _ =>
          super.visit(node, ordinal, parent)
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy