繁体   English   中英

如何使用 Spark function 在包括根数据源的多个目标中插入完全相同的 dataFrame?

[英]How to insert exactly same dataFrame in multiple target including root datasource using Spark function?

我想从单个源读取数据,然后将其写回同一源,然后写入另一个源。

来源可以不同:HDFS、Mongo、Kafka...

通过本地测试,我有一个奇怪的行为。

这是我的第一个测试:我将数据保存在磁盘上而不是重新计算来自原始来源的数据:

Dataset<Row> rootDataframe = sparkSession
        .read()
        .option("header", true)
        .csv("folder1");

Dataset<Row> cachedDataFrame = rootDataframe.persist(StorageLevel.DISK_ONLY());

cachedDataFrame
        .write()
        .option("header", true)
        .mode(SaveMode.Append)
        .csv("folder1");

cachedDataFrame
        .write()
        .option("header", true)
        .mode(SaveMode.Overwrite)
        .csv("folder2");

cachedDataFrame.unpersist();

由于持久化 function,这并不像我预期的那样工作。缓存的数据在我第一次将其写回原始源时无效。 在我的文件夹 2 中,我得到了重复的数据(原始数据和我第一次操作写入的数据)。 这张 JIRA 票看起来像我的问题: https://issues.apache.org/jira/browse/SPARK-24596

但是,如果我不使用 persist,这会按我的意愿工作,我的第二次写操作不会受到第一次的影响。 我认为这是因为缓存没有失效并且元数据保持不变。

如果您查看物理计划,我认为即使我手动清理缓存也不会重新计算InMemoryFileIndex

== Physical Plan ==
*(1) FileScan csv [COUNTRY#10,CITY#11] Batched: false, Format: CSV, Location: InMemoryFileIndex[file:/D:/dev/Intellij-project/folder1, PartitionFilters: [], PushedFilters: [], ReadSchema: struct<COUNTRY:string,CITY:string>
Dataset<Row> rootDataframe = sparkSession
        .read()
        .option("header", true)
        .csv("folder1");

Dataset<Row> cachedDataFrame = rootDataframe
cachedDataFrame.explain(true);

cachedDataFrame
        .write()
        .option("header", true)
        .mode(SaveMode.Append)
        .csv("folder1");

sparkSession.sharedState().cacheManager().clearCache();

cachedDataFrame
        .write()
        .option("header", true)
        .mode(SaveMode.Overwrite)
        .csv("folder2");

但是这种行为与其他数据源不同,例如 MongoDB,如果我不持久化数据,数据将按预期重复,因为第二次写入操作将从第一次写入操作读取数据。

有没有办法在多个数据源中插入相同的数据,可能只使用 Spark 在不同的目标中包括根数据源?

使用 dataframe 持久化似乎是不可能的。 也许使用 dataframe 检查点? 或者我应该使用外部数据存储作为中间数据存储? 脏代码打破血统? 当然,我不能颠倒写入顺序,这是一个简化的例子,我可以有多个源写入同一个多个目标。

火花:2.4.4
Java 8

在 docs中找不到它,但 AFAIK persist()是一个惰性操作,所以就像whereselect等它不会执行/做任何事情,它只是添加到执行计划中。 它只会在您触发诸如countwrite之类的操作时执行。

假设您有一个有效的用例,可以通过读取并写回 folder1 来复制folder1中的数据(尽管令人费解)。 我会对以下选项更有信心:

  1. 改变顺序。 最后回写到folder1
df = spark.read.csv('folder1')
# changed order folder2 then 1
df.write.mode(SaveMode.Overwrite).csv('folder2')
df.write.mode(SaveMode.Append).csv('folder1')
  1. 制作folder1的副本(而不是persist() )并将其用作所有后续读取的源。
shutils.copy('folder1', 'folder1_copy')
# OR spark.read.csv('folder1').write.csv('folder1_copy')
df = spark.read.csv('folder1_copy')
# original order folder1 then 2
df.write.mode(SaveMode.Append).csv('folder1')
df.write.mode(SaveMode.Overwrite).csv('folder2')
暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2023 STACKOOM.COM