Hive 使用简介

阅读更多
1.示例

CREATE TABLE records(year STRING temperature INT, quality INT)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t';
第一行声明了一个records表,包含三列及列类型。
ROW FORMAT子句是HiveQL所特有,声明数据文件中字段间以制表符分隔,每行以换行符分隔。

LOAD DATA LOCAL INPATH 'input/ncdc/micro-tab/sample.txt'
OVERWRITE INTO TABLE records;
这一命令告诉Hive把指定的本地文件放入其仓库目录中。此操作不解析文件或把它存储为
内部数据格式,文件以原样存储在/usr/hive/warehouse/records目录(hive.metastore.warehouse.dir控制)。
OVERWRITE关键字告诉Hive删除对应目录中已有的所有文件,若省略,则Hive就简单将文件加入目录。

Hive优势在于把这个查询转化为一个MapReduce作业并执行,然后将结果打印到控制台。

2. Hive与传统数据库相比
   2.1 读时模式 vs 写时模式
   传统数据库,表模式是在数据加载时强制确定的,加载时发现数据不符合模式,则拒绝加载数据。这一设计被成为"写时模式"
   Hive 对数据的验证并不在加载数据时进行,而在查询时进行,这称为"读时模式"。
   读时模式是数据加载非常迅速,因为它不用读取数据进行解析,再进行序列化并以数据库内部格式存入磁盘。
   数据加载仅仅是文件复制或移动。
   写时模式有利于提升查询性能,因为可以对列进行索引,并对数据进行压缩,但作为权衡,加载数据会花更多时间。
   2.2 更新 事务和索引
   更新:HDFS不提供文件更新,插入、更新和删除操作引起的一切变化都被保存在一个较小的增量文件中,由metastore在
   后台运行的MapReduce作业会定期将这些增量文件合并到基表文件中。此功能只有在启动了事务的背景环境下才能发挥作用。
   锁: hive 0.7.0引入了表级和分区级的锁,可以防止一个进程删除正在被另外一个进程读取的表,锁由zooKeeper透明管理,
   用户不必执行获得和释放锁的操作。
   索引:Hive索引分为两类,紧凑(compact)索引和位图(bitmap)索引。
   紧凑索引存储每个值的HDFS块号,而不是存储文件内偏移量,存储不占用过多的磁盘空间。
   位图索引使用压缩的位集合来高效存储具有某个特殊值的行,这种索引一般适合与具有较少值可能的列。

3.Hive 数据类型
  原子类型:
  Boolean存储真值和假值
  四种有符号整数类型:TINYINT、SMALLINT、INT以及BIGINT,等价于Java的byte、short、int和long
  浮点数据类型: FLOAT和DOUBLE对应Java的float和double类型,分别为32位和64浮点数。
  DECIMAL类型表示任意精度的小数,类似于Java的BigDecimal类型,常常被用来表示货币值。
  存储文本类型:STRING 一个无最大长度声明的变长字符串。
  VARCHAR与STRING相似,不过它需要声明最大长度(允许长度范围1到65355之间,例如VARCHAR(100))
  CHAR是固定长度的字符串,必要则以空格填充尾部。
  BINARY数据类型,用于存储变长的二进制数据。
  TIMESTAMP数据类型存储精度为纳秒的时间戳。
  DATE类型保存日期

  复杂类型:运行任意层次的嵌套,复杂数据类型声明必须用尖括号符号指明其中数据字段类型。
  ARRAY:一组有序字段,字段类型必须相同。定义:ARRAY,文字示例array(1,2),array字段[0]取值为1。
  MAP: 一组无序的键-值对,键的类型必须是原子的,值可以是任何类型。同一映射的键类型、值类型必须相同。
  定义: MAP,文字示例map('a',1,'b',2),map字段['b']取值为2。
  STRUCT:一种记录类型,封装了一个命名的字段集合。
  定义:STRUCT,文字示例struct('a',1,1.0),STRUCT字段名.c 取值为1
  UNION: 是从几种数据类型中指明选择一种,UNION的值必须与这些数据类型匹配。
  定义:UNION
  
