【转载】Hive 教程(官方Tutorial)

转载自:http://www.javashuo.com/article/p-nobihskb-gb.htmlcss

Tutorial

  • Hive Tutorial
  • Concepts
    • What Is Hive
    • What Hive Is NOT
    • Getting Started
    • Data Units
    • Type System
    • Built In Operators and Functions
    • Language Capabilities
  • Usage and Examples
    • Creating, Showing, Altering, and Dropping Tables
    • Loading Data
    • Querying and Inserting Data

概念

Hive是什么

Hive是一个基于Apache Hadoop的数据仓库。对于数据存储与处理,Hadoop提供了主要的扩展和容错能力。web

Hive设计的初衷是:对于大量的数据,使得数据汇总,查询和分析更加简单。它提供了SQL,容许用户更加简单地进行查询,汇总和数据分析。同时,Hive的SQL给予了用户多种方式来集成本身的功能,而后作定制化的查询,例如用户自定义函数(User Defined Functions,UDFs).正则表达式

Hive不适合作什么

Hive不是为在线事务处理而设计。它最适合用于传统的数据仓库任务。sql

Getting Started

对于Hive, HiveServer2 和Beeline的设置详情,请参考指南数据库

对于学习Hive,这些书单可能对你有所用处。apache

如下部分提供了一个关于Hive系统功能的教程。先描述数据类型,表和分区的概念,而后使用例子来描述Hive的功能。数组

数据单元

根据颗粒度的顺序,Hive数据被组织成:
- 数据库:命名空间功能,为了不表,视图,分区,列等等的命名冲突。数据库也能够用于增强用户或用户组的安全。安全

  • 表:相同数据库的同类数据单元。例如表page_views,表的每行包含如下列:bash

    • timestamp -这是一个INT类型,是当页面被访问时的UNIX时间戳。
    • userid -这是一个BIGINT类型,用于唯一识别访问页面的用户。
    • page_url -这是一个STRING类型,用于存储页面地址。
    • referer_url -这是一个STRING类型,用于存储用户是从哪一个页面跳转到本页面的地址。
    • IP -这是一个STRING类型,用于存储页面请求的IP地址。
  • 分区:每一个表能够有一个或多个用于决定数据如何存储的分区键。分区(除存储单元以外)也容许用户有效地识别知足指定条件的行;例如,STRING类型的date_partitionSTRINGcountry_partition。这些分区键的每一个唯一的值定义了表的一个分区。例如,全部的“2009-12-23”日期的“US”数据是表page_views的一个分区。(注意区分,分区键与分区,若是分区键有两个,每一个分区键有三个不一样的值,则共有6个分区)。所以,若是你只在日期为“2009-12-23”的“US”数据上执行分析,你将只会在表的相关数据上执行查询,这将有效地加速分析。然而要注意,那仅仅是由于有个分区叫2009-12-23,并不意味着它包含了全部数据,或者说,这些数据仅仅是那个日期的数据。用户须要保证分区名字与数据内容之间的关系。分区列是虚拟列,它们不是数据自己的一部分,而是源于数据加载。markdown

  • 桶(Buckets or Clusters):每一个分区的数据,基于表的一些列的哈希函数值,又被分割成桶。例如,表page_views可能经过userid分红桶,userid是表page_view的一个列,不一样于分区列。这些桶能够被用于有效地抽样数据。

类型系统

Hive支持原始类型和复要类型,以下所述,查看Hive Data Types

原始类型

  • 类型与表的列相关。支持如下原始类型:
  • Integers(整型)
    • TINYINT -1位的整型
    • SMALLINT -2位的整型
    • INT -4位的整型
    • BIGINT -8位的整型
  • 布尔类型
    • BOOLEAN -TRUE/FALSE
  • 浮点数
    • FLOAT -单精度
    • DOUBLE -双精度
  • 定点数
    -DECIMAL -用户能够指定范围和小数点位数
  • 字符串
    -STRING -在特定的字符集中的一个字符串序列
    -VARCHAR -在特定的字符集中的一个有最大长度限制的字符串序列
    -CHAR -在特定的字符集中的一个指定长度的字符串序列
  • 日期和时间
    -TIMESTAMP -一个特定的时间点,精确到纳秒。
    -DATE -一个日期
  • 二进制
    -BINARY -一个二进制位序列

