原创的在后面,前面转载csdn讲解
前言
在大规模数据量的数据分析及建模任务中,往往针对全量数据进行挖掘分析时会十分耗时和占用集群资源,因此一般情况下只需要抽取一小部分数据进行分析及建模操作。Hive提供了数据取样(SAMPLING)的功能,能够根据一定的规则进行数据抽样,目前支持数据块抽样,分桶抽样和随机抽样,具体如下所示:
数据块抽样(tablesample()函数)
1) tablesample(n percent) 根据hive表数据的大小按比例抽取数据,并保存到新的hive表中。如:抽取原hive表中10%的数据
(注意:测试过程中发现,select语句不能带where条件且不支持子查询,可通过新建中间表或使用随机抽样解决)
create table xxx_new as select * from xxx tablesample(10 percent)
2)tablesample(n M) 指定抽样数据的大小,单位为M。
3)tablesample(n rows) 指定抽样数据的行数,其中n代表每个map任务均取n行数据,map数量可通过hive表的简单查询语句确认(关键词:number of mappers: x)
分桶抽样
hive中分桶其实就是根据某一个字段Hash取模,放入指定数据的桶中,比如将表table_1按照ID分成100个桶,其算法是hash(id) % 100,这样,hash(id) % 100 = 0的数据被放到第一个桶中,hash(id) % 100 = 1的记录被放到第二个桶中。创建分桶表的关键语句为:CLUSTER BY语句。
分桶抽样语法:
TABLESAMPLE (BUCKET x OUT OF y [ON colname])
其中x是要抽样的桶编号,桶编号从1开始,colname表示抽样的列,y表示桶的数量。
例如:将表随机分成10组,抽取其中的第一个桶的数据
select * from table_01 tablesample(bucket 1 out of 10 on rand())
随机抽样(rand()函数)
1)使用rand()函数进行随机抽样,limit关键字限制抽样返回的数据,其中rand函数前的distribute和sort关键字可以保证数据在mapper和reducer阶段是随机分布的,案例如下:
select * from table_name where col=xxx distribute by rand() sort by rand() limit num;
2)使用order 关键词
案例如下:
select * from table_name where col=xxx order by rand() limit num;
经测试对比,千万级数据中进行随机抽样 order by方式耗时更长,大约多30秒左右。
————————————————
版权声明:本文为CSDN博主「raxanne」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zylove2010/article/details/78290319
以上是转载CSDN,本文原创是对第二中分桶抽样的补充。
正文
分桶抽样场景(仅代表我自己)
本人使用抽样场景是:使用java-Api在hive中查找大数据,担心查询数据量过大,导致java程序崩溃,所以采用分批查询。而前文引用的 CSDN 的第一和第三种方法则不再适用。
分桶抽样的局限
当总样本为1w,当抽样数量大于5k为Nk时;
每次抽样总是最前面Nk条
解决方法
我本身需要分批 所以已经有有了固定顺序和标号,分页语法如下
select * from (select row_number() over (order by xx) as rnum ,table.* from table)t where rnum betwneen 1 to 10;
即 我的等化抽样sql为
sql主体 + where rnum > {1} and rnum <= {2} and rnum % {3} = 0
其中{1}、{2}为分页参数,{3}为抽样因子。抽样因子=原样本总量/需抽样数量。
以上抽样sql的抽样因子不能小于2且为自然数。
改良思想:
当抽样数量大于样本数量一半时,就先取样本得偶数得一半,再将奇数按需(数量)索取
则改良后sql(仅当抽样因子小于2时):
sql主体 + where rnum > {1} and rnum <= {2} and ((rnum %2 = 0) or (rnum % 2 = 1 and rnum < {4}))
{4}=(需抽样数量-原样本总量/2)*2
原样本总量/2是向下取整
简化后sql为
sql主体 + where rnum > {1} and rnum <= {2} and (rnum < {0} or rnum % 2=0)
简化后sql得思想也可以理解为:既然当前得抽样数量大于样本总数的一半,则前面数据(无论奇偶)全部拿走,剩下抽样数量为样本总量一半,再按一半抽样。
即设定抽样数量为m,样本数量为n,"前面数据" 为x,用方程式表达上述意思:m-x<=(n-x)/2,解完方程式为x>=2m-n.