我在Spark中有一个要求,我需要从mysql实例中获取数据,经过一些处理后,需要从不同的mysql数据库中获取更多数据。
但是,当我尝试从地图功能中再次访问数据库时,我得到了一个
org.apache.spark.SparkException: Task not serializable
org.apache.spark.util.ClosureCleaner$.ensureSerializable(ClosureCleaner.scala:298)
org.apache.spark.util.ClosureCleaner$.org$apache$spark$util$ClosureCleaner$$clean(ClosureCleaner.scala:288)
org.apache.spark.util.ClosureCleaner$.clean(ClosureCleaner.scala:108)
org.apache.spark.SparkContext.clean(SparkContext.scala:2094)
我的代码如下所示:
val reader = sqlContext.read;
initialDataset.map( r => reader.jdbc(jdbcUrl, "(select enrichment_data from other_table where id='${r.getString(1)'}) result", connectionProperties).rdd.first().get(0).toString )
任何想法/指针?我应该使用两种不同的数据集吗?谢谢!
答案 0 :(得分:0)
首先,map()函数应接受现有RDD中的一行,然后将应用您所做的更改并返回更新的行。这就是为什么你得到这个例外的原因,因为scala不能序列化代码reader.jdbc(jdbcUrl, ...
要解决您的问题,您可以根据需要选择多个选项:
收集后,您可以广播其中一个数据集。通过广播,您的数据集将存储到您的节点中。记忆。如果此数据集相当小以适合节点的内存,则可以使用此方法。然后你可以查询它并将结果与第二个数据集
如果两个数据集都很大并且不适合将它们加载到节点内存中,那么使用mapPartition,您可以找到有关mapPartition here的更多信息。 mapPartition是针对每个分区而不是map()所执行的每个元素调用的。如果选择此选项,则可以从mapPartition访问第二个数据集,甚至可以从mapPartition初始化整个数据集(例如从第二个数据库中检索所有相关记录)。
请注意,我认为这两个数据集确实存在某种依赖关系(例如,您需要在执行下一步之前从第二个数据库访问某些值)。如果他们不这样做,那么只需创建ds1和ds2并正常使用它们,就像使用任何数据集一样。最后,如果您确定可能需要多次访问数据集,请记住缓存数据集。
祝你好运