复杂类型

复杂类型能够由原始类型和其余组合类型构建:
- 结构体类型(Stuct): 使用点(.)来访问类型内部的元素。例如,有一列c,它是一个结构体类型{a INT; b INT},字段a可使用表达式c.a来访问。
- Map(key-value键值对):使用['元素名']来访问元素。例如,有一个MapM,包含'group'->gid的映射,则gid的值可使用M['group']来访问。
- 数组:数组中的元素是相同的类型。可使用[n]来访问数组元素,n是数组下标,以0开始。例若有一个数组A,有元素['a','b','c'],则A[1]返回'b'

内置运算符和函数

Hive全部关键词的大小写都不敏感,包括Hive运算符和函数的名字。

内置运算

  • 关系运算
    这里写图片描述
  • 数学运算
    这里写图片描述
  • 逻辑运算
    这里写图片描述
  • 复杂类型的运算
    这里写图片描述

内置函数

  • Hive支持如下内置函数
    这里写图片描述
    这里写图片描述
  • Hive支持如下内置聚合函数
    这里写图片描述

语言能力

Hive’s SQL提供了基本的SQL操做。这些操做工做于表或分区上。这些操做是:
- 可使用WHERE从表中筛选行
- 可使用SELECT从表中查询指定的列
- 两个表之间能够join
- 能够在多个group by的列上使用聚合
- 能够存储查询结构到另外一个表
- 能够下载表的内容到本地目录
- 能够存储查询结果到hadoop的分布式文件系统目录上
- 能够管理表和分区(建立,删除和修改)
- 可使用自定义的脚本,来定制map/reduce做业

使用和实例

如下的例子有一些不是最新的,更多最新的信息,能够参考LanguageManual

如下的例子强调了Hive系统的显著特征。详细的查询测试用例和相应的查询结果能够在Hive Query Test Cases’上找到。

  • 建立,显示,修改,和删除表
  • 加载数据
  • 查询和插入数据

建立,显示,修改,和删除表

建立表

如下例子建立表page_view

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
CREATE TABLE page_view(viewTime INT, userid BIGINT, page_url STRING, referrer_url STRING, ip STRING COMMENT 'IP Address of the User') COMMENT 'This is the page view table' PARTITIONED BY(dt STRING, country STRING) STORED AS SEQUENCEFILE;

在这个例子中,表的列被指定相应的类型。备注(Comments)能够基于列级别,也能够是表级别。另外,使用PARTITIONED关键词定义的分区列与数据列是不一样的,分区列实际上不存储数据。当使用这种方式建立表的时候,咱们假设数据文件的内容,字段之间以ASCII 001(ctrl-A)分隔,行之间以换行分隔。

