如何从hdfs读取二进制文件到Spark数据帧?

时间:2016-05-24 12:51:50

标签: python hadoop numpy apache-spark spark-dataframe

我正在尝试将一些代码从pandas移植到(py)Spark。不幸的是,我已经失败了输入部分,我想读取二进制数据并将其放入Spark数据帧。

到目前为止,我正在使用来自numpy的fromfile

dt = np.dtype([('val1', '<i4'),('val2','<i4'),('val3','<i4'),('val4','f8')])
data = np.fromfile('binary_file.bin', dtype=dt)
data=data[1:]                                           #throw away header
df_bin = pd.DataFrame(data, columns=data.dtype.names)

但是对于Spark我找不到怎么做。到目前为止我的解决方法是使用csv-Files而不是二进制文件,但这不是一个理想的解决方案。我知道我不应该使用numpy的fromfile和火花。 如何读取已加载到hdfs的二进制文件?

我试过像

这样的东西
fileRDD=sc.parallelize(['hdfs:///user/bin_file1.bin','hdfs:///user/bin_file2.bin])
fileRDD.map(lambda x: ???)

但它给了我一个No such file or directory错误。

我见过这个问题: spark in python: creating an rdd by loading binary data with numpy.fromfile 但这只有在我将文件存储在驱动程序节点的主页时才有效。

4 个答案:

答案 0 :(得分:3)

因此,对于那些以Spark开头并且绊倒uopn二进制文件的人来说,这就是我解决它的方法:

dt=np.dtype([('idx_metric','>i4'),('idx_resource','>i4'),('date','>i4'),
             ('value','>f8'),('pollID','>i2')])
schema=StructType([StructField('idx_metric',IntegerType(),False),
                   StructField('idx_resource',IntegerType(),False), 
                   StructField('date',IntegerType),False), 
                   StructField('value',DoubleType(),False), 
                   StructField('pollID',IntegerType(),False)])

filenameRdd=sc.binaryFiles('hdfs://nameservice1:8020/user/*.binary')

def read_array(rdd):
    #output=zlib.decompress((bytes(rdd[1])),15+32) # in case also zipped
    array=np.frombuffer(bytes(rdd[1])[20:],dtype=dt) # remove Header (20 bytes)
    array=array.newbyteorder().byteswap() # big Endian
    return array.tolist()

unzipped=filenameRdd.flatMap(read_array)
bin_df=sqlContext.createDataFrame(unzipped,schema)

现在,您可以使用数据框在Spark中执行任何您想要的任何花哨的东西。

答案 1 :(得分:2)

编辑: 请查看此处提到的sc.binaryFiles的使用: https://stackoverflow.com/a/28753276/5088142

尝试使用:

hdfs://machine_host_name:8020/user/bin_file1.bin

core-site.xml

fs.defaultFS 中的主机名

答案 2 :(得分:1)

从 Spark 3.0 开始,Spark 支持二进制文件数据源,它读取二进制文件并将每个文件转换为包含文件原始内容和元数据的单个记录。

https://spark.apache.org/docs/latest/sql-data-sources-binaryFile.html

答案 3 :(得分:0)

我最近做过这样的事情:

from struct import unpack_from

# creates an RDD of binaryrecords for determinted record length
binary_rdd = sc.binaryRecords("hdfs://" + file_name, record_length)

# map()s each binary record to unpack() it
unpacked_rdd = binary_rdd.map(lambda record: unpack_from(unpack_format, record))

# registers a data frame with this schema; registerTempTable() it as table_name
raw_df = sqlc.createDataFrame(unpacked_rdd, sparkSchema)
raw_df.registerTempTable(table_name)

其中unpack_format和sparkSchema必须是&#34;同步&#34;。

我有一个动态生成unpack_format和sparkSchema变量的脚本;两者同时进行。 (它是更大代码库的一部分,因此不在此处发布以获取可读性)

unpack_format和sparkSchema可以定义如下,例如

from pyspark.sql.types import *

unpack_format = '<'   # '<' means little-endian: https://docs.python.org/2/library/struct.html#byte-order-size-and-alignment
sparkSchema = StructType()
record_length = 0

unpack_format += '35s'    # 35 bytes that represent a character string
sparkSchema.add("FirstName", 'string', True)  # True = nullable
record_length += 35

unpack_format += 'H'    # 'H' = unsigned 2-byte integer
sparkSchema.add("ZipCode", 'integer', True)
record_length += 2

# and so on for each field..