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

描绘产品所有用户的访问的功能路径树,话就不多说,闷得慌

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);  
	declare @yesInt int;
	set @yesInt=CAST(CONVERT(varchar(8),@yestoday,112) as int);

	declare @tomorrow datetime;
	set @tomorrow=dateadd(DAY,1,@today);
	declare @tomorrowInt int;
	set @tomorrowInt=CAST(CONVERT(varchar(8),@tomorrow,112) as int);
	 

	declare @tomorrowpathTable varchar(100);
	set @tomorrowpathTable = ‘MobileFunctionLog_‘ + CAST( YEAR(@tomorrow) as nvarchar(10));

	declare @yespathTable varchar(100);
	set @yespathTable = ‘MobileFunctionLog_‘ + CAST(YEAR(@yestoday) as nvarchar(10));

	declare @pathTable varchar(100);
	set @pathTable = ‘MobileFunctionLog_‘ + CAST(YEAR(@today) as nvarchar(10));

	declare @sql nvarchar(max);
	declare @part tinyint;
	set @part=0; 
	create table #resultbyversion(softid int,platform int,versionid int,functionid int,Pid int,ordernum int,functionpath varchar(200),optiontimes int);
	create table #result(softid int,platform int,functionid int,Pid int,ordernum int,functionpath varchar(200),optiontimes int)
	while(@part<128)
	begin
		 
       --得出昨天会话
	   set @sql=‘ select distinct SoftID,Platform,VersionID,SessionID,IMEI
				into ##tempyes
				from ‘+ @yespathTable+
				‘ where  [email protected] and [email protected]‘;
	   
	   EXEC sp_executesql @sql,N‘@part tinyint,@yesInt int‘,@part,@yesInt;

	   --得出明天的会话
	   set @sql=‘ select distinct SoftID,Platform,VersionID,SessionID,IMEI
				into ##temptomorrow
				from ‘+ @tomorrowpathTable+
				‘ where [email protected] and [email protected]‘;
	   
	   EXEC sp_executesql @sql,N‘@part tinyint,@tomorrowInt int‘,@part,@tomorrowInt;		

		set @sql=‘select distinct SoftID, Platform, VersionID, SessionID, FunctionID, IMEI, OptionTime,NeedRecord
		into ##OneDayData
	    from ‘[email protected]+
		‘ where [email protected] and [email protected]‘

		EXEC sp_executesql @sql,N‘@part tinyint,@statdate int‘,@part,@statdate;

		Delete A from 
		##OneDayData A inner join
		##tempyes B
		on A.SoftID=B.SoftID AND A.Platform=B.Platform And A.VersionID=B.VersionID
		AND A.SessionID=B.SessionID AND A.IMEI=B.IMEI;

		Delete A from 
		##OneDayData A inner join
		##temptomorrow B
		on A.SoftID=B.SoftID AND A.Platform=B.Platform And A.VersionID=B.VersionID
		AND A.SessionID=B.SessionID AND A.IMEI=B.IMEI;
                ---上述俩处完成清理缓存数据和脏数据
		drop table ##tempyes;
		drop table ##temptomorrow;

		select SoftID, Platform, VersionID, SessionID, FunctionID, IMEI, OptionTime,NeedRecord,
		ROW_NUMBER() over( partition by SoftID, Platform, VersionID, SessionID, IMEI Order By OptionTime asc) ordernum
		into #LastOneData
		from ##OneDayData ;

		drop table ##OneDayData;
		--得出标准路径 (干掉了F1->F1->F2 这种非标准路径)
		with etc2 as
		(
			select  SoftID,Platform,VersionID,SessionId,FunctionID,IMEI,OptionTime,NeedRecord,OrderNum,isnull(Pid,0) Pid  from
			(
				select  A.SoftID, A.Platform, A.VersionID, A.SessionId, A.FunctionID, A.IMEI, A.OptionTime,A.NeedRecord,
				A.OrderNum,B.FunctionID Pid
				from #LastOneData A
				left join #LastOneData B
				ON  A.SoftID=B.SoftID AND A.Platform=B.Platform And A.VersionID=B.VersionID
				AND A.SessionID=B.SessionID AND A.IMEI=B.IMEI And A.ordernum=B.ordernum+1
		    ) A where (FunctionID!=Pid or Pid is null)
		 )
		 select * into #etc2 from etc2;
		 ---路径长度大于20的不要
		 select  SoftID, Platform, VersionID, SessionId, FunctionID, IMEI, OptionTime,NeedRecord,Pid,OrderNum
	     into #GroupData from
		 (
			 select SoftID, Platform, VersionID, SessionId, FunctionID, IMEI, OptionTime,NeedRecord,Pid ,
			 ROW_NUMBER() over(PARTITION by SoftID, Platform, VersionID, SessionId, IMEI order by  OptionTime asc  ) OrderNum
			 from #etc2
		 ) a  where OrderNum<20;
		 drop table #etc2;
		 --递归得出路径结果
		 with etc3 as
		 (
			select *,CAST(FunctionID as varchar(200)) FunctionPath from #GroupData where PID=0
			UNION ALL
			select A.*,CAST((B.FunctionPath +‘-‘+ CAST(A.FUNCTIONID as varchar(12))) AS VARCHAR(200) ) FunctionPath from #GroupData  A 
			INNER JOIN etc3 B
			on A.SessionID=B.SessionID and A.SoftID=B.SoftID and A.Platform=B.platform and A.versionid=B.versionid
			and A.Imei=B.Imei and A.OrderNum-B.OrderNum=1
		  )  
		 select * into  #temppathdata from etc3;
		 
		 insert into #resultbyversion    
		 select SoftID,Platform,VersionID,FunctionID,Pid,OrderNum, FunctionPath,sum(NeedRecord) OptionTimes  
		 from  #temppathdata 
		 group by SoftID,Platform,VersionID,FunctionID,Pid,OrderNum,FunctionPath; 
		 
		 insert into #result    
		 select SoftID,Platform,FunctionID,Pid,OrderNum, FunctionPath,sum(NeedRecord) OptionTimes  
		 from  #temppathdata 
		 group by SoftID,Platform,FunctionID,Pid,OrderNum,FunctionPath; 

		 drop table #GroupData;
	     drop table #LastOneData;
	     drop table #temppathdata;
		 set @[email protected]+1;
		 

	      print(@part);

	end
	select SoftID,Platform,VersionID,FunctionID,PID,OrderNum,FunctionPath,SUM(OptionTimes) OptionTimes
	into ##tmp_FuncPathByVersion
	from #resultbyversion
	group by SoftID,Platform,VersionID,FunctionID,OrderNum,Pid,FunctionPath
	having SUM(OptionTimes)>1

	select SoftID,Platform,FunctionID,PID,OrderNum,FunctionPath,SUM(OptionTimes) OptionTimes
	into ##tmp_FuncPath
	from #result
	group by SoftID,Platform,FunctionID,OrderNum,Pid,FunctionPath
	having SUM(OptionTimes)>1

	DROP TABLE #result;
	DROP TABLE #resultbyversion;