若是数据不是以上述格式组织的,咱们也能够指定分隔符,以下:

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
CREATE TABLE page_view(viewTime INT, userid BIGINT, page_url STRING, referrer_url STRING, ip STRING COMMENT 'IP Address of the User') COMMENT 'This is the page view table' PARTITIONED BY(dt STRING, country STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY '1' STORED AS SEQUENCEFILE;

目前,行分隔符不能指定,由于它不是由Hive决定,而是由Hadoop分隔符。

对表的指定列进行分桶,是一个好的方法,它能够有效地对数据集进行抽样查询。若是没有分桶,则会进行随机抽样,因为在查询的时候,须要扫描全部数据,所以,效率不高。如下例子描述了,在表page_viewuserid列上进行分桶的例子:

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
CREATE TABLE page_view(viewTime INT, userid BIGINT, page_url STRING, referrer_url STRING, ip STRING COMMENT 'IP Address of the User') COMMENT 'This is the page view table' PARTITIONED BY(dt STRING, country STRING) CLUSTERED BY(userid) SORTED BY(viewTime) INTO 32 BUCKETS ROW FORMAT DELIMITED FIELDS TERMINATED BY '1' COLLECTION ITEMS TERMINATED BY '2' MAP KEYS TERMINATED BY '3' STORED AS SEQUENCEFILE;

以上例子,经过一个userid的哈希函数,表被分红32个桶。在每一个桶中的数据,是以viewTime升序进行存储。这样组织数据容许用户有效地在这n个桶上进行抽样。合适的排序使得内部操做充分利用熟悉的数据结构来进行更加有效的查询。

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
CREATE TABLE page_view(viewTime INT, userid BIGINT, page_url STRING, referrer_url STRING, friends ARRAY<BIGINT>, properties MAP<STRING, STRING>, ip STRING COMMENT 'IP Address of the User') COMMENT 'This is the page view table' PARTITIONED BY(dt STRING, country STRING) CLUSTERED BY(userid) SORTED BY(viewTime) INTO 32 BUCKETS ROW FORMAT DELIMITED FIELDS TERMINATED BY '1' COLLECTION ITEMS TERMINATED BY '2' MAP KEYS TERMINATED BY '3' STORED AS SEQUENCEFILE;

在这个例子,CLUSTERED BY指定列进行分桶,以及建立多少个桶。行格式分隔符指定在hive表中,行如何存储。在这种分隔符状况下,指定了字段是如何结束,集合项(数组和map)如何结束,以及map的key是如何结束的。STORED AS SEQUENCEFILE表示这个数据是以二进制格式进行存储数据在hdfs上。对于以上例子的ROW FORMAT的值和STORED AS表示系统默认值。

表名和列名不区分大小写。

浏览表和分区

   
   
   
   
  • 1
SHOW TABLES;

列出数据库里的全部的表,也能够这么浏览:

   
   
   
   
  • 1
SHOW TABLES 'page.*';

这样将会列出以page开头的表,模式遵循Java正则表达式语法。

   
   
   
   
  • 1
SHOW PARTITIONS page_view;

列出表的分区。若是表没有分区,则抛出错误。

   
   
   
   
  • 1
DESCRIBE page_view;

列出表的列和列的类型。

   
   
   
   
  • 1
DESCRIBE EXTENDED page_view;

列出表的列和表的其余属性。这会打印不少信息,且输出的风格不是很友好,一般用于调试。

   
   
   
   
  • 1
DESCRIBE EXTENDED page_view PARTITION (ds='2016-08-08');

列出列和分区的全部属性。这也会打印出许多信息,一般也是用于调试。

修改表

对已有的表进行重命名。若是表的新名字存在,则报错:

   
   
   
   
  • 1
ALTER TABLE old_table_name RENAME TO new_table_name;

对已有表的列名进行重命名。要确保使用相同的列类型,且要包含对每一个已存在列的一个入口(也就是说,就算不修改其余列的列名,也要把此列另上,不然,此列会丢失)。

   
   
   
   
  • 1
ALTER TABLE old_table_name REPLACE COLUMNS (col1 TYPE, ...);

对已有表增长列:

   
   
   
   
  • 1
ALTER TABLE tab1 ADD COLUMNS (c1 INT COMMENT 'a new int column', c2 STRING DEFAULT 'def val');

注意:
模式的改变(例如增长列),保留了表的老分区,以避免它是一个分区表。全部对这些列或老分区的查询都会隐式地返回一个null值或这些列指定的默认值。

删除表和分区

删除表是至关,表的删除会删除已经创建在表上的任意索引。相关命令是:

   
   
   
   
  • 1
DROP TABLE pv_users;

要删除分区。修改表删除分区:

   
   
   
   
  • 1
ALTER TABLE pv_users DROP PARTITION (ds='2016-08-08')

注意:此表或分区的任意数据都将被删除,并且可能没法恢复。

加载数据

要加载数据到Hive表有许多种方式。用户能够建立一个“外部表”来指向一个特定的HDFS路径。用这种方法,用户可使用HDFSputcopy命令,复制一个文件到指定的位置,而且附上相应的行格式信息建立一个表指定这个位置。一旦完成,用户就能够转换数据和插入他们到任意其余的Hive表中。例如,若是文件/tmp/pv_2016-06-08.txt包含逗号分隔的页面访问记录。这须要以合适的分区加载到表page_view,如下命令能够完成这个目标:

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
CREATE EXTERNAL TABLE page_view_stg(viewTime INT, userid BIGINT, page_url STRING, referrer_url STRING, ip STRING COMMENT 'IP Address of the User', country STRING COMMENT 'country of origination') COMMENT 'This is the staging page view table' ROW FORMAT DELIMITED FIELDS TERMINATED BY '44' LINES TERMINATED BY '12' STORED AS TEXTFILE LOCATION '/user/data/staging/page_view'; hadoop dfs -put /tmp/pv_2016-06-08.txt /user/data/staging/page_view FROM page_view_stg pvs INSERT OVERWRITE TABLE page_view PARTITION(dt='2016-06-08', country='US') SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip WHERE pvs.country = 'US';

其中,‘44’是逗号的ASCII码,‘12’是换页符(NP from feed,new page)。null是做为目标表中的数组和map类型插入,若是指定了合适的行格式,这些值也能够来自外部表。

若是在HDFS上有一些历史数据,用户想增长一些元数据,以便于可使用Hive来查询和操纵这些数据,这个方法是颇有用的。

另外,系统也支持直接从本地文件系统上加载数据到Hive表。表的格式与输入文件的格式须要相同。若是文件/tmp/pv_2016-06-08包含了US数据,而后咱们不须要像前面例子那样的任何筛选,这种状况的加载可使用如下语法完成:

   
   
   
   
  • 1
LOAD DATA LOCAL INPATH /tmp/pv_2016-06-08_us.txt INTO TABLE page_view PARTITION(date='2016-06-08', country='US')

路径参数能够是一个目录(这种状况下,目录下的全部文件将被加载),一个文件,或一个通配符(这种状况下,全部匹配的文件会上传)。若是参数是目录,它不能包含子目录。一样,通配符只匹配文件名。

在输入文件/tmp/pv_2016-06-08.txt很是大的状况下,用户能够采用并行加载数据的方式(使用Hive的外部工具)。只要文件在HDFS上-如下语法能够用于加载数据到Hive表:

   
   
   
   
  • 1
LOAD DATA INPATH '/user/data/pv_2016-06-08_us.txt' INTO TABLE page_view PARTITION(date='2016-06-08', country='US')

对于这个例子,咱们假设数组和map在文件中的值为null

更多关于加载数据到表的信息,请参考Hive Data Manipulation Language,建立外部表的另一个例子请参考External Tables

查询和插入数据

  • Simple Query
  • Partition Based Query
  • Joins
  • Aggregations
  • Multi Table/File Inserts
  • Dynamic-Partition Insert
  • Inserting into Local Files
  • Sampling
  • Union All
  • Array Operations
  • Map (Associative Arrays) Operations
  • Custom Map/Reduce Scripts
  • Co-Groups

Hive查询操做在文档Select,插入操做在文档insert data into Hive Tables from querieswriting data into the filesystem from queries

简单的查询

对于全部的活跃用户,可使用如下查询格式:

   
   
   
   
  • 1
  • 2
  • 3
  • 4
INSERT OVERWRITE TABLE user_active SELECT user.* FROM user WHERE user.active = 1;

注意:不像SQL,咱们总是插入结果到表中。随后咱们会描述,用户如何检查这些结果,甚至把结果导出到一个本地文件。你也能够在Beeline或HiveCLI执行如下查询:

   
   
   
   
  • 1
  • 2
  • 3
SELECT user.* FROM user WHERE user.active = 1;

这在内部将会重写到一些临时文件,并在Hive客户端显示。

基于查询的分区

在一个查询中,要使用什么分区,是由系统根据where在分区列上条件自动的决定。例如,为了获取全部2008年3月份,从域名xyz.com过来的page_views,能够这么写查询:

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
INSERT OVERWRITE TABLE xyz_com_page_views SELECT page_views.* FROM page_views WHERE page_views.date >= '2008-03-01' AND page_views.date <= '2008-03-31' AND page_views.referrer_url like '%xyz.com';

注意:在这里使用的page_views.date是用PARTITIONED BY(date DATATIME, country STRING)定义的.若是你的分区命名不同,那么不要期望.date可以作你想作的事情,即没法得到分区的优点。

链接

表的链接可使用如下命令:

   
   
   
   
  • 1
  • 2
  • 3
  • 4
INSERT OVERWRITE TABLE pv_users SELECT pv.*, u.gender, u.age FROM user u JOIN page_view pv ON (pv.userid = u.id) WHERE pv.date = '2008-03-03';

想实现外链接,用户可使用LEFT OUTER,RIGHT OUTERFULL OUTER关键词来指示不一样的外链接(左保留,右保留或两端都保留)。例如,想对上面的查询作一个FULL OUTER,相应的语法能够像下面这样:

   
   
   
   
  • 1
  • 2
  • 3
  • 4
INSERT OVERWRITE TABLE pv_users SELECT pv.*, u.gender, u.age FROM user u FULL OUTER JOIN page_view pv ON (pv.userid = u.id) WHERE pv.date = '2008-03-03';

为了检查key在另一个表中是否存在,用户可使用LEFT SEMI JOIN,正如如下例子同样:

   
   
   
   
  • 1
  • 2
  • 3
  • 4
INSERT OVERWRITE TABLE pv_users SELECT u.* FROM user u LEFT SEMI JOIN page_view pv ON (pv.userid = u.id) WHERE pv.date = '2008-03-03';

为了链接多个表,可使用如下语法:

   
   
   
   
  • 1
  • 2
  • 3
  • 4
INSERT OVERWRITE TABLE pv_friends SELECT pv.*, u.gender, u.age, f.friends FROM page_view pv JOIN user u ON (pv.userid = u.id) JOIN friend_list f ON (u.id = f.uid) WHERE pv.date = '2008-03-03';

注意:Hive只支持equi-joins。因此,把最大的表放在join的最右边,能够获得最好的性能。

聚合

统计用户每一个性别的人数,可使用如下查询:

   
   
   
   
  • 1
  • 2
  • 3
  • 4
INSERT OVERWRITE TABLE pv_gender_sum SELECT pv_users.gender, count (DISTINCT pv_users.userid) FROM pv_users GROUP BY pv_users.gender;

能够同时作多个聚合,然而,两个聚合函数不能同时用DISTINCT做用于不一样的列,如下状况是能够的(DISTINCT做用于相同列):

   
   
   
   
  • 1
  • 2
  • 3
  • 4
INSERT OVERWRITE TABLE pv_gender_agg SELECT pv_users.gender, count(DISTINCT pv_users.userid), count(*), sum(DISTINCT pv_users.userid) FROM pv_users GROUP BY pv_users.gender;

然而,如下状况(DISTINCT做用于不一样的列)是不容许的:

   
   
   
   
  • 1
  • 2
  • 3
  • 4
INSERT OVERWRITE TABLE pv_gender_agg SELECT pv_users.gender, count(DISTINCT pv_users.userid), count(DISTINCT pv_users.ip) FROM pv_users GROUP BY pv_users.gender;

多表/文件插入

聚合或简单查询的输出能够插入到多个表中,或者甚至是HDFS文件(可以使用HDFS工具进行操纵)。例如,若是沿用前面的“性别分类”,例子以下:

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
FROM pv_users INSERT OVERWRITE TABLE pv_gender_sum SELECT pv_users.gender, count_distinct(pv_users.userid) GROUP BY pv_users.gender INSERT OVERWRITE DIRECTORY '/user/data/tmp/pv_age_sum' SELECT pv_users.age, count_distinct(pv_users.userid) GROUP BY pv_users.age;

第一个插入语句将结果插入到Hive表中,而第二个插入语句是将结果写到HDFS文件。

动太分区插入

在前面的例子中,咱们知道,在插入语句中,只能有一个分区。若是咱们想加载到多个分区,咱们必须像如下描述来使用多条插入语句:

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
FROM page_view_stg pvs INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country='US') SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip WHERE pvs.country = 'US' INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country='CA') SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip WHERE pvs.country = 'CA' INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country='UK') SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip WHERE pvs.country = 'UK';

