Apache Calcite官方文档中文版- 进阶-3. 流(Streaming)


  Calcite扩展了SQL和关系代数以支持流式查询。  流是收集到持续不断流动的记录,永远不停止。与表不同,它们通常不存储在磁盘上,而流是通过网络,并在内存中保存很短的时间。
  数据流是对表格的补充,因为它们代表了企业现在和将来发生的事情,而表格代表了过去。一个流被存档到一个表中是很常见的。
  与表一样,您经常希望根据关系代数以高级语言查询流,根据模式(schema)进行验证,并优化以充分利用可用的资源和算法。
  Calcite的SQL是对标准SQL的扩展,而不是另一种“类SQL”的语言。区别很重要,原因如下:  如果不使用STREAM关键字,则返回常规标准SQL。  流式SQL使用以下schema:  最简单的流式查询:  该查询读取Orders流中的所有列和行。与任何流式查询一样,它永远不会终止。只要记录到达,它就会输出一条记录Orders。
  输入Control-C以终止查询。
  STREAM关键字是SQL流的主要扩展。它告诉系统你对订单有兴趣,而不是现有订单。  查询:  也是有效的,但会打印出现有的所有订单,然后终止。我们把它称为关系查询,而不是流式处理。它具有传统的SQL语义。
  Orders很特殊,因为它有一个流和一个表。如果您尝试在表上运行流式查询或在流上运行关系式查询,则Calcite会抛出一个错误:  与常规的SQL中一样,使用一个WHERE子句来过滤行:  在SELECT子句中使用表达式来选择要返回或计算表达式的列:  我们建议您始终在SEL 香港云主机ECT条款中包含rowtime列。在每个流和流式查询中有一个有序的时间戳,可以在稍后进行高级计算,例如GROUP BY和JOIN。  有几种方法可以计算流上的聚合函数。差异是:  窗口类型:  结果是流。在11点整,Calcite发出自10点以来一直到11点有下订单的productId的小计。12点,它会发出11:00至12:00之间的订单。每个输入行只贡献到一个输出行。
  Calcite是如何知道10:00:00的小计在11:00:00完成的,这样就可以发出它们了?它知道rowtime是在增加,而且它也知道CEIL(rowtime TO HOUR)在增加。所以,一旦在11:00:00时间点或之后看到一行,它将永远不会看到贡献到上午10:00:00的一行。
  增加或减少的列以及表达式是单调的。(单调递增或单调递减)
  如果列或表达式的值具有轻微的失序,并且流具有用于声明特定值将不会再被看到的机制(例如标点符号或水印),则该列或表达式被称为准单调
  在GROUP BY子句中没有单调或准单调表达式的情况下,Calcite无法取得进展,并且不允许查询:  单调和准单调的列需要在模式中声明。当记录输入流并且由从该流中读取数据的假定查询时,单调性被强制执行。我们建议为每个流指定一个时间戳列rowtime,但也可以声明其他列是单调的,例如orderId。
  我们将在下面的内容讨论标点符号,水印,并取得进展的其他方法。  前面的滚动窗口的例子很容易写,因为窗口是一个小时。对于不是整个时间单位的时间间隔,例如2小时或2小时17分钟,则不能使用CEIL,表达式将变得更复杂。
  Calcite支持滚动窗口的替代语法:  正如你所看到的,它返回与前一个查询相同的结果。TUMBLE函数返回一个分组键,这个分组键在给定的汇总行中将会以相同的方式结束;TUMBLE_END函数采用相同的参数并返回该窗口的结束时间; 当然还有一个TUMBLE_START函数。
  TUMBLE有一个可选参数来对齐窗口。在以下示例中,我们使用30分钟间隔和0:12作为对齐时间,因此查询在每小时过去12分钟和42分钟时发出汇总:  跳转窗口是滚动窗口的泛化(概括),它允许数据在窗口中保持比发出间隔更长的时间。
  查询发出的行的时间戳11:00,包含数据从08:00至11:00(或10:59.9);以及行的时间戳12:00,包含数据从09:00至12:00。  在这个查询中,因为保留期是发出期的3倍,所以每个输入行都贡献到3个输出行。想象一下,HOP函数为传入行生成一组Group Keys,并将其值存储在每个Group Key的累加器中。例如,HOP(10:18:00, INTERVAL ‘1’ HOUR, INTERVAL ‘3’)产生3个时间间隔周期:
[08:00, 09:00)
[09:00, 10:00)
[10:00, 11:00)
  这就提出了允许不满意内置函数HOP和TUMBLE的用户来自定义的分区函数的可能性。
  我们可以建立复杂的复杂表达式,如指数衰减的移动平均线:发出:  GROUPING SETS对于流式查询是有效的,只要每个分组集合包含单调或准单调表达式。
  CUBE和ROLLUP不适用于流式查询,因为它们将生成至少一个聚合所有内容(如GROUP BY ())的分组集合。  与标准SQL一样,可以使用HAVING子句来过滤由流GROUP BY发出的行:  前述的HAVING查询可以使用WHERE子查询中的子句来表示:  HAVING子句是在SQL早期引入的,当需要在聚合之后执行过滤器时,(回想一下,WHERE在输入到达GROUP BY子句之前过滤行)。
  从那时起,SQL已经成为一种数学封闭的语言,这意味着您可以在一个表上执行的任何操作也可以在查询上执行。
  SQL的闭包属性非常强大。它不仅使HAVING陈旧过时(或至少减少到语法糖),它使视图成为可能:  FROM子句中的子查询有时被称为“内联视图”,但实际上它们比视图更基础。视图只是一个方便的方法,通过给出这些分片命名并将它们存储在元数据存储库中,将SQL分割成可管理的块。
  很多人发现嵌套的查询和视图在流上比在关系上更有用。流式查询是连续运行的运算符的管道,而且这些管道通常会很长。嵌套的查询和视图有助于表达和管理这些管道。
  顺便说一下,WITH子句可以完成与子查询或视图相同的操作:  回顾一下HourlyOrderTotals视图的定义。此视图是流还是关系?
  它不包含STREAM关键字,所以它是一个关系。但是,这是一种可以转换成流的关系。
  可以在关系和流式查询中使用它:  这种方法不限于视图和子查询。遵循CQL [1]中规定的方法,流式SQL中的每个查询都被定义为关系查询,并最上面的SELECT使用STREAM关键字转换为流。
  如果STREAM关键字存在于子查询或视图定义中,则不起作用。
  在查询准备时间,Calcite计算查询中引用的关系是否可以转换为流或历史的关系。
  有时候,一个流可以提供它的一些历史记录(比如Apache Kafka [2]主题中最后24小时的数据),但不是全部。在运行时,Calcite计算出是否有足够的历史记录来运行查询,如果没有,则会给出错误。  一个特定的情况下,需要将流转换为关系时会发生我所说的“饼图问题”。想象一下,你需要写一个带有图表的网页,如下所示,它总结了每个产品在过去一小时内的订单数量。

  但是这个Orders流只包含几条记录,而不是一个小时的汇总。我们需要对流的历史记录运行一个关系查询:  如果Orders流的历史记录正在滚动到Orders表中,尽管成本很高,我们可以回答查询。更好的办法是,如果我们可以告诉系统将一小时的汇总转化为表格,在流式处理过程中不断维护它,并自动重写查询以使用表格。  ORDER BY的故事类似于GROUP BY。语法看起来像普通的SQL,但是Calcite必须确保它能够提供及时的结果。因此,它需要在ORDER BY键的前沿(leading edge)有一个单调的表达式。  大多数查询将按照插入的顺序返回结果,因为引使用流式算法,但不应该依赖它。例如,考虑一下:  productId= 30的行显然是不符合order要求的,可能是因为Orders流以productId分区,分区后的流在不同的时间发送了他们的数据。
  如果您需要特定的顺序,请添加一个显式的ORDER BY:
  Calcite可能会通过合并使用rowtime实现UNION ALL,这样只是效率稍微低些。
只需要添加一个ORDER BY到最外层的查询。如果需要在UNION ALL之后执行GROUP BY,Calcite将会隐式添加ORDER BY,以便使GROUP BY算法成为可能。  VALUES子句创建一个拥有给定行集合的内联表。
  流式传输是不允许的。这组行不会发生改变,因此一个流永远不会返回任何行。  标准SQL的功能特性之一可以在SELECT子句中使用所谓的“分析函数”。不像GROUP BY,不会折叠记录。对于每个进来的记录,出来一个记录。但是聚合函数是基于一个多行的窗口。
  我们来看一个例子。  这个功能特性付出很小的努力就包含了很多Power。在SELECT子句中可以有多个函数,基于多个窗口规则定义。
  以下示例返回在过去10分钟内平均订单数量大于上周平均订单数量的订单。  为了简洁起见,在这里我们使用一种语法,其中使用WINDOW子句部分定义窗口,然后在每个OVER子句中细化窗口。也可以定义WINDOW子句中的所有窗口,或者如果您愿意,可以定义所有内联窗口。
  但真正的power超越语法。在幕后,这个查询维护着两个表,并且使用FIFO队列添加和删除子汇总中的值。但是,无需在查询中引入联接,也可以访问这些表。
