DataStream算子转换过程

DataStream表示为同一种类型的数据流,用来描述业务转换逻辑。通过转换操作,一个DataStream可以被转换成另一个新的DataStream。

DataStream中有2个成员变量:

// 流程序执行的上下文环境
protected final StreamExecutionEnvironment environment;

// 当前DataStream的上一次转换操作(存于StreamExecutionEnvironment的List集合中)
// 即:通过该Transformation,生成当前的DataStream
protected final Transformation<T> transformation;

transformation是当前DataStream的上一次转换操作,得益于transformation,才能转换出当前DataStream。每当调用算子进行转换操作都会产生对应的xxxTransformation,StreamExecutionEnvironment会将这个xxxTransformation添加到List<Transformation<?>>集合中,以便用来构建Pipeline拓扑。(流式作业对应的Pipeline实现类是StreamGraph,批作业对应的Pipeline实现类是Plan)

例如使用DataStream.map()转换时,会在内部创建生成StreamMap算子,同时会把MapFunction对象传入,MapFunction就是我们的数据处理逻辑。StreamMap算子就是AbstractUdfStreamOperator的子类,传入的MapFunction对象会赋值给AbstractUdfStreamOperator中的userFunction变量持有。如此一来,StreamMap算子就持有了MapFunction。

– 底层对应的就是OneInputTransformation转换:

/**
 * 将MapFunction作为参数传入
 */
streamMap.map(new MapFunction<String, JSONObject>() {...});

public <R> SingleOutputStreamOperator<R> map(MapFunction<T, R> mapper) {
    // 获取本次map转换的输出类型
    TypeInformation<R> outType = TypeExtractor.getMapReturnTypes(clean(mapper), getType(),
                                                                 Utils.getCallLocationName(), true);
    return map(mapper, outType);
}

/**
 * 自定义的MapFunction会作为参数,用来构建StreamMap,即StreamOperator的子类
 */
public <R> SingleOutputStreamOperator<R> map(MapFunction<T, R> mapper, TypeInformation<R> outputType) {
    // 参数:算子name,输出类型,StreamOperator的factory
    return transform("Map", outputType, new StreamMap<>(clean(mapper)));
}

有了StreamMap算子和代表数据处理逻辑的MapFunction之后,算子name、本次转换的输出类型、StreamMap算子会作为参数,参与本次的转换:

@PublicEvolving
public <R> SingleOutputStreamOperator<R> transform(
    String operatorName, // outTypeInfo:当前算子的输出类型
    TypeInformation<R> outTypeInfo, // 本次转换的输出类型
    // StreamMap算子继承AbstractUdfStreamOperator,实现OneInputStreamOperator接口
    OneInputStreamOperator<T, R> operator) {

    // SimpleOperatorFactory.of(operator):根据StreamOperator的类型,创建StreamOperatorFactory
    return doTransform(operatorName, outTypeInfo, SimpleOperatorFactory.of(operator));
}

protected <R> SingleOutputStreamOperator<R> doTransform(
    String operatorName,
    TypeInformation<R> outTypeInfo,
    // StreamOperatorFactory:创建StreamOperator的工厂
    StreamOperatorFactory<R> operatorFactory) {

    // 保险起见,确保不会出现InvalidTypesException,保证本次的转换操作不会出问题
    transformation.getOutputType();

    // 创建本次转换所对应的xxxTransformation实例
    OneInputTransformation<T, R> resultTransform = new OneInputTransformation<>(
        this.transformation, // 上一次的Transformation转换操作
        operatorName, // 当前算子的name
        operatorFactory, // MapFunction-->StreamMap -->StreamOperatorFactory
        outTypeInfo, // 当前算子的输出类型
        // 当前算子的并行度,默认为env全局的并行度
        environment.getParallelism());

    // SingleOutputStreamOperator:每次转换操作完毕后,返回给开发者继续操作的数据结构
    @SuppressWarnings({"unchecked", "rawtypes"})
    SingleOutputStreamOperator<R> returnStream = new SingleOutputStreamOperator(environment, resultTransform);

    // 将这个xxxTransformation添加到List<Transformation>列表中,它会被用来生成StreamGraph
    getExecutionEnvironment().addOperator(resultTransform);

    return returnStream;
}

转换时,首先要确保不会出现InvalidTypesException,不然后面的转换就会出问题。StreamOperatorFactory持有StreamMap算子(也就是StreamOperator),StreamMap持有MapFunction。现在要根据StreamOperatorFactory来创建OneInputTransformation,换言之,MapFunction、StreamMap算子都会被封装到这个OneInputTransformation中。当然,也会创建出SingleOutputStreamOperator,作为本次转换结束之后返回给开发者继续操作的数据结构,下游算子可以用它继续进行转换操作。

SingleOutputStreamOperator的本质就是DataStream,在构建它时会调用父类DataStream的构造方法,将这个StreamMap对应的OneInputTransformation赋值给DataStream的成员变量。对于“下一个StreamOperator”而言,它自然就成了所谓的“上一次Transformation”

public DataStream(StreamExecutionEnvironment environment, Transformation<T> transformation) {
		this.environment = Preconditions.checkNotNull(environment, "Execution Environment must not be null.");
		/**
		 * 调用DataStream提供的转换方法来生成对应的StreamOperator后,会根据这个StreamOperator来创建对应的Transformation、返回给开发者继续使用的SingleOutputStreamOperator。
		 * SingleOutputStreamOperator的本质就是DataStream,在构建SingleOutputStreamOperator时就会调用DataStream(父类)的构造,
		 * 将本次转换操作对应的Transformation交给DataStream的成员变量持有,它自然就成了“下一个转换”的上一次Transformation
		 */
		this.transformation = Preconditions.checkNotNull(transformation, "Stream Transformation must not be null.");
	}

map转换生成的OneInputTransformation,会被add到StreamExecutionEnvironment内的 List<Transformation<?>>集合中,后续会根据这个List集合来生成StreamGraph(即用来描述业务处理逻辑的Pipeline)。

在DataStream的转换过程中,不管是哪种类型的转换操作,都是按照以下的程序进行的:

  • 将开发者自定义的xxxFunction封装到(对应)创建好的StreamOperator中
  • 基于StreamOperator构建xxxTransformation
  • 将xxxTransformation添加到StreamExecutionEnvironment的List集合中,用来生成StreamGraph
  • 基于StreamGraph,先后生成JobGraph、ExecutionGraph,申请Slot资源并调度、执行…

Transformation持有StreamOperatorFactory,StreamOperatorFactory持有StreamOperator,StreamOperator持有xxxFunction。正是因为这种持有关系,Transformation才能表达DataStream之间的转换关系,因为xxxFunction中定义的就是数据处理逻辑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值