为了加载数据到所有的country分区到指定的日期。咱们必须在输入数据中为每一个country增长一条插入语句。这是很是不方便的,由于咱们须要提早建立且知道已存在哪些country分区列表。若是哪天这些country列表变了,咱们必须修改咱们的插入语句,也应该建立相应的分区。这也是很是低效的,由于每一个插入语句可能都是转换成一个MapReduce做业。

动态分区插入(Dynamic-partition insert)(或multi-partition插入)就是为了解决以上问题而设计的,它经过动态地决定在扫描数据的时候,哪些分区应该建立和填充。这个新的特征是在版本0.6.0加入的。在动态分区插入中,输入列被评估,这行应该插入到哪一个分区。若是分区没有建立,它将自动建立这个分区。使用这个特征,咱们仅仅须要插入语桀犬吠尧来建立和填充全部须要的分区。另外,由于只有一个插入语句,相应的也只有一个MapReduce做业。相比多个插入语句的状况,这将显著地提升性能且下降Hadoop集群负载。

如下是使用一个插入语句,加载数据到全部country分区的例子:

   
   
   
   
  • 1
  • 2
  • 3
FROM page_view_stg pvs INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country) SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip, pvs.country

与多条插入语句相比,动态分区插入有一些语法上的不一样:
- country出如今PARTITION后面,可是没有具体的值。这种状况,country就是一个动态分区列。另外一方面,dt有一个值,这意味着它是一个静态的分区列。若是一个列是动态分区列,它的值将会使用输入列的值。目前,咱们仅仅容许在分区条件的最后一列放置动态分区列,由于分区列的顺序,指示了它的层级次序(意味着dt是根分区,country是子分区)。咱们不能这样指定分区(dt,country=’US’),由于这表示,咱们须要更新全部的日期的分区且它的country子分区是‘US’。

  • 一个额外的pvs.country列被加入在查询语句中。这对动态分区列来讲,至关于输入列。注意:对于静态分区列,咱们不须要添加一个输入列,由于在PARTITION语句中,它的值已经知道。注意:动态分区列的值(不是名字)查出来是有序的,且是放在select语句的最后。

