1

編集: 問題は解決しました - かなりばかげたエラーがありました。

map、reduce、map、reduce で構成される MapReduce パイプラインがあります。最初のリデュースには SequenceFileOutputFormat を使用し、2 番目のマップには SequenceFileInputFormat を使用します。使い方を調べてみたところ、うまく使えているようです。これに入れている型は、IntWritable と IntPairArrayWritable (mahout の IntPairWritable を使用するカスタム ArrayWritable サブクラス) です。問題は、2 番目のマップで IntPairArrayWritable を読み取るときに、個々の IntPairWritable を取得しようとすると ClassCastException が発生することです。これが ArrayWritable クラスの使用方法に誤りがあるためなのか、SequenceFile{Input,Output} Format の使用に問題があるためなのかはわかりません。ここや他の場所でたくさんの例を見てきましたが、どちらも正しくやっているように見えます。しかし、私はまだエラーが発生しています。何か助けはありますか?

詳細:

これが私の最初のレデューサークラスです:

public static class WalkIdReducer extends MapReduceBase implements
        Reducer<IntWritable, IntPairWritable, IntWritable, IntPairArrayWritable> {

    @Override
    public void reduce(IntWritable walk_id, Iterator<IntPairWritable> values,
            OutputCollector<IntWritable, IntPairArrayWritable> output,
            Reporter reporter) throws IOException {
        ArrayList<IntPairWritable> value_array = new ArrayList<IntPairWritable>();
        while (values.hasNext()) {
            value_array.add(values.next());
        }
        output.collect(walk_id, IntPairArrayWritable.fromArrayList(value_array));
    }
}

そして2番目のマッパークラス:

public static class NodePairMapper extends MapReduceBase implements
        Mapper<IntWritable, IntPairArrayWritable, IntPairWritable, Text> {

    @Override
    public void map(IntWritable key, IntPairArrayWritable value,
            OutputCollector<IntPairWritable, Text> output,
            Reporter reporter) throws IOException {
        // The following line gives a ClassCastException;
        // See IntPairArrayWritable.toArrayList(), below
        ArrayList<IntPairWritable> values = value.toArrayList();
        // other unimportant stuff
    }
}

最初の MapReduce のジョブ構成の関連部分:

    conf.setReducerClass(WalkIdReducer.class);
    conf.setOutputKeyClass(IntWritable.class);
    conf.setOutputValueClass(IntPairArrayWritable.class);
    conf.setOutputFormat(SequenceFileOutputFormat.class);

2 つ目の MapReduce については、次のようになります。

    conf.setInputFormat(SequenceFileInputFormat.class);
    conf.setMapperClass(NodePairMapper.class);

最後に、私の ArrayWritable サブクラス:

public static class IntPairArrayWritable extends ArrayWritable
{
    // These two methods are what people say is all you need for
    // creating an ArrayWritable subclass
    public IntPairArrayWritable() {
        super(IntPairArrayWritable.class);
    }

    public IntPairArrayWritable(IntPairWritable[] values) {
        super(IntPairArrayWritable.class, values);
    }

    // Some convenience methods, so I can use ArrayLists in
    // other parts of the code
    public static IntPairArrayWritable fromArrayList(
            ArrayList<IntPairWritable> array) {
        IntPairArrayWritable writable = new IntPairArrayWritable();
        IntPairWritable[] values = new IntPairWritable[array.size()];
        for (int i=0; i<array.size(); i++) {
            values[i] = array.get(i);
        }
        writable.set(values);
        return writable;
    }

    public ArrayList<IntPairWritable> toArrayList() {
        ArrayList<IntPairWritable> array = new ArrayList<IntPairWritable>();
        for (Writable pair : this.get()) {
            // This line is what kills it.  I get a ClassCastException here.
            IntPairWritable int_pair = (IntPairWritable) pair;
            array.add(int_pair);
        }
        return array;
    }
}

私が得る特定のエラーは次のとおりです。

java.lang.ClassCastException: WalkAnalyzer$IntPairArrayWritable cannot be cast to org.apache.mahout.common.IntPairWritable
at WalkAnalyzer$IntPairArrayWritable.toArrayList(WalkAnalyzer.java:231)
at WalkAnalyzer$NodePairMapper.map(WalkAnalyzer.java:84)
at WalkAnalyzer$NodePairMapper.map(WalkAnalyzer.java:77)
at org.apache.hadoop.mapred.MapRunner.run(MapRunner.java:50)
at org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:358)
at org.apache.hadoop.mapred.MapTask.run(MapTask.java:307)
at org.apache.hadoop.mapred.Child.main(Child.java:170)

ArrayWritable の get() メソッドから出力されるものが のインスタンスである理由について、かなり困惑してWalkAnalyzer$IntPairArrayWritableIntPairArrayWritableます。

編集

問題が見つかりました。それは、IntPairArrayWritable のコンストラクターの書き方にありました。電話super(IntPairArrayWritable.class);するべきだったときに電話しましたsuper(IntPairWritable.class);。コードは実際には次のようになります。

public static class IntPairArrayWritable extends ArrayWritable
{
    // These two methods are what people say is all you need for
    // creating an ArrayWritable subclass
    public IntPairArrayWritable() {
        super(IntPairWritable.class);
    }

    public IntPairArrayWritable(IntPairWritable[] values) {
        super(IntPairWritable.class, values);
    }
}

ArrayWritable サブクラスには、あまり混同されていない名前を使用することをお勧めします。そのため、エラーを見つけやすくなります。

4

1 に答える 1

0

IntPairWritableのインポートステートメントを確認してください。Mapperで間違ったパッケージ名を取得したため、その名前もIntPairWritableであるにもかかわらず、別のクラスにキャストしているようです。

于 2012-10-19T18:18:20.013 に答える