[英]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()
是一个惰性操作,所以就像where
或select
等它不会执行/做任何事情,它只是添加到执行计划中。 它只会在您触发诸如count
或write
之类的操作时执行。
假设您有一个有效的用例,可以通过读取并写回 folder1 来复制folder1
中的数据(尽管令人费解)。 我会对以下选项更有信心:
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')
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.