Hive之——模式设计

转载请注明出处:https://blog.csdn.net/l1028386804/article/details/88430330

按天划分的表
按天划分就是一种模式,通常会在表名中加入时间,例如:supply_2019_03_10、supply_2019_03_11等。

hive> create table supply_2019_03_10 (id int, part string, quantity int);
hive> create table supply_2019_03_11 (id int, part string, quantity int);
hive> create table supply_2019_03_12 (id int, part string, quantity int);
hive> ....load data....
hive> select part, quantity from supply_2019_03_10 
	> union all
	> select part, quantity from supply_2019_03_11 
	> where quantity < 4;

对于Hive,这种情况下,可以使用分区表。Hive通过where子句中的表达式来选择查询所需要的指定的分区。

hive> create table supply(id int, part string, quantity int) partitioned by (day int);
hive> alter table supply add partition (day=20190310);
hive> alter table supply add partition (day=20190311);
hive> alter table supply add partition (day=20190312);
hive> .... load data ....
hive> select part, quantity, from supply where day >= 20190310 and day < 20190311 and quantity < 4;

关于分区
一个理想的分区方案不应该导致差生太多的分区和文件夹目录,并且每个目录下的文件应该足够的大,应该是文件系统中块大小的若干倍。
可以按照时间粒度进行分区:

hive> create table weblogs(url string, time long, state string, city string)
	> partitioned by (day int);
hive> select * from weblogs where day=20190311;

也可以使用两个级别的分区并且使用不用的纬度。比如:第一个分区按照天(day)分区,二级分区以州名(state)进行划分。

hive> create table weblogs(url string, time long, city string)
	> partitioned by (day int, state string);
hive> select * from weblogs where day=20190311;

同一份数据,多种处理
从一个数据源产生多个数据聚合,而无需每次聚合都要重新扫描一次。
比如:下面两个查询都会从源表history表读取数据,然后倒入扫2个不同的表中:

hive> insert overwrite table sales 
	> select * form history where action = 'purchased';
hive> insert overwrite table credits 
	> select * from history where action = 'returned';

上面的查询语法是正确的,就是执行效率低下,下面这个这个查询可以达到同样的目的,只需要扫描history表一次即可:

hive> from history
	> insert overwrite sales select * where action = 'perchased'
	> insert overwrite create select * where action = 'returned';

对于每个表的分区
有时需要对Job的中间结果的临时表进行分区,以避免任务失败,重新从开始执行任务,或者某天、某些数据被覆盖掉。
例如:下面这个例子中涉及了一个名为distinct_ip_in_logs的中间表,其会在后续处理步骤中使用到:

hive --hiveconf dy=20190311
hive> insert overwrite table distinct_ip_in_logs 
	> select distinct(ip) as ip from weblogs 
	> where hit_date = '${hiveconf:dt}';
	
hive> create table state_city_for_day(state string, city string);
hive> insert overwrite state_city_for_day 
	> select distinct(state, city) from distinct_ip_in_logs 
	> join geodata on (distinct_ip_in_logs.ip = geodata.ip);

这种方式有效,不过当计算某一天的数据时会导致前一天的数据被insert overwrite语句覆盖掉。如果同时运行两个这样的示例,用于处理不同日期的数据的话,那么它们就可能会相互影响到对方的结果数据。

一个更具鲁棒性的处理方法是在整个过程中使用分区。这样就不会存在同步问题。还可以对中间数据按日期进行比较

hive --hiveconf dt=2019-03-11
hive> insert overwrite table distinct_ip_in_logs 
	> partition(hit_date=${dt}) 
	> select distinct(ip) as ip from weblogs 
	> where hit_date = '${hiveconf:dt}';

hive> create table state_city_for_day (state string, city string) partitioned by (hit_date string);

hive> insert overwrite table state_city_for_day partition(${hiveconf:dt}) 
	> select distinct(state, city) from distinct_ip_in_logs 
	> join geodata on (distinct_ip_in_logs.ip = geodata.ip) 
	> where (hit_date = '${hiveconf:dt}');

这种方法的缺点是,需要管理中间表并删除旧分区,不过这些任务也很容易实现自动化处理。

分桶表数据存储
分桶是将数据集分解成更容易管理的若干部分的另一个技术。
如果我们对表weblog进行分桶,并使用user_id字段作为分桶字段,则字段值会根据用户指定的值进行哈希分发到桶中。同一个user_id下的记录通常会存储到同一个桶中。假设用户数比桶数多得多,则每个桶内就将会包含多个用户的记录:

hive> create table weblog (user_id int, url string, source_ip string)
	> partitioned by (dt string)
	> clustered by (user_id) into 96 buckets;

不过,将数据正确的插入到表的过程完全取决于用户自己!create table语句中所规定的信息仅仅定义了元数据,而不影响实际填充表的命令。
使用insert ... table语句时,需要正确的填充表,首先,需要设置一个属性来强制Hive为目标表的分桶初始化过程设置一个正确的reducer个数。然后我们再执行一个查询来填充分区。例如:

hive> set hive.enforce.bucketing=true;

如果没有设置hive.enforce.bucketing属性,就需要自己设置和分桶个数相匹配的reducer个数,例如:使用set mapred.reduce.tasks=96,然后在insert语句中,需要在select语句后增加cluster by语句。

为表增加列

hive> create table weblogs(version long, url string)
	> partitioned by (hit_date int) 
	> row format delimited fields terminated by '\t';

hive> load data local inpath 'log1.txt' into table weblogs partition(20190101)
hive> select * from weblogs;

增加一个user_id字段

hive> alter table weblogs add columns(user_id string);
hive> load data local inpath 'log2.txt' into table weblogs partition(20190102);
hive> select * from weblogs;

注意:通过这些方式,无法在已有字段的开始或者中间增加新字段。

使用列存储表
重复数据,像state字段和age字段这样的列将会有很多重复的数据。这种类型的数据如果使用列式存储将会非常好。
多列,表中有很多的列,查询通常只会使用到一个字段或者很少的一组字段,基于列式存储将会使分析表数据执行的更快:

hive> select distinct(state) form weblogs;

 

你可能感兴趣的:(Hadoop,Hive,Hadoop生态)