将大量文件从hdfs移动到hdfs

时间:2014-01-07 17:50:41

标签: hadoop hdfs oozie

我需要将大量文件从一个hdfs目录移动(不复制)到同一个集群中的另一个hdfs目录。

我可以使用distcp,但它似乎是一种矫枉过正,因为它正在复制文件(复制它)我只想移动它。两个问题:

A)那里有什么东西:

我想使用mapreduce来执行此操作,因为有数百万个文件需要移动(或重命名为新路径)。我也想把它与oozie整合。我自己可以写一个mapreduce工作,但我想知道是否有什么可以完成这项工作。

B)我真的需要像mapred那样做吗?

不幸的是,我对hdfs重命名的性能特征知之甚少;你认为我可以采用单线程方法来重命名文件吗?

2 个答案:

答案 0 :(得分:1)

移动本身是有效的,因为它仅在元数据(即inode)级别,而不在数据级别。换句话说,发布一个移动(在Hadoop的代码内部称为rename,而不是move)比复制数据要快得多。如果您对详细信息感兴趣,可以查看source code

出于这个原因,你不应该做一个distcp ,因为这将是数据的实际副本。如果你想并行化它(因为你谈论的是数百万个文件),使用hadoop流媒体应该不会太难:

  1. 写几个包含要重命名的文件列表(src + destination)的文件,每行一个。
  2. 编写一个shell脚本,为它在stdin上读取的每一行发出重命名(hdfs command mv)。
  3. 使用流式传输:包含文件的文件是输入,shell脚本是映射器。
  4.   

    那里有什么东西吗?

    我不知道,但可能有。

      

    我真的需要像mapred那样做吗?

    如果您有数百万个文件,即使HDFS重命名本身有效,联系namenode的延迟也会增加。 BUT ,如果它是一次性的话,我宁愿发出单线程方法并等待,因为编写和调试(甚至是简单的代码)也需要一段时间。如果您打算经常这样做(为什么?),那么我会考虑实施上述方法。

答案 1 :(得分:1)

如果您要将一部分文件从一个文件夹复制到HDFS中的另一个文件夹,我想出了这一点:

import pandas as pd
import os
from multiprocessing import Process
from subprocess import Popen, PIPE
hdfs_path_1 = '/path/to/the/origin/'
hdfs_path_2 = '/path/to/the/destination/'

df = pd.read_csv("list_of_files.csv")  
to_do_list = list(df.tar) # or any other lists that you have
print(f'To go: {len(to_do_list)}')

def copyy(f):
    process = Popen(f'hdfs dfs -mv {hdfs_path_1}{f} {hdfs_path_2}', shell=True, stdout=PIPE, stderr=PIPE)
    std_out, std_err = process.communicate()
    if std_out!= b'':
        print(std_out)

ps = []
for f in to_do_list:
    p = Process(target=copyy, args=(f,))
    p.start()
    ps.append(p)
for p in ps:
    p.join()
print('done')

如果您要在目录中包含所有文件的列表,请使用以下命令:

from subprocess import Popen, PIPE
hdfs_path = '/path/to/the/designated/folder'
process = Popen(f'hdfs dfs -ls -h {hdfs_path}', shell=True, stdout=PIPE, stderr=PIPE)
std_out, std_err = process.communicate()
list_of_file_names = [fn.split(' ')[-1].split('/')[-1] for fn in std_out.decode().readlines()[1:]][:-1]
list_of_file_names_with_full_address = [fn.split(' ')[-1] for fn in std_out.decode().readlines()[1:]][:-1]