需求如下
由于运营人员将分成比例设为0,导致publisherId=10714; media_id=2454; posid=2454105在[20180612,20180619]之间的estimated earnings数据为0
ecmp是千次展现的预估费用,公式是用estimated earnings除以impressions,再除以1000
所以修正主要是在过滤条件或者选择维度满足条件时做修正,因为情况比较多,下面先简单逐一列一下:
filters:
media_id=2454 或者 pos_id=2454105
fitler中如果包含location条件,因为维度太细,也不做修正
Dimension
选择app维度且media_id=2454
选择pos维度且pos_id=2454105
维度默认是包含day的
维度中如果包含hour,或者location这些更细粒度的维度,则不修正
取数的流程是,后台先根据filter,demension,时间区间,拼凑一个query的json串,然后给druid服务器发送query请求
结果以json格式返回
因为拼凑条件不同,拼成的json串也不同,返回的json串也有所不同
本来我以为问题很简单,但是最后我提交了四版代码,在我们贴代码之前,先整理一下哪些情况下需要修正estimated earnings,
因为不修正的情况太多,所以我们详细讨论下需要修正的情况
1.filter中如果有location条件,一律不作修正
2.filter中如果有app条件,且等于2545,要做修正,这里有个问题我们下面再说
3.filter中如果有pos条件,且等于2454105,要做修正
假设filter中没有选任何条件,下面我们单独考虑dimension
4.dimension中如果有app维度,且等于2454,要做修正
5.dimension中如果有pos维度,且等于2454105,要做修正
6.dimension中如果有hour维度或者location维度,一律不需要修正
乍一看也就六种情况,最后看下我写的代码,代码大概流程如下
for (json数组结果集) {
if (满足条件) {
修正estimated earnings;
}
}
下面说下filter中如果有media_id=2454的情况,此时如果汇总维度是pos维度,一个media下面如果有10个pos,直接修正的化,
会造成2454106那些数据也被修正,所以这个地方要注意,代码中也有体现
下面的代码都是在遍历结果集的循环中,循环中的每一项都是一天的数据,每一项并不是一个javabean,而是一个JSONObject
![](https://i-blog.csdnimg.cn/blog_migrate/064dfe30c6d33aa99f29d38942450e3d.png)
因为分支条件太多,后来我想出来使用标志位,保证每个修正只会被执行一次,这样就不需要大量的else if结构
那些else if的部分其实还可以通过标志位再改造,但是我实在不想看这个代码了
什么条件都不选,dimension不选,filters也不选,是第四版时测试帮我测出来的,开始我一直没考虑这种情况
因为这个代码挺有代表性的,我就把这个Java文件保存下来了
因为我没有粘贴结果集的json结构,所以想直接看懂这个代码还是有难度的
问自己一个问题,如果让自己重新设计这个报表系统,你会怎么做?
你会放弃JSONObject,而使用javabean吗
你会时间条件也归入查询条件吗
你会把数据先读入mysql,然后用查询条件拼凑sql语句,然后把结果集封装成javabean的链表吗
如果用sql语句写查询,应该会容易很多,维度就是group by,filters就是where中的条件,绝对比现在用json条件查询简单多了
复杂的地方就是在于拼凑动态的sql,生成动态的javabean
我想这样实现更简单:
1.如果用sql查询,在service中直接通过字符串拼接的方式,生成select结果字段,where条件和group by条件,传递给mybatis
2.如果用json查询,在service中根据filter和汇总维度生成query用的json串
3.结果集一定是javabean的链表
4.取出多少列是动态指定的,在select后面传动态参数。但是javabean包含最全面的字段,对没有要展现的字段,可以全部赋null,反正前端也不要看
现在项目中的这个结果集合是一个JSONArray,前端让取不同的列,那JSONObject也不相同,导致解析的时候还得先判断哪些列被取到了,真是麻烦
我们继续深入思考,如果结果集是List<bean>,遍历list过程中,只要判断pos_id=2454105或者media_id=2454,就做修正,一行代码就完了啊
为啥这里会这么复杂呢,原因在于只有选了app或者pos维度下,结果集中才有pos_id和media_id的数据,如果只是filter中包含media_id或者pos_id,那结果集中就不包含这两个字段,那就无法在结果集中判断pos_id和media_id,这是修正如此复杂的根本原因。
所以如果重新设计的化,要保证一件事:
查出的javabean是包含所有字段的,对于不能展示的字段(比如分成比例)可以置为null,但是where条件,汇总维度这些字段在每个bean中都要能取到
刚看这个系统的时候,到处都是JSONObject,JSONArray,感觉这个玩意好屌啊
JSONObject完全可用替代javabean啊,确实是这样
JSONArray完全可以取代数组啊,确实是这样,甚至更好,因为JSONArray可以存放不同类型的数据
引申一下
其实用map完全可以构建javabean,
map user = new HashMap();
user.set(name, "luoluo");
user.set(age, 18);
用JSONObject完全可以取代javabean,
JSONObject user = new JSONObject();
user.put(name, "luoluo");
user.put(age, 18);
用JSONObject还可以做容器,不过真要做容器的化,感觉还是map好一点
JSONObject collection = new JSONObject();
collection.put(key1, bean1);
collection.put(key1, bean2)
领导在开会的时候说,做系统最重要的两件事:
1.权限
2.报表
这个系统能实现的功能很简单,但是这帮人硬是把他做成这样复杂
传参全部是JSONObject,有必要吗
构造一个javabean就可以,非要用JSONArray存储一个bean,有必要吗
那么多继承关系有必要吗
那么多format函数有必要吗
那么简单的地方非要用线程池,有必要吗
在看代码过程中,时刻问自己一个问题:
这个东西如果让你设计,你怎么做?