简单回顾
在前面的章节里,我们讨论了Delta将一切数据操作都抽象为文件的增加和删除,并且将增加和删除的动作记录到日志里(_delta_log),并且我们也探秘了Detla的目录结构,很简单根目录是数据目录,可能有分区可能没有,根目录里还有个特殊的目录_delta_log,里面是json文件,记录了每次commit产生的动作。
流批共享表
Delta的一大特点就是流批都可以对表进行写入和读取。通常而言,流写批读是最常见的场景,也存在流读流写的情况。一个比较典型的场景是我们消费Kafka的日志,然后写入到delta里,接着我们可能会利用这个表进行交互式查询或者用于制作报表,这是一个典型的流写批读的场景。
如何实现流批共享表
当流式写入Delta常见的无非就三种可能:
- Upsert操作
- 纯新增操作
- 覆盖操作
当然可能还会存在更复杂的类型,我们需要单独探讨。在这里,对于纯新增操作,是最简单的,和批没有任何区别,就是将新记录转化为新的Parquet文件写入到Delta即可。Upsert语义表示记录存在就更新,否则新增,我们通过Delta的内部机制可以将其转化为文件删除和新增动作。覆盖操作则是删除当前所有文件,然后新增文件。得益于Spark的微批模式,流式写入就是每个周期进行如上的操作,每个周期是一个commit. 而批则是一次写入一个commit。
流读Delta表是什么概念
其实就是讲Delta表当成了一个流的数据源。通常比如消息队列是典型的流程序数据源,他们的特点都是只增。所以Delta目前也只能做到纯新增表作为流数据源。因为写入端每次新增的commit都是纯增加文件,所以读的时候,只要相应的读取新增的N个commit涉及到的文件,将里面的记录作为新增的数据即可。
那为什么如果有upsert/delete/overwrite操作则不可以呢?很简单,大家想想,如果发生了upsert/delete/overwrite操作,请问你的流程序即使获取了这些信息,该如何进行操作呢?显然是很困难的。如果要追踪这些记录的变更,也是可以做到的,有点类似binlog。 所以目前Delta只支持纯新增数据的表作为流的数据源。
流批共享的好处
流批共享才是真的王道,因为我们大部分业务场景都是流写批读,比如讲MySQL的数据增量同步到Delta,然后无论ETL,交互式查询,报表都是批读。所以,后面我们提到的更新删除等等,其实都同时适用于流和批操作。