(JAVA) FP_Growth算法对MapReduce并行化的实现
在上一步JAVA实现FP_growth算法时,提及到了FP_Growth算法面临的一些问题:当事务数过大或者支持度阈值过小时,会导致FP_Growth算法执行起来递归深度太大,超出编译环境的处理范围。
因为FP_Growth算法的一些特性:
1.对于每一个频繁一项集,只需要知道和它相关联的事务而不需要知道全部事务。
2.对于任意事务,必须要共享的信息只有项头表。
出于这些特性,FP_growth算法满足MapReduce的特性:分而治之。
下面带来FP_Growth算法MapReduce并行化的java代码,共有三个Job,分别完成如下功能:
1.统计购物篮数据中各项的支持度;
2.将各项按支持度大小排序,并去除非频繁的项;
3.求出频繁多项集。
其中,第一个job实现的功能其实就是词频统计,第二个job实现的功能为排序。第三个Job中使用了作者之前编写的FPTree类和TreeNode类,具体代码参照JAVA实现FP_Growth算法(附详细注释)https://blog.csdn.net/weixin_40020929/article/details/85562071。
main方法
import java.io.File;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.KeyValueTextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class mainClass_fp {
public static String MASTER_IP = YOUR_MASTER_IP; //集群中master的IP地址
private static String[] tmpFiles = {
"/tmp/WordFrequence"}; //中间临时文件存放路径
public static String splitChar = ","; //规定文件分隔符
/*
* @param0 :输入路径,文件要求为购物篮数据
* @param1 :输出路径
* @param2 :支持度,可为比例值也可为绝对值
*/
public static void main(String[] args)throws Exception {
File jarFile = EJob.createTempJar("bin");
ClassLoader classLoader = EJob.getClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
Configuration conf = new Configuration(true);
conf.setBoolean("mapreduce.app-submission.cross-platform",true);
conf.set("mapreduce.framework.name", "local"); //本地伪分布时可设为“local”便于调试,集群式使用“yarn”
conf.set("fs.defaultFS", "hdfs://" + MASTER_IP + ":8020/");
conf.set("yarn.resourcemanager.address", MASTER_IP + ":8032");
conf.set("yarn.resourcemanager.scheduler.address", MASTER_IP + ":8030");
String time = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); //为输出路径加上时间变量,避免输出路径冲突
String[] paths = new String[3]; //paths存放所有输入输出路径
paths[0] = args[0];
paths[1] = args[1] + "_oneItem" + time; //存放频繁一项集的文件路径
paths[2] = args[1] + time; //存放频繁多项集的文件路径
double support = Double.parseDouble(args[2]);
Job job_count = Job.getInstance(conf, "WordCount"); /*job_count实现功能为统计各项的支持度(即统计单词词频)*/
job_count.setJarByClass(mainClass_fp.class);
((JobConf) job_count.getConfiguration()).setJar(jarFile.toString());
job_count.setMapperClass(wcMapper.class);
job_count.setCombinerClass(wcReducer.class); //统计词频时,为提高传输效率,可以设置Combiner,代码与Reducer相同
job_count.setReducerClass(wcReducer.class);
job_count.setOutputKeyClass(Text.class);
job_count.setOutputValueClass(IntWritable.class);
FileInputFormat.addInputPath(job_count, new Path(paths[0]));
FileOutputFormat.setOutputPath(job_count, new Path(tmpFiles[0])); //输出结果存放到临时文件中
if (!job_count.waitForCompletion(true)) {
System.out.println("error!");
System.exit(-1);
} //若支持度输入为绝对值,则不需要重复计算,下一句可删除
support = support * job_count.getCounters().findCounter(WordFrequency.Counter.LINE_LEN).getValue();
conf.setDouble("support", support); //将支持度作为全局变量
Job job_sort = Job.getInstance(conf, "WordSort"); /*job_sort实现的功能为将各项按支持度降序排列*/
job_sort.setJarByClass(mainClass_fp.class);
((JobConf) job_sort.getConfiguration()).setJar(jarFile.toString());
job_sort.setInputFo