4.操作与函数
  关系操作符: 例如等值判断,X is null,模式匹配:x like 'a%',以及逻辑操作符(x or y)
  与SQL-92不同,||是逻辑或操作符,而不是字符串连接符,在Hive中字符串应该用concat函数。
  可在Hive shell环境中输入show FUNCTIONS以获取函数列表。

5.类型转换
  隐式类型转换规则,任何数值类型都可以隐式转换为一个范围更广的类型或者文本类型等等。

6.Hive表
  Hive提供了多数据库/模式支持,通过create database dbname\use dbname\drop database dbname语句来创建删除,
  可以通过dbname.tablename来限定某一张表
  
  6.1 分区
  按照分区字段将数据文件存放在不同的目录中,加快数据分片的查询速度。
  例如日志表,按照日期分区,按照国家对每个分区进行子分区。
  CREATE TABLE logs(ts BIGINT, line STRING)
  PARTITIONED BY(dt STRING, country STRING);
  把数据加载到分区表中时,需要显示指定分区值:
  LOAD DATA LOCAL INPATH 'input/hive/partitions/file1'
  INTO TABLE logs
  PARTITION(dt='2000-01-01',country='GB')
  在文件系统级别, 分区只是表目录下嵌套的子目录。注意,PARTITIONED BY子句中的列定义是表中
  正式的列,成为分区列,但是数据文件中不含这些列的值,因为它们来源于目录名。
  可以在SELECT语句中以通常的方式使用分区列。Hive会对输入进行修剪,从而只扫描相关分区。
  SELECT ts,dt,line
  FROM logs
  WHERE country='GB';
  6.2 桶
  把表或分区组织成桶(bucket)有两个理由。
  第一个理由是获得更高的查询处理效率。Hive在处理有些查询时
  能够利用这个结构,具体而言,连接两个在相同列上划分了桶的表,可以使用Map端连接高效(map-side join)地实现。
  第二个理由是使采样更高效。在开发和修改查询阶段,可以在数据集的一小部分数据上试运行查询,会带来很多方便。
  使用Clustered by子句来指定划分桶所用的列和划分的桶个数;
  Create table Bucketed_users(id INT,name STRING)
  Clustered by(id) INTO 4 BUCKETS;
  如上所示,我们使用用户ID来确定如何划分桶(Hive对值进行哈希并将结果除以桶的个数取余数)。
  map连接:首先两个表以相同方式划分桶,处理左边表内某个桶的mapper知道右边表内相匹配的行在对应的桶内,
  这样mapper只需要获取那个桶(右边表内存储数据的一小部分)即可进行连接。
  这一优化方法并不一定要求两张表必须具有相同的桶个数,两个表的桶个数据是倍数关系也可以。
  桶中的数据可以根据一个或多个列另外进行排序。这样每个桶的连接变成了高效的归并排序(merge-sort),可以进一步
  提升map端连接的效率。
  CREATE TABLE bucketed_users(id INT,name STRING)
  CLUSTERED BY (id) SORTED BY(id AC) INTO 4 BUCKETS;
  注意:Hive并不检查数据文件中的桶是否和表定义的桶一致(无论桶的数量还是划分桶的列),如果两者不匹配,
  在查询时可能会碰到错误或未定义的结果。因此,建议让Hive来划分桶的操作。
  INSERT OVERWRITE TABLE bucketed_users
  SELECT * FROM users;
  向分桶后的表填充成员,需要将hive.enforce.bucketing属性设置为true。
  物理上,每个桶就是表(或分区)目录里的一个文件。文件名并不重要,但是桶是按照字典序排列的第N个文件。
  用TABLESAMPLE子句对表进行取样。
  SELECT * FROM bucketed_users
  TABLESAMPLE(BUCKET 1 OUT OF 4 ON id);
  桶的个数从1开始计数,前面的查询从4个桶的第一个中获取所有的用户,这会返回表中约1/4的数据行。
  6.3 存储格式
  Hive从两个维度对标的存储进行管理,分别是行格式(row format)和文件格式(file format).
  文件格式是指一行中字段容器的格式,最简单的格式是纯文本文件,也可以使用面向行和面向列的二进制格式。
  行格式是指行和一行中的字段如何存储。按照Hive的术语,行格式的定义由SerDe定义。
  SerDe是序列化和反序列化工具合成词,在执行insert或者ctas时,表的SerDe会把Hive的数据行内部表示
  形式序列化成字节形式写出输出文件中。当查询表时,SerDe将把文件中字节形式的数据航反序列化为Hive内部操作
  数据行时所使用对象形式。
  1.默认存储格式: 分隔的文本
  若在创建表时没有用row format或stored as子句,hive所使用的默认格式是分隔的文本,每行存储一个数据行。
  Hive内部使用一个名为LazySimpleSerDe的SerDe来处理这种分隔格式以及MapReduce文本输入和输出格式。
  2.二进制存储格式:顺序文件、Avro数据文件、Parquet文件、RCFile与ORCFile
  二进制格式的使用方法非常简单,只需要通过CREATE TABLE语句总的STORED AS 子句来做相应声明。
  不需要指定ROW FORMAT,因为其格式由底层的二进制文件格式来控制。
  二进制格式可划分为两大类: 面向行的格式和面向列的格式。
  一般来说,面向列的存储格式对于那些只访问表中一小部分列的查询比较有效,相反面向行的存储格式适合
  同时处理一行中很多列的情况。
  3.使用定制的SerDe: RegexSerDe
  示例,将使用一个自定义的SerDe,它采用一个正则表达式从一个文本文件中读取定长的观测站元数据:
  CREATE TABLE stations(usaf STRING,wban STRING,name STRING)
  ROW FORMAT SERDER 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe'
  WITH SERDEPROPERTIES(
    "input.regex" = "(\\d{6} (\\d{5}) (.{29}))"
  );
  SerDe可以用WITH SERDEPROPERTIES子句来设置额外的属性,input.regex是在反序列化时用的正则表达式,
  用来将数据行中的部分文本转化为列的集合。
  在这个示例中,有三个捕获组: usaf(六位数的标识符)、wban(五位数的标识符)以及name(29个字符的定长列)。
  使用LOAD DATA语句向表中输入数据:
  LOAD DATA LOCAL INPATH "input/ncdc/metadata/stations-fixed-width.txt" INTO
  TABLE stations;
  LOA DATA把文件复制或移动到Hive的仓库目录中。在这里,由于源在本地文件系统中,所以使用的是复制操作。
  加载操作并不使用表的SerDe。
  从文件检索数据时,反序列化会调用SerDe,从而使每一行的字段都能被正确解析出来:
  select * from stations LIMIT 4;

  6.4 导入数据
  INSERT语句示例:
  INSERT OVERWRITE TABLE TARGET
  select col1,col2 from source;
  分区表插入示例:(OVERWRITE关键字意味着目标表中的内容会被SELECT语句的结果替换掉,如果仅仅是填充可以
  使用INSERT INTO TABLE)
  INSERT OVERWRITE TABLE TARGET
  PARTITION(DT='2000-01-01')
  SELECT COL1,COL2 FROM SOURCE;
  动态插入分区表:
  INSERT OVERWRITE TABLE TARGET
  PARTITION(DT)
  SELECT COL1,COL2,DT FROM SOURCE;
  多表插入:
  FROM RECORDS2
  INSERT OVERWRITE TABLE STATIONS_BY_YEAR
  SELECT YEAR,COUNT(1)
  GROUP BY YEAR;
  SELECT YEAR,COUNT(1)
  WHERE TEMPERATURE != 9999 AND QUALITY IN (0,1,4,5,9)
  GROUP BY YEAR;
  CRTS用法:
  CREATE TABLE TARGET
  AS
  SELECT COL1,COL2 FROM SOURCE;

  6.5 表的修改
  重命名(更新表的元数据, 还把表目录名称修改掉/user/hive/warehouse/target)
  alter table source rename to target;
  添加新列
  alter table target add columns(col3 STRING);
  新添加的col3添加在已有列后面,数据文件并没有被更新,因此查询col3的所有只返回为空值null(除非文件中已有额外字段)
  因为Hive并不允许更新已有记录,所以需要其他机制来更新底层文件,为此更常用的做法是创建一个定义了新列的新表,
  使用select语句把数据填充进去。
  6.6 表的丢弃
  drop table 用于删除表的数据和元数据,若是外部表,仅删除元数据,数据不受影响。
  truncate table 删除表内所有数据,但保留表定义。但对于外部表不起作用,这种情况需要再Hive的Shell环境中使用
  dfs -rmr 命令删除外部表目录。
  create table new_table like existing_table; //使用LIKE关键字创建一个与第一个表模式相同的新表。

  6.7 排序和聚集
  Hive可以使用标准的ORDER BY 子句对数据进行排序。ORDER BY将对输入执行全排序。在很多情况下,并不需要结果是
  全局排序的,可以使用HIVE 非标准的扩展SORT BY,SORT BY为每个REDUCER产生一个排序文件。
  在某些情况下,需要控制某个特定行应该到哪个reducer,目的通常是为了进行后续的聚集操作。
  通过Hive的Distribute By子句可以实现此目的。
  下面的例子根据年份和气温对气象数据集进行排序,确保所有具有相同年份的行最终在同一个reducer分区中。
  FROM records2
  SELECT year,temperature
  DISTRIBUTE BY year
  SORT BY year ASC,temperature DESC;
  如果SORT BY和DISTRIBUTE BY所用的列相同,可以缩写为CLUSTER BY以便同时指定两者所用的列。

  6.8 MapReduce脚本
  与Hadoop Streaming类似,TRANSFORM、MAP和REDUCE子句可以在Hive中调用外部脚本或程序。
  6.9 连接
  SELECT sales.*,things.*
  FROM sales JOIN things on(sales.id=things.id);
  SELECT sales.*,things.*
  FROM sales,things
  WHERE sales.id = things.id;
  Hive只支持等值连接,意味着连接谓词中只能使用等号。
  Hive 可以在连接谓词中使用AND关键字分隔一系列表达式连接多个列,使用JOIN ...ON...连接多个表。
  如果多个连接的连接条件使用了相同的列,那么平均每个连接可以少用一个MapReduce作业来实现。

  外连接
  SELECT sales.*,things.*
  FROM sales Left Outer Join things on (sales.id = things.id);

  select sales.*,things.*
  FROM sales RIGHT OUTER JOIN things on (sales.id = things.id);

  全连接
  SELECT sales.*,things.*
  FROM sales FULL OUTER JOIN things on (sales.id = things.id);

  半连接
  SELECT *
  FROM things
  WHERE things.id IN (SELECT id from sales);

  SELECT *
  FROM things LEFT SEMI JOIN sales on (sales.id = things.id);

  Map连接
  SELECT sales.*,things.*
  FROM sales JOIN things on(sales.id=things.id);
  如果有一个连接小到足以放入内测,Hive就可以将较小的表放入每个mapper内存来执行连接操作。
  mapper连接可以利用分桶的表,因为作用于左侧表的桶的mapper加载右侧对应的桶接口执行连接。
  需要下述设置启动:
  SET hive.optimize.bucketmapjoin=true;

  子查询
  Hive对子查询支持很有限,只允许只查询出现在SELECT语句的FROM子句中。或某些特殊情况下的WHERE子句中。

  视图
  视图是一种用SELECT语句定义的虚表,视图的SELECT语句只是在执行引用视图的语句时才执行。
  CREATE VIEW xxx
  AS
  SELECT * FROM XXX WHERE XXX;

 

你可能感兴趣的:(Hive 使用简介)