我有一个 .txt
文件如下:
这是 xyz
这是我的家
这是我的电脑
这是我的房间
这是 ubuntu PC xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxxxxxxxxxxxxxxxxxxx
(忽略每条记录后的空行)
我已将 block 大小设置为64 字节。我想检查的是,是否存在将一条记录分成两个 block 的情况。
现在逻辑上,由于 block 大小为64字节,将文件上传到HDFS后,它应该创建3个大小分别为64、64、27字节的 block ,它是这样做的。此外,由于第一个 block 的大小为 64 字节,因此它应该只包含以下数据:
这是 xyz
这是我的家
这是我的电脑
这是我的房间
日
现在我想看看第一个 block 是否是这样的,如果我通过浏览器浏览 HDFS 并下载文件,它会下载整个文件而不是单个 block 。。 p>
所以我决定运行一个只显示记录值的 map-reduce 作业。(设置 reducers=0
,并将 mapper 输出为 context.write(null,record_value)
,还将默认分隔符更改为 ""
)
现在运行作业时,作业计数器显示 3 个拆分,这很明显,但完成后,当我检查输出目录时,它显示 3 个映射器输出文件其中 2 个是空的,第一个映射器输出文件包含文件的所有内容。
谁能帮我解决这个问题?较新版本的 hadoop 是否有可能自动处理不完整的记录?
最佳答案
重现场景的步骤
1) 创建了一个文件 sample.txt
,其内容总大小为 ~153B
cat sample.txt
This is xyz
This is my home
This is my PC
This is my room
This is ubuntu PC xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxxxxxxxxxxxxxxxxxxx
2) 将属性添加到 hdfs-site.xml
<property>
<name>dfs.namenode.fs-limits.min-block-size</name>
<value>10</value>
</property>
并加载到 HDFS 中, block 大小为 64B
。
hdfs dfs -Ddfs.bytes-per-checksum=16 -Ddfs.blocksize=64 -put sample.txt /
这创建了大小为 64B
、64B
和 25B的三个 block
。
Block0
中的内容:
This is xyz
This is my home
This is my PC
This is my room
This i
Block1
中的内容:
s ubuntu PC xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xx
Block2
中的内容:
xx xxxxxxxxxxxxxxxxxxxxx
3) 一个简单的mapper.py
#!/usr/bin/env python
import sys
for line in sys.stdin:
print line
4) 使用 0
reducer 的 Hadoop 流:
yarn jar hadoop-streaming-2.7.1.jar -Dmapreduce.job.reduces=0 -file mapper.py -mapper mapper.py -input /sample.txt -output /splittest
作业以 3 个输入拆分运行,调用 3 个映射器并生成 3 个输出文件,其中一个文件包含 sample.txt
的全部内容,其余的 0B
文件。
hdfs dfs -ls /splittest
-rw-r--r-- 3 user supergroup 0 2017-03-22 11:13 /splittest/_SUCCESS
-rw-r--r-- 3 user supergroup 168 2017-03-22 11:13 /splittest/part-00000
-rw-r--r-- 3 user supergroup 0 2017-03-22 11:13 /splittest/part-00001
-rw-r--r-- 3 user supergroup 0 2017-03-22 11:13 /splittest/part-00002
文件 sample.txt
被分成 3 个部分,这些部分被分配给每个映射器,
mapper1: start=0, length=64B
mapper2: start=64, length=64B
mapper3: start=128, length=25B
这只决定映射器必须读取文件的哪一部分,不一定是准确的。映射器读取的实际内容由 FileInputFormat 及其边界决定,此处为 TextFileInputFormat
。
这使用 LineRecordReader
从每个拆分中读取内容,并使用 \n
作为分隔符(行边界)。对于未压缩的文件,各行由每个映射器读取,如下所述。
对于起始索引为0的mapper,行读取从split的开始处开始。如果拆分以 \n
结束,则读取在拆分边界结束,否则它会查找第一个 \n
后分配的拆分长度(此处 64B
)。这样它就不会结束处理部分行。
对于所有其他映射器(起始索引!= 0),它检查从其起始索引(start - 1
)开始的前一个字符是否为 \n
,如果是的,它从拆分的开头读取内容,否则它会跳过其起始索引和该拆分中遇到的第一个 \n
字符之间的内容(因为此内容由其他映射器处理)并从第一个 \n
开始读取。
这里,mapper1
(起始索引为0)以Block0
开始,其拆分在一行的中间结束。因此,它继续读取消耗整个 Block1
的行,并且由于 Block1
没有 \n
字符,mapper1
继续读取,直到它找到一个 \n
,该 \n
也以消耗整个 Block2
结束。这就是 sample.txt
的全部内容如何在单个映射器输出中结束。
mapper2
(start index != 0),其起始索引前的一个字符不是 \n
,因此跳过该行并以无内容结束。空映射器输出。 mapper3
具有与 mapper2
相同的场景。
尝试像这样更改
sample.txt
的内容以查看不同的结果
This is xyz
This is my home
This is my PC
This is my room
This is ubuntu PC xxxx xxxx xxxx xxxx
xxxx xxxx xxxx xxxx xxxx xxxx xxxx
xxxxxxxxxxxxxxxxxxxxx
关于hadoop - 使用输入拆分 (HADOOP),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42842411/