Delta Lake:上贴如何在内部起作用?

时间:2019-12-25 09:18:33

标签: apache-spark databricks delta-lake

在数据管道中,我们从数据源中提取CDC事件,并将这些更改以AVRO格式写入“增量数据”文件夹中。

然后,我们定期运行Spark作业,以将此“增量数据”与当前版本的“快照表”(ORC格式)合并,以获取最新版本的上游快照。

在此合并逻辑中:

1)我们将“增量数据”加载为DataFrame df1

2)将当前的“快照表”加载为DataFrame df2

3)合并df1和df2重复数据删除ID,并获取行的最新版本(使用update_timestamp列)

此逻辑将“增量数据”和当前“快照表”的全部数据加载到Spark内存中,具体取决于数据库。

我注意到在Delta Lake中,使用以下代码完成了类似的操作:

import io.delta.tables._
import org.apache.spark.sql.functions._

val updatesDF = ...  // define the updates DataFrame[date, eventId, data]

DeltaTable.forPath(spark, "/data/events/")
  .as("events")
  .merge(
    updatesDF.as("updates"),
    "events.eventId = updates.eventId")
  .whenMatched
  .updateExpr(
    Map("data" -> "updates.data"))
  .whenNotMatched
  .insertExpr(
    Map(
      "date" -> "updates.date",
      "eventId" -> "updates.eventId",
      "data" -> "updates.data"))
  .execute()

在这里,“ updatesDF”可以看作是我们来自CDC来源的“增量数据”。

我的问题

1)合并/向上插入在内部如何工作?是否会将整个“ updatedDF”和“ / data / events /”加载到Spark内存中?

2)如果不是,是否应用与Apache Hudi类似的增量更改?

3)在重复数据删除期间,此upsert逻辑如何知道获取记录的最新版本?因为我看不到用于指定“更新时间戳”列的任何设置?

1 个答案:

答案 0 :(得分:1)

   1) How does merge/upsert internally works? Does it load entire "updatedDF" and 
   "/data/events/" into Spark memory?

不是,Spark不需要将需要更新的整个Delta DF加载到内存中。 否则它将无法扩展。 它采取的方法与Spark所做的其他工作非常相似-如果数据集足够大(或者您通过云创建显式分区),整个表将透明地分为多个分区。然后,为每个分区分配一个组成您的merge作业的任务。任务可以在不同的Spark执行器等上运行。

   2) If not, does it apply the delta changes something similar to Apache Hudi ?

我听说过Apache Hudi,但没有看过。 在内部,Delta看起来像版本镶木地板文件。 对表的更改按有序的原子单位(称为提交)存储。 保存表格时-查看其具有的文件-它将具有文件 例如000000.json,000001.json等,并且它们每个都会引用一个 子目录中基础镶木地板文件上的一组操作。例如, 000000.json会说该版本及时引用了实木复合地板文件001 和002,以及000001.json会说该版本不应及时引用 这两个旧的实木复合地板文件,并且仅使用实木复合地板文件003。

   3) During deduplication how this upsert logic knows to take the latest version of a record? 
Because I don't see any setting to specify the "update timestamp" column?

默认情况下,它引用最新的变更集。 时间戳记是Delta中如何实施此版本控制的内部内容。 您可以通过AS OF语法引用较早的快照-请参阅 https://docs.databricks.com/delta/delta-batch.html#syntax