使用输入拆分(HADOOP)

时间:2017-03-16 18:44:10

标签: hadoop mapreduce hadoop2

我有一个.txt文件,如下所示:

这是xyz

这是我的家

这是我的电脑

这是我的房间

这是ubuntu PC xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxxxxxxxxxxxxxxxxxxx

(忽略每条记录后的空白行)

我已将块大小设置为 64字节。我要检查的是,是否存在将单个记录分成两个块的情况。

现在逻辑上,由于块大小 64字节,在将文件上传到HDFS后,它应该创建 3块大小分别为64,64,27字节,它做的。此外,由于第一个块的大小为64字节,因此它应仅包含以下数据:

这是xyz

这是我的家

这是我的电脑

这是我的房间

的Th

现在我想查看第一个块是否是这样,如果我通过浏览器浏览HDFS并下载文件,它会下载整个文件而不是单个块

所以我决定运行map-reduce作业,它只显示记录值。(设置reducers=0,mapper输出为context.write(null,record_value),同时将默认分隔符更改为{{1} })

现在,在运行作业时,作业计数器会显示 3拆分,这很明显,但在检查输出目录完成后,它会显示 3个映射器输出文件其中2是空的,第一个映射器输出文件包含文件的所有内容。

任何人都可以帮我吗?新版本的hadoop是否有可能自动处理不完整的记录?

2 个答案:

答案 0 :(得分:7)

重现场景的步骤
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中,块大小为 64B

hdfs dfs -Ddfs.bytes-per-checksum=16 -Ddfs.blocksize=64 -put sample.txt /

这创建了三个大小 64B 64B 25B

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 缩减器播放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的映射器,行读取从拆分开始处开始。如果分组以\n结尾,则读数在分割边界处结束,否则它将查找分配的分割长度的第一个\n帖子(此处为64B)。这样它不会最终处理部分线。

对于所有其他映射器(start index!= 0),它检查起始索引(start - 1)中的前一个字符是否为\n,如果是,则从头开始读取内容split else它会跳过其开始索引与该分割中遇到的第一个\n字符之间存在的内容(因为此内容由其他映射器处理)并开始从第一个\n读取。

此处,mapper1(起始索引为0)以Block0开头,其分割结束于一行的中间。因此,它继续读取消耗整个Block1的行,并且由于Block1没有\n个字符,mapper1继续读取,直到找到{{1}最终消耗了整个\n。这就是Block2的整个内容在单个映射器输出中的结果。

sample.txt(起始索引!= 0),其起始索引之前的一个字符不是mapper2,因此跳过该行并最终没有内容。空映射器输出。 \n具有与mapper3相同的方案。

<小时/> 尝试更改此mapper2的内容,以查看不同的结果

sample.txt

答案 1 :(得分:1)

  1. 使用以下命令获取HDFS上文件的阻止列表

    hdfs fsck PATH -files -blocks -locations

  2. 其中PATH是文件所在的完整HDFS路径。

    1. 输出(部分显示如下)将是这样的(行号2,3 ...忽略)

      通过http://ec2-54-235-1-193.compute-1.amazonaws.com:50070/fsck?ugi=student6&files=1&blocks=1&locations=1&path=%2Fstudent6%2Ftest.txt连接到namenode FSCK由student6(auth:SIMPLE)从/172.31.11.124开始为路径/student6/test.txt于2017年3月22日星期三15:33:17 UTC /student6/test.txt 22个字节,1个块:OK 0. BP-944036569-172.31.11.124-1467635392176: blk_1073755254 _14433 len = 22 repl = 1 [DatanodeInfoWithStorage [172.31.11.124: 50010,DS-4a530a72-0495-4b75-a6f9-75bdb8ce7533,DISK]]

    2. 复制输出命令的粗体部分(不包括_14433),如上例输出

    3. 所示
    4. 转到datanode上的Linux文件系统到存储块的目录(这将由hdfs-site.xml的dfs.datanode.data.dir参数指向,并在整个子树中搜索这个文件名的位置是你刚才复制的粗体字符串。这将告诉你dfs.datanode.data.dir下的哪个子目录包含一个名称中包含该字符串的文件(排除任何后缀为.meta的文件名)。一旦你有了如果找到这样的文件名,您可以在该文件名上运行Linux cat命令以查看文件内容。

    5. 请记住,虽然该文件是HDFS文件,但是文件实际上存储在Linux文件系统中,并且HDFS文件的每个块都是唯一的Linux文件。该块由Linux文件系统标识,其名称如步骤2的粗体字符串所示