当前位置: 首页 > 知识库问答 >
问题:

Hbase MapReduce:如何使用自定义类作为映射器和/或还原器的值?

殷宾白
2023-03-14

我正在尝试熟悉Hadoop/Hbase MapReduce作业,以便能够正确编写它们。现在我有一个Hbase实例,其中包含一个名为dns的表,其中包含一些DNS记录。我尝试制作一个简单的唯一域计数器来输出文件,它成功了。现在,我只使用IntWritableText,我想知道是否可以为我的Mapper/Reducer使用自定义对象。我试着自己做,但我得到了

Error: java.io.IOException: Initialization of all the collectors failed. Error in last collector was :null
    at org.apache.hadoop.mapred.MapTask.createSortingCollector(MapTask.java:415)
    at org.apache.hadoop.mapred.MapTask.access$100(MapTask.java:81)
    at org.apache.hadoop.mapred.MapTask$NewOutputCollector.<init>(MapTask.java:698)
    at org.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:770)
    at org.apache.hadoop.mapred.MapTask.run(MapTask.java:341)
    at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:170)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:422)
    at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1869)
    at org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:164)
Caused by: java.lang.NullPointerException
    at org.apache.hadoop.mapred.MapTask$MapOutputBuffer.init(MapTask.java:1011)
    at org.apache.hadoop.mapred.MapTask.createSortingCollector(MapTask.java:402)
    ... 9 more

因为我是新手,所以我不知道该怎么做。我猜我必须实现一个或多个接口或扩展一个抽象类,但是我在这里或互联网上找不到合适的例子。

我试图从我的dns表中创建一个简单的域计数器,但是使用了一个类作为整数的包装器(仅用于教学目的)。我的地图类如下所示:

public class Map extends TableMapper<Text, MapperOutputValue> {
    private static byte[] columnName = "fqdn".getBytes();
    private static byte[] columnFamily = "d".getBytes();

    public void map(ImmutableBytesWritable row, Result value, Context context)
            throws InterruptedException, IOException {

        String fqdn = new String(value.getValue(columnFamily, columnName));
        Text key = new Text();
        key.set(fqdn);
        context.write(key, new MapperOutputValue(1));

    }
}

减速机:

public class Reduce extends Reducer<Text, MapperOutputValue, Text, IntWritable> {
    @Override
    public void reduce(Text key, Iterable<MapperOutputValue> values, Context context)
            throws IOException, InterruptedException {

        int i = 0;
        for (MapperOutputValue val : values) {
            i += val.getCount();
        }

        context.write(key, new IntWritable(i));
    }
}

以及我的驱动程序/主要功能的一部分:

 TableMapReduceUtil.initTableMapperJob(
                "dns",
                scan,
                Map.class,
                Text.class,
                MapperOutputValue.class,
                job);

/* Set output parameters */
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
job.setOutputFormatClass(TextOutputFormat.class);

正如我所说,MapperOutputValue只是一个简单的类,它包含一个私有整数、一个带有参数的构造函数、一个getter和一个setter。我还尝试添加一个toString方法,但它仍然不起作用。

所以我的问题是:使用自定义类作为reducer的映射器/输入的输出的最佳方式是什么?另外,假设我想使用一个具有多个字段的类作为reducer的最终输出。这个类应该实现/扩展什么?这是一个好主意还是我应该坚持使用“原语”作为可写或文本?

谢谢!

共有1个答案

诸彬郁
2023-03-14

映射输出值应实现可写,以便可以在 MapReduce 作业中的任务之间序列化它。将地图输出工作替换为以下内容应该可以正常工作:

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

public class DomainCountWritable implements Writable {
    private Text domain;
    private IntWritable count;

    public DomainCountWritable() {
        this.domain = new Text();
        this.count = new IntWritable(0);
    }

    public DomainCountWritable(Text domain, IntWritable count) {
        this.domain = domain;
        this.count = count;
    }

    public Text getDomain() {
        return this.domain;
    }

    public IntWritable getCount() {
        return this.count;
    }

    public void setDomain(Text domain) {
        this.domain = domain;
    }

    public void setCount(IntWritable count) {
        this.count = count;
    }

    public void readFields(DataInput in) throws IOException {
        this.domain.readFields(in);
        this.count.readFields(in);
    }

    public void write(DataOutput out) throws IOException {
        this.domain.write(out);
        this.count.write(out);
    }

    @Override
    public String toString() {
        return this.domain.toString() + "\t" + this.count.toString();
    }
}
 类似资料:
  • 我有两个对象,除了date成员外,其他成员都相同。在obj1中,date是java.sql.date,obj2.date是long(纪元)。 我需要编写一个映射器来将obj1映射到obj2。这就是我试图做的: 但是mapperImpl只有自己的日期转换实现: 我得到了: 这种转换的正确方式是什么?

  • 注意:我的jar是一个用Warbler编译成jar的jruby文件。

  • 我试图使用一个自定义类作为的键,如下所示: 但是,g给出了以下错误: 我想,我需要告诉C如何散列类,然而,我不太确定如何做。我怎样才能完成这些任务?

  • 我正在使用MapReduce为web搜索建立一个倒排索引。我知道如何使用一个键类型的MapReduce,您在这里设置它: 但是,如果我的密钥可以是不同类型的,那是不是支持呢?例如,一个键可能只是文本,另一个键可能是PairofWritables。我想为从映射器到reducer的输出,以及从reducer到最终输出的输出设置不同的键类型。我已经看到了一个名为MultipleOutput的类,它允许指

  • 我想在从AbstractEndPoint派生的endpoint上使用不同的jackson ObjectMapper实例(而不是在其他映射URL上使用的实例)。 为了澄清这个问题,我不想更改或自定义对象映射器,它由不同的URL使用,不同的URL来自AbstractEndpoints(如HealtEndpoint、MetricsEndpoint)。我想专门将新的对象映射器注入到管理endpoint中。

  • 问题内容: 我正在使用Spring Boot(1.2.1),其方式与他们的Build RESTful Web Service教程中的方式类似: 因此,在上面,Spring MVC隐式使用Jackson将我的对象序列化为JSON。 但我想对JSON格式进行一些简单的自定义,例如: 问题是,定制隐式JSON映射器的最简单方法是什么? 我在此博客文章中尝试了该方法,创建了CustomObjectMapp