窗口化聚合语法的一些其他功能特性:可以计算与顺序有关的函数,如RANK中位数。  如果我们想要一个返回每个记录的结果的查询,比如一个滑动窗口,但是在一个固定的时间段重置总数,就像一个翻滚的窗口?这种模式被称为级联窗口。这里是一个例子:  它看起来类似于滑动窗口查询,但单调表达式出现在PARTITION BY窗口的子句中。由于rowtime从10:59:59到11:00:00,FLOOR(rowtime TO HOUR)从10:00:00到11:00:00发生改变,因此一个新的分区开始。在新的时间到达的第一行将开始新的汇总;第二行将有一个由两行组成的汇总,依此类推。
  Calcite知道旧分区永远不会再被使用,因此从内部存储中删除该分区的所有子汇总。
  使用级联和滑动窗口的分析函数可以组合在同一个查询中。  有两种类型的连接,即stream-to-table join和stream-to-stream join。
  如果表的内容没有改变,则流到表的连接是直接的。这个查询以每个产品的列出价格丰富了订单流:  如果表格在改变,会发生什么?例如,假设product#10的单价在11点增加到0.35。在11:00之前下的订单应该是旧价格,在11:00之后下的订单应该反映新价格。
实现此目的的一种方法是创建一个表,使每个版本的开始和结束生效日期保持一致,ProductVersions如下所示:  另一种实现方法是使用具有临时支持的数据库(能够像过去的任何时候一样查找数据库的内容),并且系统需要知道Orders流的rowtime列对应于Products表的事务时间戳。
  对于许多应用程序而言,暂时支持或版本化表格的成本和努力是不值得的。查询在重放时给出不同的结果是可以接受的:在这个例子中,在重放时,product#10的所有订单被分配后来的单价0.35。  如果连接条件以某种方式强迫它们彼此保持有限的距离,那么流与流的连接就是合理的。在以下查询中,发货日期在订单日期的一小时内:  请注意,相当多的订单不会显示,因为它们在一个小时内没有发货。在系统接收到Order#10时,时间戳为11:24:11,它已经从其哈希表中删除了订单包括Order#8(时间戳10:18:07)。
  正如你所看到的,把这两个流的单调或准单调列联系在一起的“锁定步骤”是系统取得进展所必需的。如果它不能推断出一个锁定步骤, 它将拒绝执行一个查询。  这不仅是查询对流来说有意义。运行DML语句(INSERT,UPDATE,DELETE,UPSERT和REPLACE)对流来说同样有意义。
  DML非常有用,因为它允许基于流实现物华流或表格,因此经常使用值可以节省工作量。
  考虑到流的应用程序通常由查询管道组成,每个查询将输入流转换为输出流。管道的组件可以是一个视图:或者一个标准的INSERT语句:  这些看起来很相似,在这两种情况下,管道中的下一个步骤都可以读取LargeOrders,而不用担心它是如何填充的。效率是有差别的:INSERT无论有多少消费者,做的工作都是相同的。这个视图的确与消费者的数量成正比,特别是没有消费者的情况下就没有工作。
  其他形式的DML对于流也是有意义的。例如,以下常设UPSERT语句维护一个表格,以实现最后一小时订单的汇总:  Punctuation [5]允许流式查询取得进展,即使单调的键中没有足够的值来推送出结果。
  (我更喜欢术语“rowtime bounds”,水印[6]是一个相关的概念,但为了这些目的,Punctuation就足够了。)
  如果某个流具有Punctuation,那么它可能不会被排序,不过仍然可以排序。因此,出于语义的目的,按照排序的流来工作就足够了。
  顺便说一下,一个无序的流也是可排序的,如果按t-sorted排序(即,每个记录保证在其时间戳的t秒内到达)或k-sorted排序(即每个记录保证不超过k的位置造成无序)。所以对这些流的查询可以像带有Punctuation的流式查询来进行计划。
  而且,我们经常要聚合不是时间的且是单调的属性。“一个团队在获胜状态和失败状态之间转移的次数”就是这样一个单调的属性。系统需要自己弄清楚聚合这样一个属性是否安全;Punctuation不会添加任何额外的信息。  我记得一些计划器的元数据(成本指标):  并非本文中的所有概念都已经在Calcite中实现。其他的可能在Calcite中实现,但不能在SamzaSQL [3] [4]等特定的适配器中实现。
已实现 未实现
本文档中提供的以下功能特性,以为Calcite支持它们,但实际上它还没有实现。全面支持意味着参考实现支持该功能特性(包括负面情况),TCK则对其进行测试。   本文档做了什么  以下函数在标准SQL中不存在,但在流式SQL中定义。标量函数:分区函数:

相关推荐: win10系统鼠标右键卡顿怎么办

小编给大家分享一下win10系统鼠标右键卡顿怎么办,希望大家阅读完这 香港云主机篇文章之后都有所收获,下面让我们一起去探讨吧!1、按win+r打开运行窗口,输入refedit,回车即可。2、依次展开:HEKY_CLASSES_ROOTdirectoryback…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 07/24 11:13
下一篇 07/24 11:13

相关推荐