动态分区插入的语义:
- 对于动态分区列,当已经此分区时,(例如,country='CA'已存在dt根分区下面)若是动态分区插入与输入数据中相同的值(’CA’),它将会被重写(overwritten)。

插入到本地文件

在某些场合,咱们须要把输出写到一个本地文件,以便于能用excel表格打开。这可使用如下命令:

   
   
   
   
  • 1
  • 2
  • 3
INSERT OVERWRITE LOCAL DIRECTORY '/tmp/pv_gender_sum' SELECT pv_gender_sum.* FROM pv_gender_sum;

抽样

抽样语句容许用户对数据抽样查询,而不是全表查询。当前,抽样是对那些在CREATE TABLE语句的CLUSTERED BY修饰的列上。如下例子,咱们从表pv_gender_sum表中的32个桶中,选择第3个桶。

   
   
   
   
  • 1
  • 2
  • 3
INSERT OVERWRITE TABLE pv_gender_sum_sample SELECT pv_gender_sum.* FROM pv_gender_sum TABLESAMPLE(BUCKET 3 OUT OF 32);

一般,TABLESAMPLE的语法像这样:

   
   
   
   
  • 1
TABLESAMPLE(BUCKET x OUT OF y)

这个y必须是桶的数量的因子或倍数,桶的数量是在建立表的时候指定的。抽样所选的桶由桶大小,y和x共同决定。若是y和桶大小相等,则抽样所选的桶是x对y的求模结果。

   
   
   
   
  • 1
