移动分发端 基础统计指标经典业务代码节选--留存用户统计

.net + sql

                    #region 构造统计日期临时表

                    DataTable originalDates = new DataTable();
                    DataColumn col = new DataColumn("OriginalStartDate", typeof(Int32));
                    originalDates.Columns.Add(col);
                    col = new DataColumn("OriginalEndDate", typeof(Int32));
                    originalDates.Columns.Add(col);
                    int step = endDate.Subtract(startDate).Days + 1;
                    for (int i = 1; i <= 30; i++)
                    {
                        //如果是天的周期,增加到30日留存
                        if (period != PeriodOptions.Daily && i > 6) break;
                        DataRow newRow = originalDates.NewRow();
                        DateTime pStartDate;
                        DateTime pEndDate = Utility.GetNextStatDate(period, startDate, endDate, -i, out pStartDate);
                        newRow["OriginalStartDate"] = int.Parse(pStartDate.ToString("yyyyMMdd"));
                        newRow["OriginalEndDate"] = int.Parse(pEndDate.ToString("yyyyMMdd"));
                        originalDates.Rows.Add(newRow);
                    }

                    #endregion

                    //计算汇总
                    SqlParameter[] paramters = new SqlParameter[]
                    {
                        SqlParamHelper.MakeInParam("@dt", SqlDbType.Structured),
                        SqlParamHelper.MakeInParam("@StartDate", SqlDbType.Int, 4, startDate.ToString("yyyyMMdd")),
                        SqlParamHelper.MakeInParam("@EndDate", SqlDbType.Int, 4, endDate.ToString("yyyyMMdd")),
                        SqlParamHelper.MakeInParam("@Period", SqlDbType.TinyInt, 1, (int)period)                        
                    };
                    paramters[0].TypeName = "dbo.OriginalDatesType";
                    paramters[0].Value = originalDates;
                    DataSet ds = SqlHelper.ExecuteDataset(ComputingDB_ConnString, CommandType.StoredProcedure, "PR_StatRetainedUsers", paramters);
ALTER PROCEDURE [dbo].[PR_StatRetainedUsers] (
	@dt OriginalDatesType readonly,
	@StartDate int,
	@EndDate int, 
	@Period tinyint
	)
AS
begin
	create table #RetainedUsers(SoftID int,Platform tinyint,ChannelID int,OriginalStatDate int,RetainedUserCount int)
	declare @sql nvarchar(max);
	if (@Period = 1) begin
		set @sql = N‘insert into #RetainedUsers(SoftID,Platform,ChannelID,OriginalStatDate,RetainedUserCount)
					select A.SoftID,A.PLATFORM,A.FirstChannelID,B.OriginalEndDate,COUNT(distinct A.IMEI)
					from ...‘ + CAST((@StartDate / 10000) as nvarchar(10)) + N‘ A with(nolock) inner join @dt B
					on [email protected] and A.FirstLoginDate between B.OriginalStartDate and B.OriginalEndDate and (FromCache=0 or FromCache is null)
					group by A.SoftID,A.PLATFORM,A.FirstChannelID,B.OriginalEndDate;‘
		exec sp_executesql @sql, N‘@StartDate int,@dt OriginalDatesType readonly‘, @StartDate, @dt
	end else begin
		if (@StartDate/10000 = @EndDate / 10000) begin
			set @sql = N‘insert into #RetainedUsers(SoftID,Platform,ChannelID,OriginalStatDate,RetainedUserCount)
						select A.SoftID,A.PLATFORM,A.FirstChannelID,B.OriginalEndDate,COUNT(distinct A.IMEI)
						from ....‘ + CAST((@StartDate / 10000) as nvarchar(10)) + N‘ A with(nolock) inner join @dt B
						on [email protected] and A.LoginDate between @StartDate and @EndDate and A.FirstLoginDate between B.OriginalStartDate and B.OriginalEndDate and (FromCache=0 or FromCache is null)
						group by A.SoftID,A.PLATFORM,A.FirstChannelID,B.OriginalEndDate;‘
		end else begin
			set @sql = N‘insert into #RetainedUsers(SoftID,Platform,ChannelID,OriginalStatDate,RetainedUserCount)
						select A.SoftID,A.PLATFORM,A.FirstChannelID,B.OriginalEndDate,COUNT(distinct A.IMEI)
						from (
							select * from ....‘ + CAST((@StartDate / 10000) as nvarchar(10)) + N‘ with(nolock) where [email protected] and LoginDate between @StartDate and @EndDate and (FromCache=0 or FromCache is null)
							union all
							select * from ....

							‘ + CAST((@EndDate / 10000) as nvarchar(10)) + N‘ with(nolock) where [email protected] and LoginDate between @StartDate and @EndDate and (FromCache=0 or FromCache is null)) A
							inner join @dt B
						on A.FirstLoginDate between B.OriginalStartDate and B.OriginalEndDate
						group by A.SoftID,A.PLATFORM,A.FirstChannelID,B.OriginalEndDate;‘
		end
		declare @part tinyint = 0;
		while @part < 128 begin		 

			--if (@Period <> 12 or @part = 0) begin
			exec sp_executesql @sql, N‘@part tinyint,@StartDate int,@EndDate int,@dt OriginalDatesType readonly‘, @Part, @StartDate, @EndDate, @dt;
			--end

			set @part = @part + 1
		end
	end

	select @Period Period,OriginalStatDate,@EndDate StatDate,SoftID,Platform,-1 ID2,-1 ID1,0 OriginalNewUserCount,SUM(RetainedUserCount) RetainedUserCount 
	from #RetainedUsers
	group by SoftID,Platform,OriginalStatDate

	select @Period Period,OriginalStatDate,@EndDate StatDate,SoftID,Platform,ChannelID ID2,-1 ID1,0 OriginalNewUserCount,SUM(RetainedUserCount) RetainedUserCount 
	from #RetainedUsers
	group by SoftID,Platform,ChannelID,OriginalStatDate	

	drop table #RetainedUsers
