我正在尝试获取csv文件的摘要,文件的第一行是标题。有没有办法将每个列的值及其标题名称作为Java代码中的键值对。
例如:输入文件就像
A,B,C,d
1,2,3,4
-5,6,7,8-
我希望mapper的输出为(A,1),(B,2),(C,3),(D,4),(A,5),....
注意:我尝试使用覆盖Mapper类中的run函数来跳过第一行。但据我所知,每次输入分割都会调用run函数,因此不适合我的需要。对此的任何帮助都将非常感激。
这是我的mapper看起来的方式:
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
String[] splits = line.split(",",-1);
int length = splits.length;
// count = 0;
for (int i = 0; i < length; i++) {
columnName.set(header[i]);
context.write(columnName, new Text(splits[i]+""));
}
}
public void run(Context context) throws IOException, InterruptedException
{
setup(context);
try
{
if (context.nextKeyValue())
{
Text columnHeader = context.getCurrentValue();
header = columnHeader.toString().split(",");
}
while (context.nextKeyValue())
{
map(context.getCurrentKey(), context.getCurrentValue(), context);
}
}
finally
{
cleanup(context);
}
}
答案 0 :(得分:1)
我假设列标题是字母表,列值是数字。
实现此目标的方法之一是使用DistributedCache
。
以下是步骤:
Job::addCacheFile()
setup()
方法中,从分布式缓存中访问此文件。将文件内容解析并存储在columnHeader
列表中。map()
方法中,检查每条记录中的值是否与标题匹配(存储在columnnHeader
列表中)。如果是,则忽略该记录(因为记录只包含标题)。如果不是,则将值与列标题一起发出。 这就是Mapper和Driver代码的样子:
<强>驱动程序:强>
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, "HeaderParser");
job.setJarByClass(WordCount.class);
job.setMapperClass(HeaderParserMapper.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(NullWritable.class);
job.addCacheFile(new URI("/in/header.txt#header.txt"));
FileInputFormat.addInputPath(job, new Path("/in/in7.txt"));
FileOutputFormat.setOutputPath(job, new Path("/out/"));
System.exit(job.waitForCompletion(true) ? 0:1);
}
驱动程序逻辑:
在驱动程序中,添加&#34; header.txt&#34;通过执行以下语句来分布式缓存:
job.addCacheFile(new URI("/in/header.txt#header.txt"));
<强>映射器:强>
public static class HeaderParserMapper
extends Mapper<LongWritable, Text , Text, NullWritable>{
String[] headerList;
String header;
@Override
protected void setup(Mapper.Context context) throws IOException, InterruptedException {
BufferedReader bufferedReader = new BufferedReader(new FileReader("header.txt"));
header = bufferedReader.readLine();
headerList = header.split(",");
}
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
String[] values = line.split(",");
if(headerList.length == values.length && !header.equals(line)) {
for(int i = 0; i < values.length; i++)
context.write(new Text(headerList[i] + "," + values[i]), NullWritable.get());
}
}
}
Mapper Logic:
setup()
方法。setup()
方法中放置在驱动程序中的分布式缓存中)。 map()
方法中,检查该行是否与标题匹配。如果是,则忽略该行。否则,输出标题和值为(h1,v1),(h2,v2),(h3,v3)和(h4,v4)。我按以下输入运行了这个程序:
A,B,C,D
1,2,3,4
5,6,7,8
我得到了以下输出(其中值与各自的标题匹配):
A,1
A,5
B,2
B,6
C,3
C,7
D,4
D,8
答案 1 :(得分:0)
@Manjunath Ballur接受的答案是一个很好的技巧。但是,Map Reduce必须与简单性结合使用。不建议您检查每一行的标题。
一种可行的方法是编写一个自定义InputFormat来为您完成这项工作