TABLESAMPLE(BUCKET 3 OUT OF 16)

这将抽样第3个和第19个桶。桶的编号从0开始。

tablesample语句的另外一方面:

   
   
   
   
  • 1
TABLESAMPLE(BUCKET 3 OUT OF 64 ON userid)

这将抽取第3个桶的一半。

union all

这个语言也支持union all,若是假设咱们有两个不一样的表,分别用来记录用户发布的视频和用户发布的评论,如下例子是一个union all 的结果与用户表再链接的查询:

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
INSERT OVERWRITE TABLE actions_users SELECT u.id, actions.date FROM ( SELECT av.uid AS uid FROM action_video av WHERE av.date = '2008-06-03' UNION ALL SELECT ac.uid AS uid FROM action_comment ac WHERE ac.date = '2008-06-03' ) actions JOIN users u ON(u.id = actions.uid);

数组操做

表的数组列能够这样:

   
   
   
   
  • 1
CREATE TABLE array_table (int_array_column ARRAY<INT>);

假设pv.friends 是类型ARRAY<INT>(也就是一个整型数组),用户能够经过索引号获取数组中特定的元素,以下:

   
   
   
   
  • 1
  • 2
SELECT pv.friends[2] FROM page_views pv;

这个查询获得的是pv.friends里的第三个元素。

