继前篇blogseq2sparse(3)之TFParitialVectorReducer源码分析 之后,继续分析下面的代码,本次分析的是PartialVectorMergeReducer的源码,这个reducer是下面的函数调用的:

PartialVectorMerger.mergePartialVectors(partialVectorPaths, outputDir, conf, normPower, logNormalize,
maxTermDimension[0], sequentialAccess, namedVectors, numReducers);

这个调用是在前面blog分析的makePartialVectors函数之后,先make,然后在merge。这个函数的同样启动了一个Job,不过这个Job和前面的一样,没有Mapper,只有Reducer,下面来分析这个Reducer。这个reducer同样只包含setup和reduce而已,在setup中只是设置了一些基本的参数,这些参数在reduce中会用到;比如normPower,这个参数是作为一个if的条件判断,这里先明确下它的值,方便后面reduce分析。在参数解释中:

  1. --norm (-n) norm                    The norm to use, expressed as either a
  2. float or "INF" if you want to use the
  3. Infinite norm.  Must be greater or equal
  4. to 0.  The default is not to normalize

可以看到它的默认值是not to normalize,其实就是-1;

下面分析reduce:(源码如下:)

Vector vector = new RandomAccessSparseVector(dimension, 10);
for (VectorWritable value : values) {
vector.assign(value.get(), Functions.PLUS);
}
if (normPower != PartialVectorMerger.NO_NORMALIZING) {
if (logNormalize) {
vector = vector.logNormalize(normPower);
} else {
vector = vector.normalize(normPower);
}
}
if (sequentialAccess) {
vector = new SequentialAccessSparseVector(vector);
} if (namedVector) {
vector = new NamedVector(vector, key.toString());
} VectorWritable vectorWritable = new VectorWritable(vector);
context.write(key, vectorWritable);

首先,reduce接受的map输出的key是文件名,value是tokenDocument后的文件所有的单词的集合,这里就可以看出key是没有重复的,所以第一个for循环其实就只执行了一次。但是假如这里又同名的文件,那么这里执行的是什么操作呢?看代码很容易就猜到应该是把同名的文件中的单词对应的次数对应相加,然后作为一个文件,也就是所谓的merge,整合。然后到if判断,前面分析可以知道这个if是不进入的,所以不加以分析。如果硬要分析的话,单看函数名大概可以猜到应该是把出现的次数进行归一化什么之类的,比如本来的单词个数分别是[4,5,2,7],那么经过了if里面的这个次数可能变为[log(4),log(5),log(2),log(7)]之类的东西,这里应该是要防止单词的次数太大,不方便后面的计算吧。最后就是重新改下value的格式,然后就输出了。这里可以看到这个操作的输出其实和前一个make的输出是一模一样的。可以编写下面的代码进行验证:

package mahout.fansy.test.bayes;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.util.ReflectionUtils;
import org.apache.mahout.math.VectorWritable; public class PartialVectorMergeReducerFollow {
private static Configuration conf = new Configuration();
private static String mapOutPath;
static{
conf.set("mapred.job.tracker", "ubuntu:9001");
// mapOutPath="hdfs://ubuntu:9000/home/mahout/mahout-work-mahout0/20news-vectors/partial-vectors-0/part-r-00000";
mapOutPath="hdfs://ubuntu:9000/home/mahout/mahout-work-mahout/20news-vectors/tf-vectors/part-r-00000";
}
public static void main(String[] args) throws IOException {
getKeyAndValues();
} /**
* 获得PartialVectorMerger的map输出;
* @return
* @throws IOException
*/
public static Map<String,List<VectorWritable>> getKeyAndValues() throws IOException{
Map<String,List<VectorWritable>> map=new HashMap<String,List<VectorWritable>>(); FileSystem fs = FileSystem.get(URI.create(mapOutPath), conf);
Path path = new Path(mapOutPath); SequenceFile.Reader reader = null;
try {
reader = new SequenceFile.Reader(fs, path, conf);
Writable key = (Writable)
ReflectionUtils.newInstance(reader.getKeyClass(), conf);
Writable value = (Writable)
ReflectionUtils.newInstance(reader.getValueClass(), conf);
while (reader.next(key, value)) {
String k=key.toString();
VectorWritable v=(VectorWritable)value;
v=new VectorWritable(v.get()); // 第一种方式
if(map.containsKey(k)){ //如果包含则把其value值取出来加上一个新的vectorWritable到list中
List<VectorWritable> list=map.get(k);
list.add(v);
map.put(k, list);
}else{ // 否则直接new一个新的list,添加该vectorWritable到list中
List<VectorWritable> list=new ArrayList<VectorWritable>();
list.clear();
list.add(v);
// List<VectorWritable> listCopy=new ArrayList<VectorWritable>();
// listCopy.addAll(list); // 第二种方式
map.put(k, list); }
}
} finally {
IOUtils.closeStream(reader);
}
return map;
} }

