【问题标题】:MapReduce iterate values for tf-idf computationMapReduce 迭代 tf-idf 计算的值
【发布时间】:2017-06-25 11:24:16
【问题描述】:

我正在尝试做reducer,输入(键,值)对的格式如下:

  • 关键字:单词
  • 值:file=frequency,其中“file”是包含该单词的文件,“frequency”是该单词在 文件

reducer 的输出是一个 (key, value) 对

  • 键:字=文件
  • 值:该文件中该单词的 tf-idf

公式需要我知道两件事才能计算 tf-idf

  • 包含单词(即键)的文件数
  • 该词在文件中的个别频率

不知何故,我似乎必须循环遍历values 两次,一次是为了获取包含该单词的文件数量,另一次是处理 tf-idf。

伪代码如下:

//calculate tf-idf of every word in every document)
public static class CalReducer extends Reducer<Text, Text, Text, Text> {
    public void reduce(Text key, Iterable<Text> values, Context context)
            throws IOException, InterruptedException {
        // Note: key is a word, values are in the form of
        // (filename=frequency)

        // sum up the number of files containing a particular word

        // for every filename=frequency in the value, compute tf-idf of this
        // word in filename and output (word@filename, tfidf)
    }
}

我读到不可能循环两次values。一种替代方法可能是使用“缓存”,我尝试过,但结果很不稳定。

【问题讨论】:

  • 问题是?
  • 我了解您要做什么,但是您能否详细说明您期望从 mapper 和 reducer 中得到的输出类型?不清楚文件名=频率是什么意思?

标签: java hadoop mapreduce


【解决方案1】:
Text outputKey = new Text(); 
Text outputValue = new Text();

//calculate tf-idf of every word in every document)
public static class CalReducer extends Reducer<Text, Text, Text, Text> {
    public void reduce(Text key, Iterable<Text> values, Context context)
            throws IOException, InterruptedException {
        // Note: key is a word, values are in the form of
        // (filename=frequency)
        Map<String, Integer> tfs = new HashMap<>();
        for (Text value: values) {
            String[] valueParts = value.split("=");
            tfs.put(valueParts[0], Integer.parseInt(valueParts[1])); //do the necessary checks here
        }
        int numDocs = context.getInt("noOfDocuments"); //set this in the Driver, if you know it already, or set a counter in the mapper to get it here using getCounter() 
        double IDF = Math.log10((double)numDocs/tfs.keySet().size());

        // for every filename=frequency in the value, compute tf-idf of this
        // word in filename and output (word@filename, tfidf)
        for (String file : tfs.keySet()) {
            outputKey.set(key.toString()+"@"+file);
            outputValue.set(new String(tfs.get(file)*IDF)); //you could also set the outputValue to be a DoubleWritable
            context.write(outputKey, outputValue);
        }
    }
}

如果您将 tf 定义为 frequency / maxFrequency,您可以在第一个循环中找到 maxFrequency 并相应地更改 outputValue

如果要尝试单循环解决方案,则需要获取IDF,因此需要获取输入的编号values。 你可以在 Java 8 中使用:

long DF = values.spliterator().getExactSizeIfKnown();
double IDF = Math.log10((double)numDocs/DF);

this post 中的建议,或遵循同一帖子中不使用循环的其他建议(否则,您可以遵循上一个答案)。

在这种情况下,您的代码将是(我没有尝试过):

Text outputKey = new Text(); 
Text outputValue = new Text();

//calculate tf-idf of every word in every document)
public static class CalReducer extends Reducer<Text, Text, Text, Text> {
    public void reduce(Text key, Iterable<Text> values, Context context)
            throws IOException, InterruptedException {
        int numDocs = context.getInt("noOfDocuments"); //set this in the Driver, if you know it already, or set a counter in the mapper to get it here using getCounter() 
        long DF = values.spliterator().getExactSizeIfKnown();
        double IDF = Math.log10((double)numDocs/DF);            

        // Note: key is a word, values are in the form of
        // (filename=frequency)
        for (Text value: values) {
            String[] valueParts = value.split("=");
            outputKey.set(key.toString()+"@"+valueParts[0]);
            outputValue.set(new String(Integer.parseInt(valueParts[1]) * IDF);
            context.write(outputKey, outputValue);
        }           

    }
}

这也将节省一些内存,因为您不需要额外的地图(如果可以的话)。

编辑:上面的代码假定您已经知道文件名的每个单词的总频率,即相同的文件名不会多次出现在值中,但您可能想要检查它是否成立。否则,第二个解决方案不起作用,因为您必须在第一个循环中计算每个文件的总频率和。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-23
    • 2015-04-17
    • 2012-04-30
    • 2017-11-14
    • 1970-01-01
    • 2019-05-24
    • 2014-04-21
    • 2018-04-27
    相关资源
    最近更新 更多