我在MySQL中有一个test
表,其ID和名称如下所示:
+----+-------+
| id | name |
+----+-------+
| 1 | Name1 |
+----+-------+
| 2 | Name2 |
+----+-------+
| 3 | Name3 |
+----+-------+
我使用Spark DataFrame
来读取这些数据(使用JDBC)并修改这样的数据
Dataset<Row> modified = sparkSession.sql("select id, concat(name,' - new') as name from test");
modified.write().mode("overwrite").jdbc(AppProperties.MYSQL_CONNECTION_URL,
"test", connectionProperties);
但我的问题是,如果我提供覆盖模式,它会丢弃上一个表并创建一个新表但不插入任何数据。
我通过读取csv文件(与测试表相同的数据)和覆盖来尝试相同的程序。这对我有用。
我在这里遗漏了什么吗?
谢谢!
答案 0 :(得分:8)
问题在于您的代码。因为您覆盖了一个您尝试读取的表,所以在Spark实际访问之前,您会有效地删除所有数据。
请记住,Spark是懒惰的。创建Dataset
Spark时,会获取所需的元数据,但不会加载数据。因此,没有魔法缓存可以保留原始内容。实际需要时将加载数据。这是当你执行write
动作时,当你开始写作时,没有更多的数据可以被提取。
你需要的是这样的东西:
Dataset
。应用所需的转换并将数据写入中间MySQL表。
TRUNCATE
来自中间表的原始输入和INSERT INTO ... SELECT
或DROP
原始表和RENAME
中间表。
替代但不太有利的方法是:
Dataset
。df.write.saveAsTable(...)
或等效的)TRUNCATE
原始输入。spark.table(...).write.jdbc(...)
)我们不能强调使用Spark cache
/ persist
是不可能的。即使使用保守的StorageLevel
(MEMORY_AND_DISK_2
/ MEMORY_AND_DISK_SER_2
),缓存的数据也可能会丢失(节点失败),从而导致无声的正确性错误。
答案 1 :(得分:1)
我认为上述所有步骤都是不必要的。这是您需要做的:
创建数据集A
,例如val A = spark.read.parquet("....")
以数据帧B
的形式读取要更新的表。确保为数据帧B
启用了启用缓存。 val B = spark.read.jdbc("mytable").cache
在count
上强制使用B
-这将强制执行并根据所选的StorageLevel
-B.count
现在,您可以进行类似val C = A.union(B)
然后,将C
像C.write.mode(SaveMode.Overwrite).jdbc("mytable")
答案 2 :(得分:0)
读取和写入同一张表。
cols_df = df_2.columns
broad_cast_var = spark_context.broadcast(df_2.collect())
df_3 = sqlContext.createDataFrame(broad_cast_var.value, cols_df)
在相同的表上进行读写操作。
cols_df = df_2.columns
broad_cast_var = spark_context.broadcast(df_2.collect())
def update_x(x):
y = (x[0] + 311, *x[1:])
return y
rdd_2_1 = spark_context.parallelize(broad_cast_var.value).map(update_x)
df_3 = sqlContext.createDataFrame(rdd_2_1, cols_df)