hive编程指南摘抄---待更新
摘抄仅是摘写个人关注的方面,想看全面的请下载附件。
0 前言:
hive不是一个完整的数据库,hdfs设计本身约束和局限性限制了hive不能支持记录级别的更新,插入,删除操作,hive不支持事务。
hive不支持OLTP(联机事务处理)所需要的关键功能,更接近一个OLAP(联机分析技术)工具,
但是hive并没有满足OLAP的联机部分,因为hadoop处理本身的时间开销是很大的,
hive最适合数据仓库应用程序,可以维护海量数据,可以对数据进行挖掘,然后形成意见和报告。
因为对于数据仓库不需要实时响应查询,不需要记录级别的插入,更新,删除。
hql和mysql提供的sql方言最接近。
本书目的:
让开发者深入了解hive技术细节,学习如何优化hive查询性能,通过用户自定义函数和自定义数据格式来个性化使用hive。
wordcount不是一个虚构的例子,这个程序所产生的数据可用于拼写检查程序,计算机语言检测和翻译系统,以及其他应用程序。
hive不仅提供了一个熟悉SQL的用户所能熟悉的编程模型,还消除了大量的通用代码,甚至是那些有时是不得不使用Java编写的令人棘手的代码。
无论是用户,DBA还是Java开发,hive让你花费相当少的精力就可以完成大量工作。
如上图,hive所有命令和查询都会进入到Driver 驱动模块,在该模块中进行解析编译,对需要的计划进行优化,当需要启动mapreduce任务时,hive通过一个表示job执行计划的xml文件驱动执行内置的,原生的mapper, reducer模块,这个通用的模块函数类似于微型语言的语言翻译程序,hive本身不会生成Java的mapreduce算法程序,然后hive通过和jobtracker通信来初始化mapreduce任务(job)。
1.2.2 hbase
hbase填补了hive不支持的功能: 行级别更新, 快速响应查询, 支持事务。
hbase设计灵感来自于google bigtable,但是并没有实现bigtable的所有特性, hbase支持的一个重要特性就是列存储,其中的列可以组织成列族,列族在分布式集群中物理上存储在一起,这样当查询的列是所有列的子集时,读写速度会快得多。
hbase使用键值存储,每一行都使用唯一键来提供非常快的速度读写这一行的列或者列族。
hbase为了可以提供行级别的快速更新和快速查询,hbase也使用了内存缓存技术对数据和本地文件进行追加数据更新操作日志,持久化文件将定期的使用附加日志更新进行更新等操作。
hbase没有提供类sql查询语言,但是hive可以和hbase结合使用。
扩展:
没有使用mapreduce分布式处理的工具有:
spark: 一个基于scala api的分布式数据集的分布式计算框架,其可以使用hdfs,并且对于mapreduce中多种计算可以提供显著性能改善。
shark: 将hive指向spark的项目
storm: 实时事件流处理系统
kafka: 分布式发布-订阅消息传递系统
R: 用于统计分析和数据图形化展示的开源语言,在数据和统计学家,经济学家人群中受欢迎,基于R目前还不是分布式系统,因此处理的数据集有限,社区正努力将R和hadoop结合起来。
1.3 Java和hive:
以单词计数为例, 使用 mapreduce代码用63行, 使用hive为8行,这是表明使用hive能够提高实现速率。
2 基础操作
一个hive二进制包可以在多个版本的hadoop上工作,这样升级hive相对于hadoop相比,会更容易和低风险
hive二进制分支版本核心分为三部分,主要部分是Java代码本身,
比如 hive-exec*.jar, hive-metastore*.jar, 每个jar都实现了hive功能中某个特定部分。
hive的组件 thrift提供了可远程访问其他进程的功能,也提供了使用JDBC和ODBC访问hive的功能,
这些都属于thrift服务实现的。
hive中关键字是大小写无关的,对于本地模式
hive模块对应的东西:
2.7.3 hive中使用注释:
从hive 0.8版本后,hive使用字符串 --来表示注释。
hive变量内部以Java字符串方式存储,用户可以在查询中引用变量,
hive会先替换掉变量引用然后再将查询语句提交给hive查询处理器。
hive引用变量: 如下两个案例都是在oracle迁移到hive时 遇到的工作场景
a) hive cli内部使用变量 方式a今早实验后结果是不可行的
hive> set foo=bar2; 1 实验下是否可行 2 实验下 set foo = select name from stu where id = 2;是否
hive> create table toss1(i int, ${hivevar:foo} string); ----> 报错!!!!!!
hive> describe toss1;
i int
bar2 string
hive> create table toss2(i2 int, ${foo} string);
hive> describe toss2;
i2 int
bar2 string
b) hive使用linux shell变量
$year=2012 hive -e "select * from stu where year = ${env:year}";
尝试下 $name=zhangsan hive -f stu.hql
stu.hql:
select * from stu where name=${env:name}
第三章 数据类型和文件格式
关注
1 hive数据类型是如何在文本文件中进行表示的;
2 文本存储时中为了解决各种性能问题以及其他问题有哪些替代方案
同时你要知道: hive具有一个独特的功能,它对于数据在文件中的编码方式具有非常大的灵活性,
大多数数据库对数据具有完全的控制,控制包括数据存储到磁盘过程的控制 + 数据生命周期的控制。
hive将这些控制交给用户, 以便更容易的使用各种各样的工具管理和处理数据。
关系型数据库会定义字段的长度,提供这个功能是基于性能优化的考虑,
定长的记录会更容易建立索引,数据扫描等,
在hive所在的宽松世界里,hive支持不同存储格式的文件存储数据,在
不同格式文件中,根据字段间隔符实现判断列, 并且关系型数据库限制列长度的方式对于Hadoop这种
强调优化磁盘读写性能而言,并不重要。
如果用户查询中将一个float类型的列和一个double类型的列作对比或者将一个整型的的值和另一个整型的值做对比,那么hive会隐式的将类型转换为类型比较大的那一种,即 float转换为double,
对于hive 字符串希望转换为别的类型: cast (agestr as int) 使用这种方式来执行、
而对于hive中的集合数据类型: struct map array,实际上是调用了内置函数。
大多数关系数据库类型都不支持这些集合数据类型,因为他们趋向于破坏标准格式。
破坏后会增大数据冗余风险,从而消耗不必要的磁盘空间,或者造成数据不一致,或者当数据发生改变时冗余的拷贝数据可能无法进行相应的同步。
但是在hive对应的大数据中,不遵循标准格式的好处是: 提供更高吞吐量的数据。
当处理数据级别在T/P时,以最少的头部寻址从磁盘上扫描数据是非常必要的,而通过hive的集合数据类型对应的数据集进行封装能够减少寻址次数。
3.4 读时模式
当用户向传统数据库写入数据,不论是装载外部数据,还是查询一个结果后将数据写入方式,还是update方式,数据库对于存储都有完全的控制力,数据库就是守门人,传统数据库是写时模式,在数据写入数据库时对模式进行检查。
hive不会不会再数据加载时进行校验,而是在查询时,及读时模式,hive在读取这些数据时,如果数据个数对不上,或者数据类型和模式类型对不上,那么将返回null.
第四章 hiveql: 数据定义
hiveql不完全遵循 ANSI SQL,和MySQL方言最相似,hive增加了在Hadoop背景下可以提供更高性能的扩展,个性化扩展,以及增加一些外部程序。
4.1 hive数据库
数据库本质上是一个目录或者命名空间。
hive数据库创建后,比如 mydb, 那么会在hdfs目录的 /user/hive/warehouse/mydb.db创建这个目录。
即数据库的文件目录名是以 .db结尾的。
默认情况下 hive不允许用户删除已个包含有表的数据库, 要么先删除库里面的表,要么删除库时使用cascade: hive>dorp database if exists mydb cascade;
4.2 hive 表
可以定义表存储位置 存储文件格式
hive默认创建的是管理表,这个表都会在默认 /user/hive/warehouse目录和子目录下。内部表不方便和其他工作共享数据。
hive会对内部表或多或少的控制数据的生命周期
create table stu1 as
select * from stu; 这是创建表和增加数据
create table stu1 like stu; 创建stu1结构和stu结构一样
4.2.1 分区表 管理表
a) 分区表中的严格模式存在意义:
分区能将数据以一定符合逻辑的方式进行组织数据,比如分层存储。
在分区表中如果用户做一个查询,查询对象是所有员工,那么这个操作中hive会不得不扫描所有磁盘的数据,这种查询会触发一个巨大的mapreduce任务,一个高度的安全措施是将hive设置为strice严格模式,
这样如果对分区表进行查询而where没有加分区过滤的话,将会禁止提交这个任务,
hive> set hive.mapred.mode=strict;
hive> select * from employees e limit 10;
Error in semantic analysis: No partition predicate found for ....
b) 分区表使用例子
日志文件分析: 记录有时间戳,严重程度(error warning info).服务器名称, 进程名,期望通过ETL,
将每条日志信息转换为按照制表符分割的记录,将时间戳解析成年,月,日三个字段,剩余时间作为一个字段:
hive记录编码是通过 inputformat对象来控制,比如textfile对应的textinputformat的Java类,
记录的解析是由序列化/反序列化 SerDe控制,
为了保证完整性,hive还使用outputformat对象将数据写出出去。
上面的话总结: hive使用一个inputformat对象将输入流分割成记录,使用outputformat对象将记录格式化成输出流,使用SerDe在读数据时将一行行的记录解析成列,在写数据时将列组织成一行行记录。
下例是hive自定义 serde inputformat outputformat写法:
create mytable
partitioned by (ds string)
row format serde 'com.linkedin.haivvreo.AvroSerDe'
stored as
inputformat 'com.linkedin.haivvreo.AvroContainerInputFormat'
outputformat 'com.linkedin.haivvreo.AvroContainerOutputFormat';
4.6 修改表alter table语句会修改元数据,但不会修改数据本身,这种修改需要用户确认所有的修改都和真实的数据是一致的。
第五章 HiveQL数据操作
5.1 向管理表中装载数据
load data local inpath '....' overwrite into table employee partition(country='us',state='ca');
如果分区目录不存在,此命令会先创建分区目录,然后将数据拷贝到该目录下。
如果目标表是非分区表,那么需要省略掉 partition
如果使用Local, 那么对应路径是本地文件,此文件是拷贝到目标位置。
如果没有lcoal, 那么次文件是分布式文件系统的路径,此时文件会被移动到目标位置。
如果有overwrite,那么目标文件之前存在的数据将会被先删除
如果没有overwrite,仅仅会把新增的文件放在目标文件夹下,不会删除原目标文件夹下的文件,
但是如果目标文件存在和要新加入文件同名的文件,会保留之前的文件并且会重命名新文件为之间文件名_序列号(这种方式从hivev0.9.0开始,之前是会将同名的原文件覆盖掉)
在导入数据中,hive不会验证用户装载数据和表的模式是否匹配,但是hive会验证装载的文件格式和hive表定义的结构格式文件是否一致,比如都应该是 sequencefile。
5.2 通过查询语句向表中插入数据
insert overwrite table employees
partition(country='us', state='or')
select * from employees se where se.cnty='us' and se.st='or';
上述应用场景: 数据存在于一个外部表中,要将其导入到最终分区表中,
或者 将数据导入到一个具有不同记录格式(比如 具有不同字段分隔符)的目标表。
上述语句中,如果对于美国56个州都需要创建分区表,那么上述语句形式需要遍历employees 表56次,
为了优化这种操作,使得既能如期创建56个分区,同时对原表employee也只扫描一次,hive提供如下写法:
from employees se
insert overwrite table employee partition(country='us', state='or') select * where se.cnty='us' and se.st='or'
insert overwrite table employee partition(country='us', state='ca') select * where se.cnty='us' and se.st='ca'
......... ;
动态分区插入:
如果分区很多,用户会写会多sql,为了解决这个问题,hive提供动态分区概念,可以基于查询参数推断出需要创建的分区名称,上述的写法叫静态分区,下面看一个动态分区案例:
insert overwrite table employees
partition(country,state)
select ...., se.cnty, se.st from employeesse;
动态分区中,分区值是根据位置来定义的,是表的最后字段作为分区值。
而静态分区和动态分区是可以混合使用的, 但是静态分区键必须在动态分区键之前。
insert overwrite table employees
partition(country='us',state)
select ...., se.cnty, se.st from employeesse where se.cnty='us';
动态分区默认没有打开, 打开命令为 hive.exec.dynamic.partition=true;
默认以严格strict模式执行,此模式下要求必须要有一列分区字段是静态的,strict模式是为了防止
设计错误导致查询产生大量的分区,比如以时间戳作为分区字段,导致每一秒都对应一个分区。
对于动态分区限制资源利用的参数如下:
打开动态分区参数限制如下:
hive> set hive.exec.dynamic.partition=true;
hive> set hive.exec.dynamic.partition.mode=nonstrict;
5.3 单个查询语句中创建表并加载数据
create table stu1 as select name, age from stu; 用于从大宽表中获取一些字段来构建一个新的内部表!!
5.4 导出数据
a) 如果数据文件是用户需要的格式,直接拷贝即可:
hadoop fs -cp source_path target_path
b) 使用insert directory:
insert overwrite lcoal directory '/tmp/myfold'
select * from stu;
第6章 hiveql查询
注意和mysql语法特性差异 以及hql对性能影响
hive 浮点类型介绍:hive 浮点类型比较(float double)
hive like 就是普通标准的sql操作符份, rlike 是需要和正则搭配使用。
hive group by+having
hive inner join 对应mapredue任务 和执行顺序:
select a.ymd, a.price, b.price from stocks a join stocks b on a.ymd = b.ymd where a.symbol='apple'
and b.symbol='ibm';
在join和where同时出现时, 会先执行join语句的记录, 然后在执行where条件对join后的结果进行筛选操作
select a.ymd, a.price, b.price, c.price from stocks a join stocks b on a.ymd = b.ymd
join stocks c on a.ymd = c.ymd
where a.symbol='apple' and b.symbol='ibm' and c.symbol='ge';
大多数情况下hive会对每对join连接对象启动一个mapreduce任务,并且hive总是会从左向右顺序执行。
上例中,将 a ,b join产生的mapreduce job结果在和 表c进行连接操作,启动一个新的mapreduce job。
hive对于join优化已经做的几点:
a) 当三个或者更多表进行join连接时,如果每个on子句都使用相同连接键的话,那么只会产生一个mapreduce job, 上面的三个表join on例子中只会产生一个mapreduce job
b) hive查询中表的大小从左到右应该依次增加,因为hive会假定最后一个表是最大的表,然后尝试将其余表都缓存起来,
c)
p107
P 317