这里有点小纠结的地方,就是value和v的地址是一样的,如果使用第二种方式是不行的,第二种方式没有实现list的深复制,所以v的地址和value的地址是一样的,这样导致map的输出的key是不一样的,但是所有key的value都是一样的;有下面的图像可以大概看出一二:


这里说看出一二是指,前面两次的value值中的单词顺序不是按照一样的规则排序的,如果你把所有的value值都拷贝下来,前后两次对比,就会发现,是一样的。

分享,快乐,成长

转载请注明出处:http://blog.csdn.net/fansy1990

seq2sparse(4)之PartialVectorMergeReducer源码分析的更多相关文章

  1. Mahout源码分析之 -- 文档向量化TF-IDF

    fesh个人实践,欢迎经验交流!Blog地址:http://www.cnblogs.com/fesh/p/3775429.html Mahout之SparseVectorsFromSequenceFi ...

  2. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  3. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  4. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  5. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  6. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  7. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  8. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  9. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

随机推荐

  1. unexpected nil window in _UIApplicationHandleEventFromQueueEvent...

    unexpected nil window in _UIApplicationHandleEventFromQueueEvent, _windowServerHitTestWindow: <UI ...

  2. windows下安装CI框架

    CI框架是一个非常流行的 mvc框架, CI框架如何安装和使用,在CI中文网已经讲的比较详细了 ,这里记录下几个需要注意的地方. 一. index.php问题 把压缩包下载解压到项目根目录即可运行里面 ...

  3. STL中的set容器

    #include <iostream> #include <set> using namespace std; int main() { set<int> s; s ...

  4. PAT - IO - 螺旋方阵

    所谓“螺旋方阵”,是指对任意给定的N,将1到N*N的数字从左上角第1个格子开始,按顺时针螺旋方向顺序填入NxN的方阵里.本题要求构造这样的螺旋方阵. 输入格式: 输入在一行中给出一个正整数N(< ...

  5. BAT清理垃圾

    @echo off title ϵͳȥm del /f /s /q %systemdrive%\*.tmp del /f /s /q %systemdrive%\*._mp del /f /s /q ...

  6. jquery ajax (1)原始js 实现

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  7. Js监控回车事件

    标题通俗的说,也就是绑定当用户按下回车键要执行的事件. 下面,入正题. 第一步,先编写简单的页面代码,这里我们只需要一个按钮就足够了.当然,还有按钮事件. <html> <head& ...

  8. Xcode can't verify the identity of the server

    当升级了苹果系统到 OS X El Captain 之后  ,打开Xcode 有时候会报错 如图 而且打开 svn  也会出类似错误  点击continue  了  下次 还会 出现 .这个很好解决 ...

  9. Logger之Logger.getLogger(CLass)

    之前一直在使用System.out.println()来调试.但是用这种方式开发项目部署到生产环境,会因为众多的控制台输出降低应用的性能.这时候Log4J就成为可平衡开发和部署应用的利器了. 在项目中 ...

  10. Ratchet(WebSockets for PHP)的官方TUTORIALS 的实践

    前几天稍微看了一下Ratchet,并且实践了一下它官方例子.所以现在就将实践的过程记录下来. 在具体实践之前先将Ratchet是什么东东,要先说明一下.以下的英文是从官方copy过来的 Ratchet ...