Flink-Table StreamTableEnvironment基础知识(三)

StreamTableEnvironment用于流计算场景,流计算的对象是DataStream。相比 TableEnvironment,StreamTableEnvironment 提供了 DataStream 和 Table 之间相互转换的接口,如果用户的程序除了使用 Table API & SQL 编写外,还需要使用到 DataStream API,则需要使用 StreamTableEnvironment。

一、数据流上的关系查询

Relational Algebra / SQL Stream Processing
关系(或表)是有界(多)元组集 流是元组的无限序列
对批处理数据(如关系数据库中的表)执行的查询可以访问完整的输入数据 流式查询在启动时无法访问所有数据,必须“等待”数据流式输入
批处理查询在生成固定大小的结果后终止 流式查询根据接收到的记录不断更新其结果,但从未完成

尽管存在这些差异,使用关系查询和SQL处理流并非不可能。高级关系数据库系统提供了一个称为物化视图的特性。物化视图被定义为SQL查询,就像普通的虚拟视图一样。与虚拟视图不同,物化视图缓存查询的结果,这样在访问视图时就不需要计算查询。缓存的一个常见挑战是防止缓存提供过时的结果。物化视图在其定义查询的基表被修改时变得过时。Eager View Maintenance是一种在更新基表后立即更新物化视图的技术。

如果我们考虑以下几点,那么Eager View Maintenance和对流的SQL查询之间的联系将变得显而易见:
    1、数据库表是INSERT,UPDATE和DELETEDML语句的一个结果流,通常被称为更新日志流。 
    2、物化视图定义为SQL查询。为了更新视图,查询会持续处理视图基本关系的更改日志流。
    3、物化视图是流式SQL查询的结果。

二、动态表是Flink对流数据的表API和SQL支持的核心概念。与表示批处理数据的静态表不同,动态表是随时间变化的。它们可以像静态批处理表一样进行查询。查询动态表会产生连续查询。连续查询永远不会终止,并因此生成动态表。查询不断更新其(动态)结果表,以反映其(动态)输入表上的更改。实际上,动态表上的连续查询与定义物化视图的查询非常相似。
需要注意的是,连续查询的结果在语义上始终等同于在输入表的快照上以批处理模式执行的同一查询的结果。
下图显示了流、动态表和连续查询的关系:

Flink-Table StreamTableEnvironment基础知识(三)

    1、流被转换为动态表。
    2、对动态表计算连续查询,生成新的动态表。
    3、生成的动态表被转换回流。

注:动态表首先是一个逻辑概念。在查询执行期间,动态表不一定(完全)具体化。

三、查询限制
    许多(但不是所有)语义有效的查询可以作为流上的连续查询进行计算。有些查询的计算成本太高,要么是因为它们需要维护的状态的大小,要么是因为计算更新的成本太高。
    1、状态大小:连续查询是在无边界的流上计算的,通常应该运行数周或数月。因此,连续查询处理的数据总量可能非常大。必须更新先前发出的结果的查询需要维护所有发出的行才能更新它们。例如,查询需要存储每个用户的URL计数,以便在输入表收到新行时增加计数并发送新结果。如果只跟踪注册用户,则要维护的计数可能不会太高。但是,如果未注册的用户分配了唯一的用户名,则要维护的计数将随着时间的推移而增加,并可能最终导致查询失败。
        SELECT user, COUNT(url)
        FROM clicks
        GROUP BY user;

    2、计算更新:一些查询需要重新计算和更新大部分发出的结果行,即使只添加或更新了一个输入记录。显然,这种查询不太适合作为连续查询执行。下面的查询就是一个例子,它根据最后一次单击的时间为每个用户计算一个排名。一旦clicks表接收到一个新行,用户的lastAction就会更新,并且必须计算一个新的排名。但是,由于两行不能具有相同的排名,所以所有排名较低的行也需要更新
        SELECT user, RANK() OVER (ORDER BY lastLogin)
        FROM (
          SELECT user, MAX(cTime) AS lastAction FROM clicks GROUP BY user
        );

四、表到流到转换
与常规数据库表一样,动态表可以通过插入、更新和删除更改进行连续修改。它可能是一个只有一行的表,该行是不断更新的,也可能是一个只插入而不更新和删除修改的表,或者介于两者之间的任何内容。将动态表转换为流或将其写入外部系统时,需要对这些更改进行编码。Flink的表API和SQL支持三种方式对动态表的更改进行编码:
    1、仅追加流(Append-only stream):仅通过插入更改修改的动态表可以通过发出插入的行转换为流。
    2、回收流(Retract stream):回收流是包含两类消息的流,添加消息和收回消息。动态表通过将INSERT change编码为add消息、DELETE change编码为retract消息、UPDATE change编码为updated(previous)行的retract消息和UPDATE(new)行的add消息转换为retract流。下图显示了将动态表转换为收缩流的过程。

Flink-Table StreamTableEnvironment基础知识(三)


    3、更新插入流(Upsert stream):upsert流是一种包含两种类型消息的流,包括Upsert消息和删除消息。 转换为upsert流的动态表需要(可能是复合的)唯一键。 通过将INSERT和UPDATE更改编码为upsert消息并将DELETE更改编码为删除消息,将具有唯一键的动态表转换为流。 流消耗运算符需要知道唯一键属性才能正确应用消息。 与回收流的主要区别在于UPDATE更改使用单个消息进行编码,因此更有效。 下图显示了动态表到upsert流的转换。

Flink-Table StreamTableEnvironment基础知识(三)

官方文档地址