改了一万个BUG,才开始HIVE之旅。且行且珍惜。
HIVE是Facebook开发贡献给Hadoop开源社区的。
他可以无基础帮助OLAP分析人员使用简单的sql语句进行数据分析。它的原理也很简单,hivesql先被sql解析其解析,生产个一个可执行的mr计划,最后交给hadoop处理。
hadoop是批量处理,所以hive也是高延迟的。它不提供数据的排序和查询缓冲,以及在线事务和记录级跟新。
hive主要构架:
Driver组建:核心组件,有编译器 优化器 执行器,能将sql变为rm任务。
MetaStore:元数据。hive的元数据都存储在这里面。一般元数据都存储在关系数据库中,最常用的是msql,还有Derby。但后者只适合简单的测试
CLI:命令行接口,其负责类是hive-cli中的CliDriver
Thrift Server:提供JDBC接口,可以进行可扩展且跨语言的服务
HIVE WEB INTERFACE(HWI):简单说就是可操作的ui界面
我觉得hwi是最方便好用的。
配置hwi也简单介绍一下:
1.下载src包,我们下载的hive都是bin包。最好下载对应版本的src包,还有一个需要注意的是,最好用1..版本的。2以上版本的的hive/lib里没有hwi.jar(个人测试结果)。
将src中的web文件里所有文件打包为一个war包,并对hive-site.xml进行hwi配置。
2.下载ant,并进行配置
3.依赖包,依赖包有来自ant的,有来自tomacat的,有来自java的tools.
DDL操作
表的创建主要分为了内部表创建和外部表创建
内部表是存储的具体数据,每次加载数据时,是将整个文件拉取,删除该表数据也会被删除。
外部表存储的是一个外部引用,所以也就不存在删除源文件。
创建表的注意点:
1.参数的先后,比如创建外部表是,LOCATION是最后的参数,如果你放在中间肯定会报EOF miss的错误。顺序为,表(字段) 分区 分桶(排序) 规则 类型 Location
2.path的范围,一般导入的文件path=hdfs:///localhost:9000/user/root+'path',就是说它的前缀是已经指定好的。这个参数也可以配置。而LOCATION的path则没有前缀的。如目录在hdfs:///localhost:9000/user/external需要写/user/external.
3.文件格式和数据规则必写。因为你load进入的数据的格式如果不被识别,那么就将全部是null。FIELDS TERMINATED BY ' ' LINES TERMINATED BY '\n' 。意思是列与列的数据用' '隔开,每行数据用/n隔开。
修改表
改名
ALTER TABLE old_name RENAME TO new_name
增加列
ALTER TABLE table_name ADD COLUMNS (new_col INT COMMENT '注意有引号')
改变表属性
ALTER TABLE table_name SET FILEFORMAT TEXTFILE(改变存储方式)
ALTER TABLE table_name SET serdeproperties('field.delim'='\t')(改变了分割方式)
alter table table_name set tblproperties('EXTERNAL'='TRUE')(内部表转外部表)
分区操作
增加分区
ALTER TABLE table_name ADD PARTITION (name=value)
如果这个表本来没有这个name字段的分区:会报错ValidationFailureSemanticException table is not partitioned but partition spec exists: {id=1}
大意是这不是一个分区表,所以说在建表的时候就要确认这个分区表,才可以在后续进行增加分区的操作
ALTER TABLE table_name DROP PARTITION (name=value)(删除一个分区)
删除表
DROP TABLE table_name
TRUNCATE TABLE my_table(只删除表中数据,不改变表结构)
truncate不能删除外部表,因为外部表的数据不是存放在Meta Store中
DML操作
想数据表导入数据
LOAD DATA [LOCAL] INPATH ' ' [OVERWRITE] INTO table_name
如果是在hdfs里的文件,则不需要local。 overwrite into是覆盖表分区,仅仅是这个分区的数据内容,如果是追加,则不需要overwrite。
hive 会把该目录下的该文件移动到表中,如果文件名产生冲突会用新的文件代替久的文件。
将查询结果插入
INSERT OVERWRITE TABLE table_name [partition] SELECT ....
可以将后续的查询结果插入表或者是表的分区里。overwrite会强制写入,其中的输出格式和序列化方式由表的元数据决定。同时我们也可以使用多表插入,可以减少扫描的次数。
将查询结果写入文件系统
INSERT OVERWRITE [LOCAL] DIRECTORY dir SELECT...
dir可以是全路径,如果没有定义scheme或者authority那么hive会使用hadoop配置的fs.default.name来定义。比如我的默认dir前缀就是hdfs://localhost:9000/user/root
sql操作
SELECT WHERE 和sql语句没有大区别
如select * from user where id=1
重复项处理
在默认的select name from user中,返回的name是all也就是包括所有(包含了重复的项)
如果想过滤掉这些项,用select distinct name from user
使用正则
https://www.cnblogs.com/Allen-rg/p/9323506.html
使用正则可以过滤数据。
基于分区查询
select * from table_name where table_name.partition<100
这里的table_name表加入是按partition分区的,那么这里就不会进行全局扫描,而是找出满足条件的分区,再进行查询
聚合
Group by 该函数可以产生聚合操作,
如select name from user group by name.
这个操作会按name进行分组,但这个过程中,可能其他列的值会变为多值,如name=张三的有两个,那么name这一行对应的id列就有两个值了,对于关系数据库这是不可以的。这是必须对id进行操作,使之变为一个值才行。如max,count等操作。
join操作
一图以蔽之
1367194228.jpg
分区,分桶
将表划分为分区,partition会根据分区字段进行分区。分区可以让数据的部分查询更快。表或者分区可以进一个进行分桶,捅通常在原始数据中加入额外的数据结构,使得高效查询。例如用户可以增加ID桶。
分区可以是时间或者时间戳,在查询时带上这个时间查询,当然就不会全局扫描(是不是和mysql的索引很像呢)。分区也可以进行多维度分区,这样就可以建立一个目录级关系。如天时间和时刻进行分区。总目录下是天,天下面是时刻.
动态分区开启:
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
默认值:strict
描述:strict是避免全分区字段是动态的,必须有至少一个分区字段是指定有值的避免产生大量分区
使用分桶的原因是为了高效查询和高效抽样。指定字段会根据hash后取余数,来决定进入哪个桶。在map-side关联中,两边桶不必相同,成倍数即可。系统也给了一个hive.enforce.bucketing=true的方式,将分桶交给hive.set hive.enforce.sorting=true;开启强制排序,插数据到表中会进行强制排序,默认false;
我们发现其实桶的概念就是MapReduce的分区的概念,两者完全相同。物理上每个桶就是目录里的一个文件,一个作业产生的桶(输出文件)数量和reduce任务个数相同。
而分区表的概念,则是新的概念。分区代表了数据的仓库,也就是文件夹目录。每个文件夹下面可以放不同的数据文件。通过文件夹可以查询里面存放的文件。但文件夹本身和数据的内容毫无关系。
桶则是按照数据内容的某个值进行分桶,把一个大文件散列称为一个个小文件。
这些小文件可以单独排序。如果另外一个表也按照同样的规则分成了一个个小文件。两个表join的时候,就不必要扫描整个表,只需要匹配相同分桶的数据即可。效率当然大大提升。
同样,对数据抽样的时候,也不需要扫描整个文件。只需要对每个分区按照相同规则抽取一部分数据即可。
网友评论