所以要明确出头了:
亨利马乌的XMLInputFormat将处理XML文件,并提取出两个已配置的开始/结束标记之间的XML。所以,如果你的XML如下所示:
<main>
<person>
<name>Bob</name>
<dob>1970/01/01</dob>
</person>
</main>
,你已经配置了开始/结束标记是<person>
和</person>
,那么你的映射器将传递以下<LongWritable, Text>
对到其地图方法:
LongWritable: 10
Text: "<person>\n <name>Bob</name>\n <dob>1970/01/01</dob>\n </person>"
你在你的mapper中使用这些数据是由你自己决定的。
至于分裂,XmlInputFormat
延伸TextInputFormat
,因此,如果您输入文件是分割型(即未压缩的或具有可分离的编解码器,例如活泼的压缩),则该文件将被通过一个或多个映射器如下处理:
- 如果输入文件大小(假设48 MB)小于HDFS单块(可以说64MB),而且没有配置最小/最大分大小的属性,那么你会得到一个单个映射器来处理文件
- 与上面一样,但您将最大分割大小配置为10MB(
mapred.max.split.size=10485760
),那么您将得到5个映射任务来处理文件
- 如果文件大于块大小,那么您将为每个块获得一个映射任务,或者如果配置了最大分割大小,则将按该分割大小映射文件分割的每个部分
当文件被拆分成这些块或拆分大小的块时,XmlInputFormat将寻找块/拆分边界的字节地址/偏移量,然后向前扫描,直到找到配置的XML开始标记或达到字节块/拆分边界的地址。如果它找到开始标记,它将消耗数据直到找到结束标记(或文件结束)。如果它发现结束标记,记录将传递给你的映射器,否则你的映射器将不会收到任何输入。要强调的是,当试图找到结束标记时,地图可能会扫描块/分割的结尾,但只有在找到开始标记时才会执行此操作,否则将在块/分割结束时停止扫描。如果你还没有配置映射器(并且正在使用默认或标识映射器,因为它也是已知的),那么对于(最终)回答你的问题,那么是的,无论XML块有多大都不重要(MB的,GB的,TB的!)它将被发送到减速器。
我希望这是有道理的。
编辑
要跟进您的意见:
- 是的,每一个映射器将尝试处理其文件
- 是的,分裂(字节范围)不管是什么您也设置了最大分割大小,您的映射程序将接收代表(包含)开始/结束标记之间数据的记录。 person元素不会被分割,不管它的大小是多少(显然,如果开始元素和结束元素之间存在GB数据,则很可能会用尽内存,试图将其缓存到Text对象中)
- 继续上面的内容,你的数据永远不会在开始和结束元素之间被分开,一个人元素将被全部发送给一个映射器,所以你应该总是可以使用类似于SAX解析器的东西来进一步处理它,而不用担心你只看到人物元素的一部分。
感谢您的回答。所以,让我说出我的理解,并请纠正我,如果我错了.. 1. XmlInputFormat将扫描XML元素,无论分裂。 2.除非我明确设置'mapred.max.split.size',否则它将发送整个元素(所有数据在和 之间),而不管它的大小 - 即使它是500 MB。 3.如果我设置了'mapred.max.split.size',它将拆分XML元素并将其发送给不同的映射器,但是因为这些块都不是完整的XML,所以它们不能通过StAX进行分析。 我正确以上3点? –
@ChrisWhite能否澄清一些问题:由于'XMLInputFormat'扩展了'TextInputFormat',并且不覆盖'getSplits'方法,因此它使用'FileInputFormat'中的默认getSplits实现。如果我添加了根据XML标记进行拆分的自定义getSplits实现,它会使我受益吗?例如:https://github.com/whym/wikihadoop#splitting – Nilesh