seq2sparse(4)之PartialVectorMergeReducer源码分析
继前篇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分析。在参数解释中:
- --norm (-n) norm The norm to use, expressed as either a
- float or "INF" if you want to use the
- Infinite norm. Must be greater or equal
- 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源码分析的更多相关文章
- Mahout源码分析之 -- 文档向量化TF-IDF
fesh个人实践,欢迎经验交流!Blog地址:http://www.cnblogs.com/fesh/p/3775429.html Mahout之SparseVectorsFromSequenceFi ...
- ABP源码分析一:整体项目结构及目录
ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- nginx源码分析之网络初始化
nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...
- zookeeper源码分析之五服务端(集群leader)处理请求流程
leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...
- zookeeper源码分析之四服务端(单机)处理请求流程
上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...
- zookeeper源码分析之三客户端发送请求流程
znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...
- java使用websocket,并且获取HttpSession,源码分析
转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...
- ABP源码分析二:ABP中配置的注册和初始化
一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...
随机推荐
- 认识div(division)在排版中的作用
在网页制作过程过中,可以把一些独立的逻辑部分划分出来,放在一个<div>标签中,这个<div>标签的作用就相当于一个容器. 语法: <div>…</div&g ...
- bash shell学习-正则表达式基础 (笔记)
A gentleman is open-minded and optimistic; a small person is narrow-minded and pessimistic. "君子 ...
- 一款好看+极简到不行的HTML5音乐播放器-skPlayer
Demo: github skPlayer在线预览 预览: 单曲循环模式预览: 使用方法: 方式1:NPM npm install skplayer 方式2:引入文件 引入css文件: <lin ...
- @Index用法——javax.persistence.Index
package com.springup.utiku.model; import java.io.Serializable; import javax.persistence.Entity; impo ...
- C#三种方式实现序列化(转)
序列化和反序列化我们可能经常会听到,其实通俗一点的解释,序列化就是把一个对象保存到一个文件或数据库字段中去,反序列化就是在适当的时候把这个文件再转化成原来的对象使用. 序列化和反序列化最主要的作用有: ...
- [HttpClient]简单使用GET请求
package com.jerry.httpclient; import java.io.IOException; import org.apache.http.HttpEntity; import ...
- php 实用函数
第一次随笔,写一些自己工作当中比较实用的函数吧. 数组函数: 1 array_column --返回数组当中指定的一列 用法一:返回数组当中指定的一列 应用场景:取出全班同学的id,去其他表查询这些同 ...
- php转化输入日期为Unix 纪元到当前时间的秒数 日期筛选
多条件筛选时 日期筛选 部分 demo http://pan.baidu.com/s/1hqGF5Ik 时间输入控件http://www.jq22.com/jquery-info332 输入控件 ...
- php设计模式之简单工厂模式
①抽象基类:类中定义抽象一些方法,用以在子类中实现 ②继承自抽象基类的子类:实现基类中的抽象方法 ③工厂类:用以实例化所有相对应的子类 /** * * 定义个抽象的类,让子类去继承实现它 * */ a ...
- CSU 1337(费马大定理)
CSU 1337 Time Limit:1000MS Memory Limit:131072KB 64bit IO Format:%lld & %llu Descrip ...