总结:满分10分的话,这本书可以打7分(豆瓣评分点这儿),我认为它的定位是Hive入门,前6章作为入门讲解是良好的,但是后面章节特别到了第11章之后,作者开始东一榔头西一棒槌,让人摸不着头脑。这本书的优点就是基本讲解了常用的Hive语法并举了一些示例,对细节处作了点到为止的提示(很不够深入),偶尔几句富含思想性的话语给了一些启示,但总的来说,仅此而已。翻译水平还能接受,但越到后面能感觉到翻译得越不认真,整本书发现的印刷错误约10处左右,无伤大雅。选来做Hive入门书的话,细读前10章就可以了,后面的可以不看。我认为Hive入门还是比较简单的,应用关键在于如何优化,还是挺期待Hive性能调优实战这本书的,下一本就读它啦!以下是我在阅读过程中记下的笔记,供参考。
目录
第16章 Hive的Thrift服务(通过指定端口访问Hive)
第1章 基础知识(略)
Hadoop和MapReduce的综述;Hive由来;用Java写了一个词频统计MR算法
第2章 基础操作(略)
安装虚拟机、Hadoop、Hive;配置Hadoop;熟悉HIve CLI命令行界面等等
第3章 数据类型和文件格式
- “Hive具有一个独特的功能,那就是其对于数据在文件中的编码方式具有非常大的灵活性。大多数的数据库对数据具有完全的控制,这种控制既包括对数存储到磁盘的过程的控制,也包括对数据生命周期的控制。Hive将这些方面的控制权转交给用户,以便更加容易地使用各种各样的工具来管理和处理数据。”
- 基本数据类型:TINYINT、SMALINT、INT、BIGINT、BOOLEAN、FLOAT、DOUBLE、STRING、TIMESTAMP、BINARY
- 这些数据类型都是对Java中的接口的实现。
- Hive根据不同字段间的分隔符来区分字段,不限制字段值的长度;Hadoop和Hive强调优化磁盘读和写的性能。
- TIMESTAMP的值(UTC时间):1)整数——距离Unix新纪元时间1970年1月1日晚上12点的秒数;2)浮点数——距离Unix新纪元时间的秒数,精确到纳秒,小数点后保留9位数;3)字符串——YYYY-MM-DD hh:mm:ss:fffffffff。
- 如果一个表的表结构指定3列,实际数据文件每行有5个字段,那么最后2列数据会被省略。
- float类型或int类型和double类型进行比较,会隐式地将float或int转换成double。
- 集合数据类型
- “大多数的关系型数据库并不支持这些集合数据类型,因为使用它们会趋向于破坏标准格式。传统数据模型中,structs可能需要由多个不同的表拼装而成,表间需要外键连接。破坏标准格式带来的问题:增大数据冗余的风险、消耗不必要的磁盘空间、可能造成数据不一致。好处:提供更高吞吐量的数据。”
- 按数据集进行封装可以减少寻址次数从而提高查询的速度;外键关系关联需要进行磁盘间的寻址操作,带来非常高的性能消耗。
- 一个例子,注意STRUCT一旦声明好结构,那么其位置就不可以再改变。
- Hive中默认的记录和字段分隔符
- TIPS:JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。
- 指定分隔符,例子:
,ROW FORMAT DELIMITED必须写在其他子句之前(除STORED as外);\001是^A的八进制数;LINES TERMINATED BY和STORED AS不需要ROW FORMAT DELIMITED关键字。意义:强大的可定制功能,使Hive可以容易地处理其他工具产生的文件。
- 传统数据库是写时模式(schema on write),即数据在写入数据库时对模式进行检查;Hive是读时模式,在查询时进行模式检查,不在数据加载时验证;Hive中查询的时候模式和文件内容不匹配:如1)实际字段少于模式定义的字段,则没有的字段返回null 2)实际字段与定义字段类不一致,返回null
第4章 HiveQL:数据定义
- Hive不支持行级插入、更新、删除操作;不支持事务
- 创建数据库:CREATE DATABASE [IF NOT EXISTS] financials COMMENT ‘Holds all financial tables’ LOCATION ‘.......’;
- 数据库相关命令,都可以用SCHEMA替代TABLE。
- 增加K-V属性信息:
- Hive默认是不允许用户删除一个包含有表的数据库的,要么先把表删了再删库,要么在删库命令后面加上CASCADE,这样Hive会自动先把库里的表删了。
- 建表语句,注意:如果表名相同而字段定义不同,Hive是不知道的,不会给你重新创建一个新表,需要删除旧表之后重建表
- TBLPROPERTIES还可用作表示关于数据库连接的必要的元数据信息;Hive会自动增加两个表属性:last_modified_by和last_modified_time,分别保存最后修改表的用户名和新纪元时间秒。
- 查看表的详细结构信息 DESCRIBE EXTENDED mydb.employees; 或 DESCRIBE FORMATTEDmydb.employees; 后者输出信息可读性好;只查看某个字段信息 DESCRIBE mydb.employees.salary; 。
- 内部表(又叫管理表),默认情况下这些表的数据存储在由配置项hive.metastore.warehouse.dir所定义的目录的子目录下;删除内部表时表中数据也会被删掉;内部表不方便共享数据。
- 外部表,删除表只会删除描述表的元数据信息,不会删除数据;注意有些HiveQL语法不适用于外部表;建表语句:
- 如何查看一个表是管理表还是外部表?
- 分区表,把数据按分区存在很多目录下,形成很多较小的文件;SHOW PARTITIONS tbl_name; 查看分区;
- 管理表中用户可以载入数据时创建分区,需要为每个分区字段指定一个值。
- 外部分区表,建表语句示例:
- 表的存储格式,Hive默认是TEXTFILE,即所有字段都使用字母、数字、字符编码,包括国际字符集,每一行被认为是一个单独的记录;SEQUENCEFILE和RCFILE使用二进制编码和压缩(可选),优化磁盘空间和IO带宽性能。
SerDe即序列化器/反序列化器;编码、解析、输出使用的Java类名分别为org.apache.hadoop.mapred.TextInputFormat、org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe、org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat;还可以指定第三方的输入、SerDe、输出格式,就能够自定义Hive本身不支持的其他文件格式,示例:
- 注意:ALTER TABLE仅仅修改表的元数据,表里的数据不会有任何修改,需要自己确认修改是否和真实数据一致。
- 表重命名 ALTER TABLE log_messages RENAME TO logmsgs;
- 增加、修改、删除分区,示例:
- 修改字段,即使字段名或字段类型没有变,也需要完全指定旧的字段名并给出新的字段名及新的字段类型,示例:
- 增加字段,示例:
- 移除字段并重新指定,示例:
- 修改存储格式,示例:
- 修改SerDe属性,示例:
- 向SerDe增加新的属性,示例:
- ALTER TABLE ... ARCHIVE PARTITION将分区内的文件打成一个Hadoop压缩包文件(HAR),注意这样仅仅可以降低文件系统中的文件数以及减轻NameNode的压力,并不会减少任何的存储空间,示例:
;UNARCHIVE是ARCHIVE的逆操作;注意这个功能只能用于分区表中独立的分区。
- 防止分区被删除或被查询,示例:
;使用DISABLE即逆操作;这些操作仅可用于分区表。
第5章 HiveQL:数据操作
- 装载数据到内部表,注意路径是一个目录而不是单个文件,示例:
使用LOCAL则路径为本地文件路径,数据会被拷贝到目标目录;不使用LOCAL则路径为分布式文件系统路径,数据会被转移到目标路径;注意:源文件和目标文件以及目录应该在同一个文件系统中(无法跨集群转移)。
- 扫描一次,按多种方式划分,示例:
注意:这不是if...else...结构,每条记录都会经过所有selectt...where...语句的判断,因此某些数据会被写入多个分区而某些数据会被删掉。
- 静态分区 vs 动态分区,动态分区插入示例:
- 静态、动态分区可以混用,示例:
,注意:静态分区键必须出现在动态分区键之前。
- 动态分区的一些属性:
,注意:需要先设置这些属性,才能按期望使用动态分区,示例:
- 查询并创建表,示例:
- 如何从表中导出数据?如果格式没问题了,直接用hdfs命令拷贝文件夹或文件;使用
,其中文件个数取决于reducer个数;Hive会将所有字段序列化为字符串写入文件;可指定多个输出目录,示例:
- 和很多关系型数据库不同,Hive没有临时表的概念,创建了的表不想用了得手动删掉。
第6章 HiveQL:查询
- 数组索引从0开始,和Java中一样。
- 引用数组元素
;引用MAP元素
;引用STRUCT元素
;以上WHERE子句同样适用。
- Hive支持所有典型的算数运算符;注意:数据溢出的问题,Hive遵循的是Java中数据类型的规则。
- Hive内置一系列数学函数(略);数据转换时首选内置函数进行转换,而不是CAST。
- 聚合函数,注意:
- 表生成函数——聚合函数的反向操作,单列扩多列或者多行;
;使用表生成函数的时候生成的列要指定别名。
- 其他内置函数(很多,在原书p88~92,略)
- CASE...WHEN...THEN,示例:
- 无需触发MapReduce任务:1)WHERE子句中过滤条件只是分区字段;2)hive.exec.mode.local.auto = true。
- 注意:不能在WHERE子句中使用列别名。
- FLOAT与DOUBLE进行比较会出问题,例子:
,因为0.2被存成DOUBLE,但是计算机无法准确表示浮点数,0.2最近似的精确值略大于0.2,对于FLOAT类型,0.2是0.2000001,对于DOUBLE类型,0.2是0.200000000001,当FLOAT转换成DOUBLE时,0.2就变成了0.200000100000,就大于0.200000000001。
规避的方法:1)CAST (0.2 as FLOAT);2)定义的时候就把类型规定好,比如用DOUBLE,虽然会浪费内存。。 - RLIKE用正则表达式。
- HAVING子句可以在group的时候过滤结果。
- JOIN语句,SQL支持不等值连接,但Hive只支持等值连接;
,这个语句在SQL中是合法的,在Hive中是非法的,因为MapReduce很难实现这种类型的连接(为什么?)。
- Hive不支持在JOIN操作的ON连接条件中使用OR。
- 可以对多张表进行连接,每对JOIN启动一个MapReduce任务,比如a、b、c三个表join,首先启动一个MR任务对a和b进行join,然后再启动一个MR对a join b的输出和c进行join;注意Hive总是按照从左到右的顺序执行的。
- 当对3个或者更多个表进行JOIN时,如果每个ON子句都使用相同的连接键的话,只会产生一个MR任务。
- Hive假定查询中的最后一个表是最大的那个表,在对每行记录进行JOIN时,它会尝试将其他表缓存起来,然后扫描最后的表做计算,所以最好保证连续查询中的表大小从左到右递增;Hive还提供标记机制来显式地告诉查询优化器哪张表是最大的,使用示例:
- WHERE语句在JOIN操作执行后才会执行;ON语句中的过滤条件在OUTER JOIN中是无效的,在INNER JOIN中是有效的(这一点和Hive文档相反)。
- FULL OUTER JOIN:返回所有表中符合WHERE语句条件的所有记录,任一表的指定字段没有符合条件的值的话,用NULL替代。
- LEFT SEMI JOIN:返回左边表的记录,前提是其记录对于右边表满足ON语句的判定条件;
,注意:右边表的字段只能出现在ON子句中;SEMI JOIN比INNER JOIN要更高效,因为一旦找到匹配的记录,HIve立即停止扫描;详细讲解见:https://blog.youkuaiyun.com/HappyRocking/article/details/79885071。
- 笛卡尔积,即JOIN的时候不指定ON子句;Hive没法优化;hive.mapred.mode设为strict的话,会阻止笛卡尔积。
- map-side JOIN:如果所有表中只有一张表是个小表,那么可以在最大的表通过mapper的时候将小表完全放到内存中,这样Hive在map端执行连接过程,从而省略了常规join需要的reduce过程;
还可以配置可优化的表的大小:;RIGHT OUTER JOIN和FULL OUTER JOIN不支持这个优化。
- ORDER BY会对查询结果执行一个全局排序,都通过一个reducer处理,很慢;hive.mapred.mode的值为strict的话,会强制要求加一个LIMIT限制。
- SORT BY可以对每个reducer中的数据排序,可以提高后面进行全局排序的效率;注意:SORT BY后每个reducer输出的数据范围可能重叠,意思是,假如全部数据范围是1~10,sort by有两个reducer,它们排完序后各自的数据范围可能是1~7和5~10,而不是1~5和6~10,就是说会存在重叠;更深入的原理:MR计算框架会根据map输入的键计算相应的哈希值,然后按照哈希值将键-值对均匀分发到多个reducer中去,这也就意味着不同reducer的数据范围会有重叠。
- DISTRIBUTE BY可以按照指定字段将数据分发到reducer中去,保证了每个reducer处理的数据范围不重叠,结合SORT BY使用就可以得到局部字段值有序的结果,示例:
注意:DISTRIBUTR BY语句必须在SORT BY语句前面。 - CLUSTER BY等价于DISTRIBUTE BY + SORT BY(使用同样字段,且用默认的升序排列)。
- 类型转换函数CAST如果原始值不合法,会返回NULL;浮点数转整数推荐用round()或floor()。
- 分桶抽样:
,分母表示数据分到多少个桶,分子表示将会选择的桶的个数。
- 数据块百分比抽样:
,注意抽样的最小单元是一个HDFS数据块(128MB),若小于这个,则返回所有行;hive.sample.seednumber设置种子。
- UNION ALL要求每一个子查询列相同且每个字段的类型相同。
第7章 HiveQL:视图
- 啥叫视图:保存一个查询并像表一样使用,是一个逻辑结构,但不会存储数据;当一个查询引用一个视图时,视图定义的查询语句和用户自己的查询语句组合在一起,然后查询,相当于先执行视图,在利用结果执行后续查询;和软件里面定义函数避免重复、控制代码长度的思想一样的;示例:
- 视图还可以限制数据访问以保护信息不被随意查询,示例:
- 视图的其他操作类似表,比如删除:
;SHOW TABLES可以查看视图。
第8章 HiveQL:索引
- 补:索引是对数据库表中一列或多列的值进行排序的一种结构。
- Hive中没有普通关系型数据库中键的概念,但是可以对一些字段建立索引来加速,一张表的索引数据存在另一张表中。
- 对分区字段country建立索引,示例:
- 重建索引,示例:
- 显示索引:
- 删除索引:
- 索引处理器可以自己用Java开发。
第9章 模式设计
- 问:什么叫关系型数据库的模式?
- HDFS被设计用来存储数百万的大文件,而非数十亿的小文件。
- 从一个数据源产生多个数据聚合,只用扫描一次,示例:
,这个要扫描2次
,这个扫描1次就行。
- Hive通常使用行式存储,但对于某些字段的列存在大量重复数据的情况下,列式存储要好一些,Hive提供了一个列式SerDre。
- 压缩可以是磁盘存储的数据量变少,可降低I/O,对于I/O密集型任务是个好事,但是压缩和解压都会消耗CPU资源,对于CPU密集型任务,压缩就可能会降低性能了。
第10章 调优
- 使用EXPLAIN查看查询计划,示例:
;
打印出抽象语法树:;
Hive实际上会先将输出写到一个临时文件里,再写到控制台;
STAGE PLAN部分: - EXPLAIN EXTENDED展示更多信息。
- 开启LIMIT采样功能:
缺点:有可能有用的数据永远不会被处理到。 - 临时启用本地模式处理很小的数据集,示例:
- 开启并发执行:hive.exec.parallel设为true;注意:在共享集群中,job中并行执行的阶段增多,集群利用率增大。
- 调整mapper和reducer个数:
- JVM重用,参数:
缺点:会一直占用使用到的task插槽 - 索引可以加快含有GROUP BY语句的查询的运行速度。
第11章 其他文件格式和压缩方法(这章书上写得很烂。。)
- sequence file存储格式可以将一个文件划分成多个块,然后采用以各种可分割的方式对块进行压缩;它是二进制格式的。
第12章 开发(啥玩意儿。。略)
第13章 函数
- SHOW FUNCTIONS可以列举出当前HIve会话所加载的所有函数名称;DESCRIBE EXTENDED FUNCTION展示函数详细描述。
- UDAF——用户自定义聚合函数;UDTF——用户自定义表生成函数。
- 从表中产生其他的列,使用LATERAL VIEW,示例:
注意:需要指定视图别名和生成的新列的别名。 - UDF:继承UDF类,实现evaluate()函数,写注解,对Java代码编译,将编译后的UDF二进制文件打包成JAR,用ADD JAR将JAR加入Hive路径,用CREATE FUNCTION定义使用。
- GenericUDF,更复杂。
- 将函数永久加入Hive的话需要重新编译Hive。
以下略
第14章 Streaming(略)
第15章 自定义Hive文件和记录格式
-
RCFile - 列式存储
第16章 Hive的Thrift服务(通过指定端口访问Hive)
第17章 存储处理程序和NoSQL
第18章 安全
第19章 锁
第20章 Hive和Oozie整合
第21章 Hive和亚马逊网络服务系统
第22章 HCatalog
第23章 案例研究