在hadoop中加载大日文文件

时间:2017-04-21 07:12:26

标签: python apache-spark hive pyspark hdfs

我在HDFS这个巨大的文件,这是我的数据库的摘录。 e.g:

1||||||1||||||||||||||0002||01||1999-06-01 16:18:38||||2999-12-31 00:00:00||||||||||||||||||||||||||||||||||||||||||||||||||||||||2||||0||W.ISHIHARA||||1999-06-01 16:18:38||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||19155||||||||||||||1||1||NBV||||||||||||||U||||||||N||||||||||||||||||||||
1||||||8||2000-08-25 00:00:00||||||||3||||0001||01||1999-06-01 16:26:16||||1999-06-01 17:57:10||||||||||300||||||PH||400||Yes||PH||0255097�`||400||||1||103520||||||1||4||10||||20||||||||||2||||0||S.OSARI||1961-10-05 00:00:00||1999-06-01 16:26:16||�o��������������||�o��������������||1||||����||||1||1994-01-24 00:00:00||2||||||75||1999-08-25 00:00:00||1999-08-25 00:00:00||0||1||||4||||||�l��������������||�o��������������||�l��������������||||�o��������������||NP||||�l��������������||�l��������������||||||5||19055||||||||||1||||8||1||NBV||||||||||||||U||||||||N||||||||||||||||||||||
  • 文件大小:40GB
  • 记录数:~120 000 000
  • 字段数:112
  • 字段sep:||
  • 行sep:\ n
  • 编码:sjis

我想使用pyspark(1.6和python 3)在hive中加载此文件。但我的工作仍然失败。 这是我的代码:

toProcessFileDF = sc.binaryFiles("MyFile")\
    .flatMap(lambda x: x[1].split(b'\n'))\
    .map(lambda x: x.decode('sjis'))\
    .filter(lambda x: x.count('|')==sepCnt*2)\
    .map(lambda x: x.split('||'))\
    .toDF(schema=tableSchema) #tableSchema is the schema retrieved from hive
toProcessFileDF.write.saveAsTable(tableName, mode='append')

我收到了几个错误,但除此之外,jave 143(内存错误),心跳超时和内核已经死亡。 (如果您需要确切的日志错误,请告诉我。)

这是正确的方法吗?也许有更聪明的方式或更有效率。你能告诉我一些关于如何执行此操作的建议吗?

2 个答案:

答案 0 :(得分:1)

我发现databrick csv阅读器非常有用。

toProcessFileDF_raw = sqlContext.read.format('com.databricks.spark.csv')\
                                        .options(header='false',
                                                 inferschema='false',
                                                 charset='shift-jis',
                                                 delimiter='\t')\
                                        .load(toProcessFile)

遗憾的是,我可以使用分隔符选项仅拆分一个字符。因此我的解决方案是使用制表符分割,因为我确定我的文件中没有任何内容。然后我可以在我的线上应用分割。

这不是完美的,但至少我有正确的编码,我不会把所有内容都放在内存中。

答案 1 :(得分:0)

日志会有所帮助。

binaryFiles将此视为HDFS中的二进制文件作为单个记录,并以键值对的形式返回,其中键是每个文件的路径,值是每个文件的内容。

来自Spark文档的注意事项:首选小文件,也允许使用大文件,但可能会导致性能下降。

如果您使用textFile

会更好
toProcessFileDF = sc.textFile("MyFile")\
                    .map(lambda line: line.split("||"))\
....

此外,一个选项是在读取初始文本文件时指定更多数量的分区(例如sc.textFile(path,200000)),而不是在阅读后重新分区。

另一个重要的事情是确保您的输入文件是可拆分的(某些压缩选项使其不可拆分,在这种情况下,Spark可能必须在导致OOM的单个机器上读取它)。