用户也可使用函数size来获取数组的长度,以下:

   
   
   
   
  • 1
  • 2
SELECT pv.userid, size(pv.friends) FROM page_view pv;

Map(关联数组)操做

Map提供了相似于关联数组的集合。这样的结构不只能够由程序建立。咱们也将很快能够继承这个。假设pv.properties是类型map<String,String>,以下:

   
   
   
   
  • 1
  • 2
  • 3
INSERT OVERWRITE page_views_map SELECT pv.userid, pv.properties['page type'] FROM page_views pv;

这将查询表page_views的‘page_type‘属性。

与数组类似,也可使用函数size来获取map的大小:

   
   
   
   
  • 1
  • 2
SELECT size(pv.properties) FROM page_view pv;

定制Map/Reduce脚本

经过使用Hive语言原生支持的特征,用户能够插入他们本身定制的mapper和reducer在数据流中。例如,要运行一个定制的mapper脚本script-map_script和reducer脚本script-reduce_script),用户能够执行如下命令,使用TRANSFORM来嵌入mapper和reducer脚本。

注意:在执行用户脚本以前,表的列会转换成字符串,且由TAB分隔,用户脚本的标准输出将会被做为以TAB分隔的字符串列。用户脚本能够输出调试信息到标准错误输出,这个信息也将显示hadoop的详细任务页面上。

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
FROM ( FROM pv_users MAP pv_users.userid, pv_users.date USING 'map_script' AS dt, uid CLUSTER BY dt) map_output INSERT OVERWRITE TABLE pv_users_reduced REDUCE map_output.dt, map_output.uid USING 'reduce_script' AS date, count;

map脚本样本(weekday_mapper.py)

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
import sys import datetime for line in sys.stdin: line = line.strip() userid, unixtime = line.split('\t') weekday = datetime.datetime.fromtimestamp(float(unixtime)).isoweekday() print ','.join([userid, str(weekday)])

固然,对于那些常见的select转换,MAP和REDUCE都是“语法糖”。内部查询也能够写成这样:

   
   
   
   
  • 1
SELECT TRANSFORM(pv_users.userid, pv_users.date) USING 'map_script' AS dt, uid CLUSTER BY dt FROM pv_users;

Co-Groups

在使用map/reduce的群体中,cogroup是至关常见的操做,它是未来自多个表的数据发送到一个定制的reducer,使得行由表的指定列的值进行分组。在Hive的查询语言中,可使用如下方式,经过使用union allcluster by来实现此功能。假设咱们想对来自表actions_videoaction_comment的行对uid列进行分组,且须要发送他们到reducer_script定制的reducer,可使用如下语法:

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
FROM ( FROM ( FROM action_video av SELECT av.uid AS uid, av.id AS id, av.date AS date UNION ALL FROM action_comment ac SELECT ac.uid AS uid, ac.id AS id, ac.date AS date ) union_actions SELECT union_actions.uid, union_actions.id, union_actions.date CLUSTER BY union_actions.uid) map INSERT OVERWRITE TABLE actions_reduced SELECT TRANSFORM(map.uid, map.id, map.date) USING 'reduce_script' AS (uid, id, reduced_val);

翻译自:
https://cwiki.apache.org/confluence/display/Hive/Tutorial

相关文章
相关标签/搜索