mapreduce实现一天内用户使用总时长

本文介绍了一种使用MapReduce技术统计用户一天内累计在线总时长的方法。通过自定义Mapper和Reducer处理用户访问记录,实现了精确计算每位用户的在线时间,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

根据公司需要使用mapreduce实现用户一天内使用总时长,代码如下:
package com.online.time;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;

public class UserOnlineTime {
	// mapper
	public static class OnlineMapper extends Mapper{
		private Text info = new Text();
		private Text otherInfo = new Text();
		// 数据输入格式:手机号(空格)数据访问时间(空格)动作(空格)访问的页面
		public void map(Object key, Text value, Context context) throws IOException, InterruptedException{
			String[] userInfo = value.toString().split(" ");
			String phone = userInfo[1];
			String other = timeToSecond(userInfo[0]) + "-" + userInfo[2] + "-" + userInfo[3];
			
			info.set(phone);
			otherInfo.set(other);
			// map的输出为:<手机号, 数据访问时间-动作标识(共有两个动作:In-进入页面,Out-退出页面)-访问的页面>
			context.write(info, otherInfo);
		}
	}

	// reduce
	public static class OnlineReduce extends Reducer{
		private Text result = new Text();
		// 获取昨天日期
		String yesterday = getYesterday();
		public void reduce(Text key, Iterable values, Context context) throws IOException, InterruptedException{
			List list = new ArrayList();
			for (Text val : values) {
				list.add(val.toString());
			}
			
			// 将集合转换为数组
			String[] valueArray = (String[]) list.toArray(new String[list.size()]);
			
			String[] resultInfo = sortReduceValue(valueArray);
			
			// 36666-In-HouseController
			int resultTime = 0;
			for(int i = 0; i < resultInfo.length; i++){
				String[] tls = resultInfo[i].split("-");
				
				if("In".equals(tls[1])){
					// 数据已按照时间升序排序
					int inTime = Integer.parseInt(tls[0]);
					String inLocal = tls[2];
					
					for(int j = i + 1; j < resultInfo.length; j++){
						String[] ols = resultInfo[j].split("-");
						String outLocal = ols[2];
						
						// 判断是否是同一页面
						if(inLocal.equals(outLocal)){
							if("Out".equals(ols[1])){
								int outTime = Integer.parseInt(ols[0]);
								
								// 在本页面停留的时间
								int stayTime = outTime - inTime;
								// 在本页面停留时间大于10分钟,则抛弃此数据
								if(stayTime < 600){
									resultTime = resultTime + stayTime;
									break;
								}else{
									break;
								}
							}else{
								break;
							}
						}
					}
				}
			}
			
			if(resultTime == 0){
				resultTime = 1;
			}
			
			// 数据分隔符为 Tab键,方便交给hive管理
			result.set(String.valueOf(resultTime) + "	" + yesterday);
			context.write(key, result);
		}
	}
	
	// 将时间转换为秒
	public static int timeToSecond(String time){
		int second = 0;
		if(time != null && !"".equals(time)){
			String[] times = time.split(":");
			int hourSecond = Integer.parseInt(times[1]) * 60 * 60;
			int minuteSecond = Integer.parseInt(times[2]) * 60;
			second = hourSecond + minuteSecond + Integer.parseInt(times[3]);
		}
		return second;
	}
	
	// 对reduce数据按照时间从小到大排序(冒泡排序)
	public static String[] sortReduceValue(String[] values){
        for (int i = 0; i < values.length -1; i++){  
            for(int j = 0 ;j < values.length - i - 1; j++){
                if(Integer.parseInt(values[j].split("-")[0]) > Integer.parseInt(values[j + 1].split("-")[0])){
                    String temp = values[j];
                    values[j] = values[j + 1];
                    values[j + 1] = temp;
                }
            }            
        }
        return values;
	}
	
	// 获取昨天的日期
	public static String getYesterday(){
		Calendar cal=Calendar.getInstance();
		cal.add(Calendar.DATE,-1);
		Date time=cal.getTime();
		String yesterday = new SimpleDateFormat("yyyyMMdd").format(time);
		return yesterday;
	}
	
	// main函数
	@SuppressWarnings("deprecation")
	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
		
		if(otherArgs.length != 2){
			System.err.println("Usage: wordcount  ");
			System.exit(2);
		}
		
		Job job = new Job(conf, "User Online Job");
		job.setNumReduceTasks(1);
		job.setJarByClass(UserOnlineTime.class);
		job.setMapperClass(OnlineMapper.class);
		job.setReducerClass(OnlineReduce.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Text.class);
		FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
		FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
		System.exit(job.waitForCompletion(true) ? 0 : 1);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值