从RDBMS加载数据并写入Parquet

时间:2018-03-16 22:03:50

标签: scala apache-spark apache-spark-sql

我正在尝试实现一个管道,用于从RDBMS数据源读取数据,在日期时间字段上对读取进行分区,以及将数据分区数据存储在镶木地板中。

该管道旨在每周运行,每次运行只是将已添加到RDBMS源的任何新行附加到分区的拼花数据。

目前,我处理此问题的方式是:

1)存储上一次摄取时间。

2)从RDBMS读取并在上一次摄取之后的日期时间列上应用过滤器。

3)将此数据附加到分区的镶木地板文件中。

虽然这有效,但我不确定它是否是最常用的处理可能是一个非常常见的用例的方法。同样,除非我想允许行重复,否则必须对已经写入的数据进行一些额外的按摩。

此管道的一个示例是:

// rdbms is an object which stores various connection information for an RDBMS.
// dateCol is the column name of the datetime column.
// path is the parquet file path.
val yearCol = "year"
val monthCol = "month"
val dayCol = "day"
val refreshDF = spark.read
          .format("jdbc")
          .option("url", rdbms.connectionString + "/" + rdbms.database)
          .option("dbtable", rdbms.table)
          .option("user", rdbms.userName)
          .option("password", rdbms.password)
          .option("driver", rdbms.driverClass)
          .option("header", true)
          .option("readOnly", true)
          .load()
val ts = unix_timestamp(col(dateCol), dateFormat).cast("timestamp")
val unixDateCol = dateCol + "_unix"
val datedDF = refreshDF.withColumn(unixDateCol, ts)
val filteredDF = datedDF.filter(col(unixDateCol).lt(lastRun))
val ymdDF = filteredDF.withColumn(yearCol, year(col(unixDateCol)))
    .withColumn(monthCol, month(col(unixDateCol)))
    .withColumn(dayCol, day(col(unixDateCol)))
ymdDF.write.mode("append").partitionBy(yearCol, monthCol, dayCol).parquet(path)

有更好的方法吗?我想避免阅读整个表格,并出于性能原因计算差异。

(编辑:在分区中添加,但由于此传递不会删除最新的读取,因此不会利用它。)

1 个答案:

答案 0 :(得分:1)

不是每次都从DB读取所有数据,而是可以通过'predicates'参数将时间戳字段过滤器传递给DB端,以便只返回您感兴趣的数据范围的数据。在大型表的情况下,如果时间戳在数据库端被索引和/或分区,则速度要快得多。以下是相关方法:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="charl">
  <li>Foo</li>
</ul>

至于确保数据不重复,您可以从拼花文件中查询每天的记录数,例如过去几周查找最早的日期,其中有0条记录为“上次摄取时间” 。这将消除该日期与镶木地板数据不同步的可能性。