end

hadoop

@MapConfig
public static class MapTask extends Mapper<LongWritable, Text, Text, Text> {
    private Text mKey = new Text();
    private Text mValue = new Text();
    private StringBuilder sb = new StringBuilder();
    private Map<String,Integer> map=new HashMap<String,Integer>();

    @Override
    protected void setup(Context context) throws IOException, InterruptedException {
        String enddate =context.getConfiguration().get("key_enddate");
        int period =Integer.parseInt(context.getConfiguration().get("period"));
        int step=Integer.parseInt(context.getConfiguration().get("step"));
        DateTime curstatdate=DateTime.parseToDateTime(enddate,"yyyyMMdd");

        //设置要计算留存的时间
        if (period==PeriodOptions.GetValueByEnum(PeriodOptions.Daily)){
            for (DateTime startdate=curstatdate.addDays(-30);new Double(DateTime.minusDay(curstatdate,startdate)).intValue()>0;startdate=startdate.addDays(1)){
                Integer tmp=Integer.parseInt(startdate.toString("yyyyMMdd"));
                map.put(startdate.toString("yyyyMMdd"),tmp);
            }
        }else if(period==PeriodOptions.GetValueByEnum(PeriodOptions.Weekly)){
            for (DateTime startdate=curstatdate.addDays(-48);DateTime.minusDay(curstatdate,startdate)>0;startdate=startdate.addDays(1)){
                if (WeekOptions.GetEnumByValue(startdate.getDayOfWeek())== WeekOptions.SUNDAY){
                    Integer tmp=Integer.parseInt(startdate.toString("yyyyMMdd"));
                    for (DateTime substartdate=startdate.addDays(-step);new Double(DateTime.minusDay(startdate,substartdate)).intValue()>=0;substartdate=substartdate.addDays(1)){
                        map.put(substartdate.toString("yyyyMMdd"),tmp);
                    }
                }
            }
        }else if(period==PeriodOptions.GetValueByEnum(PeriodOptions.NaturalMonth)){
            for (DateTime startdate=curstatdate.addMonths(-7).addDays(1);DateTime.minusDay(curstatdate,startdate)>0;startdate=startdate.addDays(1)){
                if (startdate.addDays(1).day()==1){
                    Integer tmp=Integer.parseInt(startdate.toString("yyyyMMdd"));
                    for (DateTime substartdate=startdate.addMonths(-1).addDays(1);new Double(DateTime.minusDay(startdate,substartdate)).intValue()>0;substartdate=substartdate.addDays(1)){
                        map.put(substartdate.toString("yyyyMMdd"),tmp);
                    }
                }
            }
        }
    }
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

        String str = value.toString();
        String[] params = StringUtils.splitByWholeSeparatorPreserveAllTokens(str, "\t");

        if (!map.containsKey(params[23]) || (Integer.parseInt(params[15])&1)!=0 ){
            return;
        }
        int firstlogintime=map.get(params[23]);

