hadoop - 使用输入拆分 (HADOOP)

标签 hadoop mapreduce hadoop2

我有一个 .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 /

这创建了大小为 64B64B25B

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/

相关文章:

Windows 上的 Hadoop。 YARN 无法以 java.lang.UnsatisfiedLinkError 启动

java - 在 Mapreduce 程序中使用 MulipleInputs 会出现错误

hadoop - 在hbase中自动生成row_key

hadoop - 如何知道执行的奴隶数量

hadoop - hadoop-2.7.3 中的 yarn : yarn-default. xml 位置

java - 如何获取cloudera中文件夹的路径?

Hadoop双节点集群环境,NameNode的web UI显示活节点数为1,死节点数为0

java - 在hadoop中没有reducer的情况下限制多输出中映射器的数量

hadoop - 在 Oozie 中可以实现这种类型的工作流程吗?

hadoop - 使用 importtsv 将文本文件导入 HBase