MapReduce用户行为数据分析之最多购买组合

需求分析:
通过对购买组合的分析可以对商品进行捆绑销售或者特殊促销的手段来提高销量,利用Map统计所有用户的购买商品情况,在Reduce阶段将所有商品组合,最后在cleanup阶段统计各种组合商品的购买次数并输出Top5。
测试数据如下:
在这里插入图片描述
在这里插入图片描述
结果:
在这里插入图片描述
可视化:如下图4所示
在这里插入图片描述
部分代码分析:
reduce阶段:
map阶段use_ID和time为key,ite_ID为value。reduce阶段购买组合为key,组合购买次数为value。
reduce阶段取出map的value:同一用户同一时间购买的商品,并放在一个集合中,嵌套的for循环是在集合中分别组合同一用户同一时间购买的商品,并将所有组合商品放到一个新的集合中。
在这里插入图片描述
注:要用嵌套for循环将ite_ID两两组合,需要将item放到集合中!
在这里插入图片描述
这段代码的作用是为了避免下述情况:
在这里插入图片描述
这两个组合实际上是相同的。所以,将ite_ID的第一个字符排序避免上述情况的发生。
cleanup阶段:
将集合中的各种ite_ID组合相比较,相等则sum++,来统计各种组合的个数。
list2.remove这行代码的作用是为了避免下述情况的发生:
在这里插入图片描述
集合中前面的元素已完成遍历整个集合的比较并计数,如果不删除集合后面的元素,再比较前面的元素,会重复计数。
在这里插入图片描述
注:此循环不能写在reduce中,只能写在clean up阶段。因为reduce()会执行多次,一个key就会执行一次reduce()。而对于组合的统计要在所有的ite_ID组合写到集合中后计数,所以要写在cleanup中。
完整代码:
map阶段:

package combination;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
public class CombinationMapper extends Mapper<LongWritable,Text,Text,Text>{
    
    Text k=new Text();
    Text v=new Text();
    @Override
    protected void map(LongWritable key, Text value, Context context) 
            throws IOException, InterruptedException {
        //1 获取一行
        String line = value.toString();
        
        //2 切割单词
        String[] fields = line.split("\t");
        
        String keywords=fields[0]+" "+fields[5];
        
        //3 use_ID和time为key,ite_ID为value 
        k.set(keywords);
        v.set(fields[2]);
        
        //4 写出(测试数据假定0为购买)
        if(fields[4].equals("0")){
            
            context.write(k, v);     
     
        }
    }
}

reduce阶段:

package combination;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class CombinationReducer extends Reducer<Text,Text,Text,IntWritable>{
    Map<String,Integer> map=new HashMap<String,Integer>();
    IntWritable v=new IntWritable();
    List<Text> list2=new ArrayList<>();
    @Override
    protected void reduce(Text key, Iterable<Text> values, Context context) 
            throws IOException, InterruptedException {
        String combination;
        List<Text> list1=new ArrayList<>();
        for (Text value : values) {
            Text e=new Text(value.toString());
            list1.add(e);
        }
        for(int i=0;i<list1.size();i++){
            for(int j=i+1;j<list1.size();j++){
                if(list1.get(i)!=list1.get(j)){
                    if(list1.get(i).charAt(0)<list1.get(j).charAt(0)){
                        combination=list1.get(i)+" "+list1.get(j);
                    }else{
                        combination=list1.get(j)+" "+list1.get(i);
                    }
                    Text t=new Text(combination);
                    list2.add(t);
//                    context.write(new Text(combination), new IntWritable(1));
                }
            }
        }
    }
//
    @Override
    protected void cleanup(Context context) throws IOException, InterruptedException {
        for(int m=0;m<list2.size();m++){
            int sum=1;
            for(int n=m+1;n<list2.size();n++){
                if(list2.get(m).equals(list2.get(n))){
                    sum++;
                    list2.remove(n);
//                    context.write(list2.get(m),new IntWritable(sum));
                }
                
            }
//            context.write(list2.get(m),new IntWritable(sum));
            map.put(list2.get(m).toString(), sum);
        }
        
        //这里将map.entrySet()转换成list
        List<Map.Entry<String,Integer>> list=new LinkedList<Map.Entry<String,Integer>>(map.entrySet());
        //通过比较器来实现排序
        Collections.sort(list, new Comparator<Map.Entry<String, Integer>>(){
            //升序排序
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                return (int)(o2.getValue()-o1.getValue());
            }
        });
        
        for(int i=0;i<3;i++){
            context.write(new Text(list.get(i).getKey()), new IntWritable(list.get(i).getValue()));
        }
    }
    
}

driver:

package combination;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class Combination {

    public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException{
        Configuration conf = new Configuration();
        
        //1 获取job对象
        Job job = Job.getInstance(conf);
        
        //2 设置jar存储位置
        job.setJarByClass(Combination.class);
        
        //3 关联map和reduce类
        job.setMapperClass(CombinationMapper.class);
        job.setReducerClass(CombinationReducer.class);
        
        //4 设置Mapper阶段输出数据的key和value类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(Text.class);
        
        //5 设置最终数据输出的key和value类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);
        
        //6 设置输入路径和输出路径
        FileInputFormat.setInputPaths(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        //7 提交job
        //job.submit();
        boolean result = job.waitForCompletion(true);
        System.exit(result? 0 : 1);
        }    
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值