        String enddate =context.getConfiguration().get("key_enddate");

        sb.delete(0, sb.length());
        //key<0:softid,2:platform,22 firstchannelid>
        //value<23 firstlogindate,4:logindate,3:imei>
        sb.append(params[0]).append("\t")
                .append(params[2]).append("\t")
                .append(params[22]);
        mKey.set(sb.toString());
        mValue.set(firstlogintime + "\t" + enddate + "\t" + params[3]);
        context.write(mKey, mValue);

        sb.delete(0, sb.length());
        sb.append(params[0]).append("\t")
                .append(params[2]).append("\t")
                .append(-1);
        mKey.set(sb.toString());
        mValue.set(firstlogintime + "\t" + enddate + "\t" + params[3]);
        context.write(mKey, mValue);
    }
    @Override
    protected void cleanup(Context context) throws IOException, InterruptedException {
        map.clear();
    }
}

//key<0:softid,2:platform,22 firstchannelid>
//value<23 firstlogindate,4:logindate,3:imei>
@CombineConfig
public static class CombineTask extends Reducer<Text, Text, Text, Text> {

    Text mvalue=new Text();
    //留存用户
    private Multiset<String> multiset=HashMultiset.create();
    @Override
    protected void reduce(Text key, Iterable<Text> values, Context context)
            throws IOException, InterruptedException {

        multiset.clear();
        for (Text item:values){
            multiset.add(item.toString());
        }

        for (String item:multiset.elementSet()){
            mvalue.set(item);
            context.write(key,mvalue);
        }
    }

}

//key<0:softid,2:platform,22 firstchannelid>
//value<23 firstlogindate,4:logindate,3:imei>
@ReduceConfig
public static class ReduceTask extends Reducer<Text, Text, Text, Text> {

    private Text mValue = new Text();
    //留存用户
    private Map<String, Multiset<Object>> MRetained = new HashMap<>();
    @Override
    protected void reduce(Text key, Iterable<Text> values, Context context)
            throws IOException, InterruptedException {

        for (Map.Entry<String, Multiset<Object>> map : MRetained.entrySet()) {
            MRetained.get(map.getKey()).clear();
        }
        MRetained.clear();

        for (Text item : values) {
            String[] params = StringUtils.splitByWholeSeparatorPreserveAllTokens(item.toString(), "\t");
            String mapkey = params[0] + "\t" + params[1];

            if (!params[0].equals(params[1])) {
                if (!MRetained.containsKey(mapkey)) {
                    MRetained.put(mapkey, HashMultiset.create());
                }
                MRetained.get(mapkey).add(params[2]);
            }
        }
        String period = context.getConfiguration().get("period");
        for (Map.Entry<String, Multiset<Object>> map : MRetained.entrySet()) {
            if (map.getKey().split("\t") == null ) {
                continue;
            }
            mValue.set(period
                    + "\t" + map.getKey()
                    + "\t" + 0
                    + "\t" + map.getValue().elementSet().size());
            //softid,platform,channelid,period,originaldate,statdate,OriginalNewUserCount,RetainedUserCount
            context.write(key, mValue);
        }
    }

}
时间: 2024-08-28 22:42:22

移动分发端 基础统计指标经典业务代码节选--留存用户统计的相关文章

移动分发端 基础统计指标经典业务代码节选--功能路径统计

描绘产品所有用户的访问的功能路径树,话就不多说,闷得慌 sql 代码 ALTER procedure [dbo].[PR_StatFuncPath](@statdate int) as  begin declare @today datetime; set @today=CAST(convert(varchar(8),@statdate) as datetime); declare @yestoday datetime; set @yestoday=dateadd(DAY,-1,@today);

业务代码与非业务代码

1.什么是业务代码? 直接用于实现用户需求的代码就是业务代码,比如用户需要查询某个数据,那么直接查询数据库,返回结果的代码,就是业务代码. 2.什么是非业务代码? 辅助业务代码,一般可以脱离业务而存在的代码,比如用户查询某个数据,接收用户输入可能出现中文乱码,这时解决中文乱码的代码并不直接包含在用户的目的中,可以脱离当前业务,应用于其他业务中,这一代码就是非业务代码. 3.区分业务代码与非业务代码的标准 是否被目的直接指向,是否可以脱离具体业务而存在. 4.区分业务代码与非业务代码的目的 区分业

图像处理与计算机视觉基础,经典以及最近发展

