两种方式查询数据的数据量不一样:
select * from ods_log;
select count(*) from ods_log;
原因是select * from ods_log
不执行MR操作,默认采用的是ods_log建表语句中指定的DeprecatedLzoTextInputFormat
,能够识别lzo.index为索引文件。
select count(*) from ods_log
执行MR操作,默认采用的是CombineHiveInputFormat
,不能识别lzo.index
为索引文件,将索引文件当做普通文件处理。更严重的是,这会导致LZO文件无法切片。
set hive.input.format;
hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
解决办法
解决办法:修改CombineHiveInputFormat为HiveInputFormat
在ads层需要考虑的一个很重要的问题是重聚重复和小文件问题:
对于小文件问题,首先将原始表中的数据查询出来,然后在和今天计算的数据union操作,union操作本来就有去重的效果。
对于数据重复问题:使用union操作有去重的效果,然后使用overwrite操作,覆盖原来表中的数据,保证数据没有重复项。
日活:末次登录时间等于统计当天时间。
周活:末次登录时间在一周时间范围内
月活:末次登录时间在一个月范围内即可。
首先是数据的重复问题:如果使用into进行追加,如果任务失败的话,重新跑任务会导致数据的重复。 其次是小文件问题:追加操作是针对hive表来说的,但是对于hdfs来说,就是创建一个文件,所以对于ads层会产生很多的小文件。
在插入数据之前,先将表中的数据查询出来,然后将今天的一条数据和查询出来的历史数据做一个union操作,然后将今天的一条数据和查询出来的历史数据做一个union操作,然后整体重新写入文件中,这样就避免了小文件的产生。因为始终写入的是一个文件
对于数据重复问题,这里使用的是overwrite+union操作,每一次都把前面的数据进行覆盖,然后union在合并数据的时候,也具有去重功能,所以不会产生数据的重复问题。
首次登录时间等于统计当天时间就是新增用户。
在计算新增设备数指标时候,可以使用sum(if)进行计算,但是在数据量很大的情况下,这种方式效率很低,因为需要一行一行的判断数据。
在这里使用where过滤操作,首先对数据按照时间进行过滤,这样就可以过滤掉很大一部分的数据,然后再去累加计算,计算量会小很多。
核心是计算某个时间前,在某日的新增用户还剩下多少。
根据首次登录时间和末次登录时间,末次登录时间-首次登录时间=留存的天数
在计算留存用户数的时候,因为需要从同一张表中读取不同时间留存的用户,读取数据的逻辑是不同的,只是日期不同,所以每次读取数据都需要从表中读取数据,读取次数越多,性能月不好。
使用in子句判断日期,然后按照首次登录日期进行分组操作,这样从表中读取数据一次,就可以计算多个日期的留存用户。
首次登录时间==末次登录时间即可。
本周活跃的-本周新增用户-上周新增用户
减法操作可以使用left join实现,也可以使用not in实现。
末次登录时间在7天前。
分别求出三周的活跃用户数,然后找出公共部分。
使用内连接,内连接的结果会返回共有的部分。
使用union all将数据拼接在一起,然后分组统计每组的个数。
从dwt_user_topic主题宽表中计算字段。
使用distinct去重一般会进行全局去重,侠侣很低,所以使用group by分组去重。
join两个子查询效率很低,所以使用多重子查询代替join操作。
本质上是top k问题。按照指标字段进行倒序排序,取前十即可。
top k问题。
top k问题。
top k问题。
top k问题。
求top k问题: