1

私が出力しているものは次のとおりです。

単語、ファイル ----- ------ wordx Doc2、Doc1、Doc1、Doc1、Doc1、Doc1、Doc1、Doc1

私が欲しいのは:

単語、ファイル ----- ------ wordx Doc2、Doc1

public static class LineIndexMapper extends MapReduceBase
        implements Mapper<LongWritable, Text, Text, Text> {

    private final static Text word = new Text();
    private final static Text location = new Text();

    public void map(LongWritable key, Text val,
            OutputCollector<Text, Text> output, Reporter reporter)
            throws IOException {
        FileSplit fileSplit = (FileSplit) reporter.getInputSplit();
        String fileName = fileSplit.getPath().getName();
        location.set(fileName);

        String line = val.toString();
        StringTokenizer itr = new StringTokenizer(line.toLowerCase());
        while (itr.hasMoreTokens()) {
            word.set(itr.nextToken());
            output.collect(word, location);
        }
    }
}

public static class LineIndexReducer extends MapReduceBase
        implements Reducer<Text, Text, Text, Text> {

    public void reduce(Text key, Iterator<Text> values,
            OutputCollector<Text, Text> output, Reporter reporter)
            throws IOException {

        boolean first = true;
        StringBuilder toReturn = new StringBuilder();
        while (values.hasNext()) {
            if (!first) {
                toReturn.append(", ");
            }
            first = false;
            toReturn.append(values.next().toString());
        }

        output.collect(key, new Text(toReturn.toString()));
    }
}

最高のパフォーマンスを得るには - 繰り返されるファイル名をどこでスキップする必要がありますか? マップ、リデュース、またはその両方?ps: 私は MR タスクの作成の初心者であり、質問でプログラミング ロジックを理解しようとしています。

4

2 に答える 2

1

Reducer でのみ重複を削除できます。これを行うには、重複を許可しないセットを使用できます。

public void reduce(Text key, Iterator<Text> values,
        OutputCollector<Text, Text> output, Reporter reporter)
        throws IOException {

    // Text's equals() method should be overloaded to make this work
    Set<Text> outputValues = new HashSet<Text>();

    while (values.hasNext()) {
      // make a new Object because Hadoop may mess with original
      Text value = new Text(values.next());

      // takes care of removing duplicates
      outputValues.add(value);
    }

    boolean first = true;
    StringBuilder toReturn = new StringBuilder();
    Iterator<Text> outputIter = outputValues.iter();
    while (outputIter.hasNext()) {
        if (!first) {
            toReturn.append(", ");
        }
        first = false;
        toReturn.append(outputIter.next().toString());
    }

    output.collect(key, new Text(toReturn.toString()));
}

編集: Chris のコメントに従って Set に値のコピーを追加します。

于 2012-04-24T20:34:25.703 に答える
0

ローカル マップ アグリゲーションを実行し、コンバイナーを導入することでパフォーマンスを向上させることができます。基本的には、マッパーとレデューサーの間で送信されるデータの量を減らしたいと考えています。

ローカル マップ アグリゲーションは、LRU のような出力ペアのマップ (またはセット) を維持するという概念です。あなたの場合、現在のマッパー ドキュメントの一連の単語です (マップごとに 1 つのドキュメントがあると仮定します)。このようにして、セット内の単語を検索し、セットにまだその単語が含まれていない場合にのみ K,V ペアを出力できます (エントリをまだ出力していないことを示します)。セットに単語が含まれていない場合は、単語とドキュメント ID のペアを出力し、単語でセットを更新します。

セットが大きすぎる場合 (たとえば 5000 または 10000 エントリ)、それをクリアして最初からやり直してください。このようにして、マッパーから出力される値の数が劇的に表示されます (値のドメインまたは値のセットが小さい場合、単語はこれの良い例です)。

また、コンバイナー フェーズでリデューサー ロジックを導入することもできます。

警告の最後の言葉 - Key / Value オブジェクトをセットに追加する際には注意してください (Matt D の回答のように)。参照 - 常にオブジェクトのコピーを作成します。

役立つと思われるローカル マップの集計に関する記事 (ワード カウントの例) があります。

于 2012-04-24T21:07:42.270 に答える