我有一张镶木桌子 - 我们称它为table_a
- 大概是6 GB。我需要在这张桌子上加上50万张其他镶木桌子,比如table_1
... table_n
,其大小介于10 MB到20 GB之间。然后我将联接的内容写在其他地方。连接字段为A,B和C,表名(1 ... n)上的后缀表示该表的值为A.
如果我选择一个表格(例如table_1),然后将table_a过滤到仅记录A' A' ==' 1',然后进行加入:
table_1 = sqlContext.read.load(path_to_table_1)
table_a = sqlContext.read.load(path_to_table_a).filter("A = '1'")
broadcasted_a = broadcast(table_a)
# omitting "A" here because we've already filtered down for it
result = table_1.join(broadcasted_a, ["B", "C"))
do_something_with_result(result)
但是,当我尝试在没有预过滤table_a的情况下进行连接时,连接会挂起。我已经等了10-20分钟才能完成加入,但还没有看到它完成。所以,虽然我可以通过过滤使这个工作用于1个表,但我不确定如何在所有表1 ... n中执行此操作。我可以循环遍布五十万个镶木桌子并按照上面的步骤进行操作,但我想知道是否有更快的方式来表达这些连接并且并行地在镶木桌上循环。我有一个想法是将表1 ... n的路径收集到rdd然后尝试:
table_a = sqlContext.read.load(path_to_table_a)
def my_function(path):
# The paths are formatted such that the suffix of each path is the table's value for column A
filter_key = path.split('=')[-1]
table = sqlContext.read.load(path)
table_a_filtered = table_a.filter("A = '%s'" % filter_key)
result = table.join(table_a_filtered, ["B", "C"])
do_something_with_result(result)
path_rdd = sc.parallelize(table_paths)
path_rdd.foreach(my_function)
但这不起作用,因为你无法在诸如foreach
之类的函数中嵌套rdd。
我可以选择快速加入这些表格吗?有没有其他方法我可以为每个表1 ... n进行过滤而没有嵌套rdds?或者是否有某种方法可以优化所有表1 ... n和table_a之间的单个大规模连接?
更新1
我用table_a重新运行了table_1的连接(没有预过滤),最终我得到了以下警告,之后所有的工作都崩溃了:
2017-06-01 14:49:11,879 WARN org.apache.hadoop.hdfs.DFSClient -
Error Recovery for block XXX in pipeline DatanodeInfoWithStorage[XXX,DISK],
DatanodeInfoWithStorage[XXX,DISK],
DatanodeInfoWithStorage[XXX,DISK]: bad datanode DatanodeInfoWithStorage[XXX,DISK]
然后我尝试删除table_a的广播,然后进行连接(再次,没有预过滤) - 它完美地工作。接下来,我将尝试阅读镶木桌的整个目录,并将结果DataFrame与table_a DataFrame相结合 - 但我可以使用任何其他更有效的解决方案。