end

java 代码

@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();

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        String str = value.toString();
        String[] params = StringUtils.splitByWholeSeparatorPreserveAllTokens(str, "\t");

        //过滤数据
        if (params.length < 21 || params[12].equals("0") || !params[11].equals("False")) {
            return;
        }

        sb.delete(0, sb.length());

        //key:imei 0,softid 2,softversion 3,platform 4,sessionid 12
        //value:functionid 7,actiontime 9
        sb.append(params[0]).append("\t")
                .append(params[2]).append("\t")
                .append(params[3]).append("\t")
                .append(params[4]).append("\t")
                .append(params[12]);

        mKey.set(sb.toString());
        mValue.set(params[7] + "\t" + params[9]);

        context.write(mKey, mValue);
    }
}
    
    @ReduceConfig
    public static class ReduceTask extends Reducer<Text, Text, Text, IntWritable> {

        private Text rKey = new Text();
        private IntWritable rValue = new IntWritable();
        private String[] valItem = new String[2];
        private int i = 0;

        //key:actiontime value:lastfunctionid   firstfunctionid;
        private SortedMap<String, String> map = new TreeMap<String, String>();

        String pid = "";
        //lastid
        private String valTemp;
        private String firstid;

        private StringBuilder sbpathvalue = new StringBuilder();

        //key:road,value:functionid
        private Map<String, Integer> mRoads = new HashMap<String, Integer>();

        @Override
        protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
            map.clear();
            mRoads.clear();
            boolean isfirstid = true;
            sbpathvalue.delete(0, sbpathvalue.length());
            i = 0;

            for (Text item : values) {
                valItem = item.toString().split("\t");
                if (map.containsKey(valItem[1]) || valItem[1].equals("")) {
                    continue;
                }
                map.put(valItem[1], valItem[0]);
            }
            //添加退出功能点
            map.put(System.currentTimeMillis() + "", "-1");
            pid = "";
            valTemp = "";

            Iterator it = map.entrySet().iterator();

            //用户一次操作完整路径才计算路径长度
            int pathlengtn = 0;
            while (it.hasNext()) {
                Map.Entry<String, String> entry = (Map.Entry<String, String>) it.next();

                if (isfirstid) {
                    firstid = entry.getValue();
                    isfirstid = false;
                }
                pathlengtn = 0;

//                //过滤掉F1->F1
//                if (valTemp.equals(entry.getValue())){
//                    continue;
//                }
                valTemp = entry.getValue();

                //算法关键点
                int start = sbpathvalue.indexOf(valTemp);
                if (start >= 0) {
                    sbpathvalue = sbpathvalue.replace(start + valTemp.length(), sbpathvalue.length(), "");
                    //continue;
                }

                if (i != 0 && firstid.equals(valTemp)) {
                    i = 0;
                    sbpathvalue.delete(0, sbpathvalue.length());
                }

                if (i == 0) {
                    sbpathvalue.append(valTemp);
                    pid = valTemp;
                } else {
                    if (start == -1) {
                        sbpathvalue.append("_").append(valTemp);
                    }

                    int first = sbpathvalue.indexOf("_");
                    int last = sbpathvalue.lastIndexOf("_");
                    if (last == -1) {
                        pid = sbpathvalue.toString();
                    } else {
                        pid = sbpathvalue.substring(first == last ? 0 : sbpathvalue.substring(0, last).lastIndexOf("_") + 1, last);
                    }

                }
                //表示此路径为完整路
                if (valTemp.equals("-1")) {
                    if (sbpathvalue.toString().contains("_")) {
                        pathlengtn = sbpathvalue.toString().split("_").length;
                    }
                }

                String roadkey = pid + "\t" + valTemp + "\t" + pathlengtn + "\t" + sbpathvalue;
                if (!mRoads.containsKey(roadkey)) {
                    mRoads.put(roadkey, 1);
                } else {
                    mRoads.put(roadkey, mRoads.get(roadkey) + 1);
                }
                i++;
            }
            if (mRoads.size() <= 0) {
                return;
            }
            Iterator itRoads = mRoads.entrySet().iterator();

            while (itRoads.hasNext()) {
                Map.Entry<String, Integer> entry = (Map.Entry<String, Integer>) itRoads.next();
                rKey.set(key + "\t" + entry.getKey());
                rValue.set(entry.getValue());
                context.write(rKey, rValue);
            }
        }
    }
时间: 2024-10-10 23:33:44

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

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

.net + sql                     #region 构造统计日期临时表                     DataTable originalDates = new DataTable();                     DataColumn col = new DataColumn("OriginalStartDate", typeof(Int32));                     originalDates.Columns.Ad

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

*************************************************************************************************************** 在这里,我特别声明:本文章的源作者是   杨晓冬  (个人邮箱:[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

面试题精选:Android埋点,减少对业务代码的如侵!

前言 前几天去参加了一场面试.面试的题目大多很基础,有一道关于埋点的问题,面试官问我如果不用第三方SDK进行埋点,自己埋点的话,如何减少埋点对业务代码的ru侵. 当时没想太多,就说创建一个 BaseView 类,在这个类中进行埋点的操作,然后使需要进行埋点操作的 View 继承这个 Base 类.后来想想,这个方案其实存在很多问题,因为让每个需要埋点的 View 去继承 BaseView 类,说明 View 需要自定义,会耗费很多的时间和精力,对于自带的 Button 等控件的埋点,这种方法又无