*************************************************************************************************************** 在这里,我特别声明:本文章的源作者是   杨晓冬  (个人邮箱:[email protected]).原文的链接是 http://www.iask.sina.com.cn/u/2252291285/ish.版权归 杨晓冬 朋友所有. 我非常感谢原作者辛勤地编写本文章,并愿意共

天天写业务代码,如何成为技术大牛

前序 在工作之余浏览公司的技术网站,看到了以下这篇文章,细细读来真心觉得不错,写得有价值很实在.于是想联系下作者,问一下是否可以转载.打开钉钉一搜,作者是资深技术专家,差不多就是技术总监级别啊,这也从侧面旁征了,以下的内容是有其亲身经历,切实体会的,而不是鸡汤口号之流.相较与作者的级别,自己确实惭愧汗颜,所以没好直接聊天询问而是在文章底下留言.在得到了作者的同意后将文章的内容贴到这里,作为分享也作为自己的鞭策和提醒.在这里谢谢我的大牛同事了^_^. ....................以下内

天天写业务代码,如何成为技术大牛?

不管是开发.测试.运维,每个技术人员心理多多少少都有一个成为技术大牛的梦,毕竟"梦想总是要有的,万一实现了呢"!正是对技术梦的追求,促使我们不断地努力和提升自己. 然而"梦想是美好的,现实却是残酷的",很多同学在实际工作后就会发现,梦想是成为大牛,但做的事情看起来跟大牛都不沾边,例如,程序员说"天天写业务代码还加班,如何才能成为技术大牛",测试说"每天都有执行不完的测试用例",运维说"扛机器接网线敲shell命令,这

业务代码解构利器--SWAK

摘要: 作者:闲鱼技术-紫思 简介 业务的不断发展.商品类型的不断增多.不断添加的业务需求使得闲鱼的代码出现"bad smell"--平台代码和业务代码耦合严重难以分离:业务和业务之间代码交织缺少拆解.这也是行业中的通病. 作者:闲鱼技术-紫思 简介业务的不断发展.商品类型的不断增多.不断添加的业务需求使得闲鱼的代码出现"bad smell"--平台代码和业务代码耦合严重难以分离:业务和业务之间代码交织缺少拆解.这也是行业中的通病.为解决此类问题,闲鱼自研了一套技术

天天写业务代码的那些年,我们是如何成长过来的

比起写业务代码更不幸的是,主要工作是修 Bug,bug,buG, bUg. 在一家大的公司里,不同的人总会有不同的运气: 运气好的人遇上一个好的项目,升职加薪,从此就走上了人生的巅峰. 运气差的人摊上一个差的项目,升不了职,少加了薪,并且还获得不了技术成长. 我刚毕业那会儿,所在团队的主要工作是,维护一个『又老又旧』的系统.比起写业务代码更不幸的是,我们的主要工作是修 Bug,bug,buG, bUg. 那一年多里,尽管都是维护旧系统和少量的新需求,我们还是在飞速的成长~~.而来源主要是: 组内

JVM 性能调优实战之:使用阿里开源工具 TProfiler 在海量业务代码中精确定位性能代码

本文是<JVM 性能调优实战之:一次系统性能瓶颈的寻找过程> 的后续篇,该篇介绍了如何使用 JDK 自身提供的工具进行 JVM 调优将 TPS 由 2.5 提升到 20 (提升了 7 倍),并准确定位系统瓶颈:我们应用里静态对象不是太多.有大量的业务线程在频繁创建一些生命周期很长的临时对象,代码里有问题.那么问题来了,如何在海量业务代码里边准确定位这些性能代码?本文将介绍如何使用阿里开源工具 TProfiler 来定位这些性能代码,成功解决掉了 GC 过于频繁的性能瓶颈,并最终在上次优化的基础

如何从业务代码中抽离出可复用的微组件

背景 很多业务代码,掺杂着一些通用的大段逻辑:容易导致的后果是,当需要类似功能时,不得不重新写一道,或者复制出几乎相同的代码块,让系统的无序性蹭蹭蹭往上涨. 具有良好抽象思维的有心的开发者,则会仔细观察到这种现象,将这些通用的大块逻辑抽离出来,做成一个可复用的微组件,使得以后再做类似的事情,只需要付出很小的工作即可. 那么,如何从业务代码中抽离出可复用的微组件,使得一类事情只需要做一次,今后可以反复地复用呢? 本文将以一个例子来说明. 在业务开发中,常常需要根据一批 id 查到相对应的 name