通常,我们以以下形式编写映射器:
public static class Map extends Mapper<**LongWritable**, Text, Text, IntWritable>
这里映射器的输入键值对是<LongWritable, Text>
- 据我所知,当映射器获取输入数据时,它逐行通过 - 因此映射器的键表示行号 - 如果我错了,请纠正我。
我的问题是:如果我将mapper的输入键值对作为<Text, Text>
,那么它会给出错误
java.lang.ClassCastException: org.apache.hadoop.io.LongWritable cannot be cast to org.apache.hadoop.io.Text
将映射器的输入键值对赋予<LongWritable, Text>
是否必须 - 如果是,那么为什么?如果没有那么错误的原因是什么?你能帮我理解错误的正确推理吗?
提前致谢。
答案 0 :(得分:30)
映射器的输入取决于使用的是什么InputFormat。 InputFormat负责读取传入的数据并将其整形为Mapper期望的任何格式。默认的InputFormat是TextInputFormat,它扩展了FileInputFormat<LongWritable, Text>
。
如果不更改InputFormat,则使用具有与<LongWritable, Text>
不同的键值类型签名的Mapper将导致此错误。如果您希望输入<Text, Text>
,则必须选择合适的InputFormat。您可以在作业设置中设置InputFormat:
job.setInputFormatClass(MyInputFormat.class);
就像我说的那样,默认设置为TextInputFormat。
现在,假设您的输入数据是由逗号分隔的一系列以换行符分隔的记录:
如果希望映射器的输入键为(“A”,“value1”),(“B”,“value2”),则必须使用<Text, Text>
实现自定义的InputFormat和RecordReader。签名。 幸运的是,这很简单。有an example here并且可能还有一些示例浮动在StackOverflow周围。
简而言之,添加一个扩展FileInputFormat<Text, Text>
的类和一个扩展RecordReader<Text, Text>
的类。覆盖FileInputFormat#getRecordReader
方法,让它返回自定义RecordReader的实例。
然后,您必须实现所需的RecordReader逻辑。最简单的方法是在自定义RecordReader中创建LineRecordReader的实例,并将所有基本职责委托给此实例。在getCurrentKey和getCurrentValue方法中,您将通过调用LineRecordReader#getCurrentValue
并在逗号上将其拆分来实现用于提取逗号分隔的Text内容的逻辑。
最后,将新的InputFormat设置为Job InputFormat,如上面第二段所示。
答案 1 :(得分:1)
在汤姆怀特的“Hadoop:The Difinitive Guide”一书中,我认为他对此有适当的答案(第197页):
“的TextInputFormat的 键,简单地说是文件中的偏移量,通常不是很好 有用。文件中的每一行通常是键值对,由分隔符分隔 例如制表符。例如,这是由...产生的输出 TextOutputFormat,Hadoop的默认值 输出格式。要正确解释这些文件, KeyValueTextInputFormat 是合适的。
您可以通过指定分隔符 key.value.separator.in.input.line 属性。它 默认情况下是制表符。“
答案 2 :(得分:-3)
映射器输入的键将始终为整数类型....映射器输入键表示行的偏移号。而值表示整条线...... 记录阅读器在第一个周期中读取一行。映射器的o / p可以是你想要的任何东西(它可以是(Text,Text)或(Text,IntWritable)或......)