Cloudera CDH 、Impala本地通过Parcel安装配置详解

original:http://www.cnblogs.com/shudonghe/archive/2013/06/19.html

一、Parcel本地源与Package本地源的区别

本地通过Parcel安装过程与本地通过Package安装过程完全一致,不同的是两者的本地源的配置。

区别如下:

Package本地源:软件包是.rpm格式的,数量通常较多,下载的时候比较麻烦。通过”createrepo .”的命令创建源,并要放到存放源文件主机的web服务器的根目录下,详见创建本地yum软件源,为本地Package安装Cloudera Manager、Cloudera Hadoop及Impala做准备

Parcel本地源:软件包是以.parcel结尾,相当于压缩包格式的,一个系统版本对应一个,下载的时候方便。如centos 6.x使用的CDH版本为CDH-4.3.0-1.cdh4.3.0.p0.22-el6.parcel,而centos 5.x使用的CDH版本为CDH-4.3.0-1.cdh4.3.0.p0.22-el5.parcel

CDH的下载地址:http://archive.cloudera.com/cdh4/parcels/

IMPALA的下载地址:http://archive.cloudera.com/impala/parcels/

下载好相应的.parcel文件后,拷贝到本地的parcel源目录下(有Cloudera Manager Server指定,默认是/opt/cloudera/parcel-repo),然后打开同目录下的mainfest.json(也要拷贝到其中)文件,找到与你下载的包一致的那部分,然后根据其创建一个sha文件。例如我的操作系统是CentOS 6.4,下载的对应包为CDH-4.3.0-1.cdh4.3.0.p0.22-el6.parcel,那么就应该找到相应的:

{
      "parcelName": "CDH-4.3.0-1.cdh4.3.0.p0.22-el6.parcel",
      "components": [
        { "name":     "flume-ng",
          "version":  "1.3.0-cdh4.3.0",
          "pkg_version":  "1.3.0+159" 
        }
        ,{ "name":     "hadoop-0.20-mapreduce",
          "version":  "2.0.0-cdh4.3.0",
          "pkg_version":  "2.0.0+1357" 
        },         

           . . . .  <snip> . . . 

        ,{ "name":     "zookeeper",
          "version":  "3.4.5-cdh4.3.0",
          "pkg_version":  "3.4.5+19" 
        }
        ,{ "name":     "hue",
          "version":  "2.3.0-cdh4.3.0",
          "pkg_version":  "2.3.0+136" 
        }
      ],
      "hash": "df5cc61b2d257aaf625341f709a4f8e09754038a"
    },

然后创建一个后缀名为.sha的文本文件,名字与下载的parcel同名,我下载的为CDH-4.3.0-1.cdh4.3.0.p0.22-el6.parcel,所以sha文件CDH-4.3.0-1.cdh4.3.0.p0.22-el6.parcel.sha。然后执行如下命令将hash码写到sha文件中。

# cat > CDH-4.3.0-1.cdh4.3.0.p0.22-el6.parcel.sha
df5cc61b2d257aaf625341f709a4f8e09754038a

然后将sha文件也拷贝到本地parcel源的目录下。
总之,要确保/opt/cloudera/parcel-repo下面有三个文件:

CDH-4.3.0-1.cdh4.3.0.p0.22-el6.parcel

mainfest.json

CDH-4.3.0-1.cdh4.3.0.p0.22-el6.parcel.sha

这些文件放好之后,CM会获取这个包,并出现在主机->包裹的页面。出现的快慢跟你设置的包的刷新频率有关,默认是1小时。

可以在管理页面的属性标签下的包裹种类里修改。

 

 

 
posted @ 2013-06-19 21:23 九天高远 阅读(132) 评论(0)  编辑
 

一、前言

Hive是Hadoop上的数据仓库框架,其设计目的是让精通SQL技能(但Java编程技能相对较弱)的分析师能够在存放到HDFS大规模数据集上运行查询。提出Hive的主要原因是SQL并不是所有的“大数据”的理想工具。

Hive在工作站上运行,它把SQL转换为一系列在Hadoop集群上运行的MapReduce作业,即用MapReduce操作HDFS数据。Hive把数据组织为表,通过这种方式为存储在HDFS上的数据赋予结构。元数据——如表模式——存储在名为metastore的数据库中。

Hive的metastore默认存储在本地机器上,这样就无法和其他用户共享这些定义。后面将会详细讲述如何在生产环境中设置远程共享metastore。

二、HiveQL

用户通过在Hive的解释器交互,发出HiveQL命令,HiveQL是Hive的查询语言,它是SQL的一种方言,和mysql有很大的相似之处。

1、基本命令:

a、显示metastore数据库中的表:

hive> show tables;
OK
Time taken: 1.528 seconds
hive> show tables;
OK
Time taken: 0.126 seconds
hive>

系统采用”懒“策略,第一次比较慢,当创建metastore数据库后加载的就比较快了。该数据库存放在你运行hive命令所在位置下名为metastore_db的目录中。

我的Hive metastore_db的目录位置如下:

[root@master admin]# find / -name metastore_db
/usr/lib64/R/metastore_db

b.运行Hive脚本

对于较长的脚本,通常保存在.q文件中,在shell环境下用如下命令执行:

% hive -f script.q

如果对于较短的脚本,可以使用-e命令在行内嵌入执行,这两种情况下都不需要加上表示结束的分号。

% hive -e "select * from dummy"

下面是一个生成单行表的方法:

[root@master admin]# echo 'X' > /tmp/dummy.txt
[root@master admin]# cat /tmp/dummy.txt 
X
[root@master admin]# hive -e "create table dummy(value STRING);\
> load data local inpath '/tmp/dummy.txt' \
> overwrite into table dummy"
Logging initialized using configuration in jar:file:/opt/cloudera/parcels/CDH-4.3.0-1.cdh4.3.0.p0.22/lib/hive/lib/hive-common-0.10.0-cdh4.3.0.jar!/hive-log4j.properties
Hive history file=/tmp/root/hive_job_log_450335d5-274c-4082-81a7-0b4bbe8d1c0c_944836217.txt
OK
Time taken: 2.321 seconds
Copying data from file:/tmp/dummy.txt
Copying file: file:/tmp/dummy.txt
Loading data to table default.dummy
rmr: DEPRECATED: Please use 'rm -r' instead.
Moved: 'hdfs://master:8020/user/hive/warehouse/dummy' to trash at: hdfs://master:8020/user/root/.Trash/Current
Table default.dummy stats: [num_partitions: 0, num_files: 1, num_rows: 0, total_size: 2, raw_data_size: 0]
OK
Time taken: 1.369 seconds
[root@master admin]#

无论是在shell命令还是在交互式环境下,Hive都会把操作运行的时间打印到标准错误输出,可以在启动程序的时候使用- S选项强制不限时这条消息,其结果只是查询输出结果。
-S的和不带的对比结果如下:

[root@master admin]# hive -S -e 'select * from dummy'
X
[root@master admin]# hive  -e 'select * from dummy'
Logging initialized using configuration in jar:file:/opt/cloudera/parcels/CDH-4.3.0-1.cdh4.3.0.p0.22/lib/hive/lib/hive-common-0.10.0-cdh4.3.0.jar!/hive-log4j.properties
Hive history file=/tmp/root/hive_job_log_44207314-384b-4f29-a590-834c723b96ad_444463715.txt
OK
X
Time taken: 2.173 seconds
[root@master admin]#

备注:

其他有用的Hive交互式程序的特性有:使用a!前缀来运行宿主操作系统的命令;使用dfs来访问hadoop文件系统。
c、示例

和RDMS一样,Hive把数据组织成表,下面我们用create table语句为气象数据创建一个表格(各行换行符分隔,用’\t’分隔字段):

create table records (year string, temperature int, quality int)
row format delimited
fields terminated by '\t';

创建表格完成后,我们可以向Hive中输入数据,overwrite关键字告诉Hive删除表所对应的目录下的所有文件,如果省略overwrite,Hive就简单的把新文件加入目录,如果有同名文件就替换掉,其他的不作处理。

load data local inpath 'input/ncdc/micro-tab/sample.txt'
overwrite into table records;

这样命令告诉Hive把指定的本地文件放到它的存储目录中,这仅仅是一个简单的文件系统操作,不解析文件,也不会将其转换为内部格式,这是因为hive并不强制星星某种特定的文件格式。文件以原样子逐字存储,Hive对文件没有做任何修改。
Hive的表存储在HDFS中,由(fs.default.name 设为默认值file:///),在Hive的仓库目录中,表存储为目录。仓库录由hive.metastore.warehouse.dir设定,默认值为/user/hive/warehouse,在HDFS的根目录下。

Hive的查询语句:

hive> select year, max(temperature)
    > from records
    > where temperature!=9999
    > and (quality=0 or quality=1 or quality=4 or quality=5 or quality=9)
    > group by year;

d、 多个Hive 共享hadoop集群

如果准备让多个Hive用户共享一个Hadoop集群,则需要更改Hive所使用目录的权限,对所有用户可写。用以下命令创建,并设置合适的权限:

% hadoop -mkdir /tmp
% hadoop -chmod a+w /tmp
% hadoop -mkdir /user/hive/warehouse
% hadoop -chmod a+w /user/hive/warehouse

如果所有用户在同一个用户组中,把仓库目录权限设置为g+w即可。
e、在一个会话中使用SET命令更改设置

hive> set hive.enforce.bucketing=true;

可以只使用带属性名的SET命令查看属性的当前值:

hive> set hive.enforce.bucketing;

设置属性的优先级,数值越小,优先级越高。
1、Hive SET命令

2、命令行-hiveconf选项

3、hive-site.xml

4、hive-default.xml

5、hadoop-site.xml(或等价的core-site.xml、hdfs-site.xml、mapred-site.xml)

6、hadoop-default.xml(或等价的core-default.xml、hdfs-default.xml、mapred-default.xml)

可以对日志的配置进行设置,下面的语句可以方便的将调试信息发送到控制台:

% hive -hiveconf hive.root.logger=DEBUG, console

e、metastore

metastore是Hive的元数据的集中存放地,metastore包括两部分:后台和数据库的存储。默认情况下,metastore服务和hive服务运行在同一个JVM中,它包含一个内嵌的以本地磁盘作为存储的Derby数据库实例,使用内嵌数据库是Hive入门最简单的方法,在局限是一次只能访问一个磁盘上的数据文件,这就意味着一次只能为每一个metastore打开一个hive会话,如果启动两个会话时就会报如下错误:

Failed to start database 'metastore_db'

若果要支持多会话,就要配置使用一个独立的数据库,这种配置称为”本地metastore”。

f、HiveQL和SQL的比较

SQL的延迟级别为秒级,而HiveQL延迟为分钟级别。HiveSQL支持create table as select语法,而SQL不支持。SQL支持存储过程,而HiveSQL支持用户定义函数,MapReduce脚本。

Hive的string类似其他数据库中的VARCHAR,但不能声明存储长度,最长可以存储2GB字符数(理论上)。当然这样做效率较低,可以使用Sqoop对大对象的处理。

可以使用CAST进行数据类型转换,例如CAST(’1′ AS INT),可以把字符串’1′转换为整数1。如果转换失败,那么表达式会返回空(CAST (‘X’ AS INT))。

g、复杂类型

Hive有三种复杂数据类型:array、map、struct,复杂数据类型必须用尖括号”<>”指明其中数据字段的类型。

如下表所示的表定义有三列,每一种对应一种复杂的数据类型:

create table complex(
    col1 arrary<int>,
    col2 map<string, int>,
    col3 struct<a:string, b:int, c:double>
);

下面是展示每种数据类型的访问操作:

hive>select col1[0], col2['b'], col3.c from complex;

h、操作与函数

可以通过hive shell下面键入show functions获取函数列表,用describe function length获取函数帮助。

提供普通的SQL操作:关系操作(x=’a’,空值判断x is null,模式匹配 x like ‘A%’),算数操作(x+1),以及逻辑或(or),如x or y。MySql和Hive中字符串连接使用concat函数。

i、表

Hive表格逻辑上由存储的数据和描述表格中数据形式的相关数据组成。数据一般存放在HDFS中,当然也可以放在本地文件系统中,而把元数据放在关系数据库中。

数据库支持命令空间,0.90的hive也支持命名空间,提供了create database dbname, use dbname以及drop database dbname这样的语句。

托管表和外部表

这两种表的区别表现在load和drop命令的语义上。

加载托管表时,Hive把数据移动到仓库目录,例如;

create table managed_table(dummy string);
load data inpath '/user/tom/data.txt' into table managed_table;

把文件从hdf://user/tom/data.txt 移动到hive的数据仓库目录managed_table表的目录,即hdfs://user/hive/warehouse/managed_table。

如果随后要删除一个表格,可以用

drop table managed_table;

它的表(包括数据和元数据)会一起被删除,这就是hive所谓的”数据托管的含义“。
而对于外部表而言,这两个操作结果就不一样了,用户来控制数据的创建和删除。外部数据的位置要在创建表格的时候说明:

create external table external_table(dummy string)
location '/user/tom/external_table';
load data inpath '/user/tom/data.txt' into table external_table;

使用external关键字之后,hive知道数据并不由自己管理,因此不会把数据移动到自己的仓库目录。丢弃外部表时,Hive不会碰数据,仅删除元数据。

经验法则:所有的数据都在hive中完成,使用托管表,如果使用Hive和其他工具共同处理一个数据集,应该使用外部表。普遍的做法是把存放在hdfs(由其他进程创建)的初始数据集用作外部表,然后使用hive的变换功能把数据移动到托管的hive表,可以使用hive导出数据供其他应用程序使用。

j、分区和桶

hive把表组织成分区(partition),根据分区列(partition column,如日期)对表进行粗略划分的机制。使用分区可以加快数据分片(slice)的查询速度。分区可以进一步划分为桶(bucket)。它会为数据提供额外的结构以获得更搞笑的查询处理。例如,通过根据用户ID来划分桶,我们可以在所有用户集合的随机样本上快速计算基于用户的查询。

使用分区并不会影响大范围查询的执行,我们依然可以查询跨多个分区的整个数据集合。

对于假想的日志文件,在根据日期对日志进行分区外,还可以能根据国家对每个分区进行子分区(subpartition),以加速根据地理位置进行查询。分区在创建表格的时候用partitioned by子句定义,该子句需要定义列的列表。我们可能要把表记录定义为由时间戳和日志行构成:

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='2010-01-01', country='GB');

在文件系统级别,分区只是表示目录下嵌套的子目录。把更多文件加载到日志表以后,目录结构可能像下面这样:

/user/hive/warehouse/logs/dt=2010-01-01/country=GB/file1
                                                                                  /file2
                                                               /country=US/file3
/user/hive/warehouse/logs/dt=2010-01-02/country=GB/file4
                                                              /country=US/file5
                                                                                 /file6

可以使用show partitions 表名  命令查询表中有哪些分区:

hive> show partitions logs;
dt=2010-01-01/country=GB
dt=2010-01-01/country=US
dt=2010-01-02/country=GB
dt=2010-01-02/country=US

注意:partitioned by 子句中的列定义是表中正式的列,称为“分区列”(partition column)。但是数据文件并不包含这些列的值,因为它们源于目录名。
实际使用的过程中可以以普通方式使用分区列。Hive会对输入进行修剪,从而只扫描相关分区。例如:

select ts, dt, line
from logs
where country='GB';

将只扫描file1、file2、file4。还要注意,这个查询也返回dt分区列的值。这个值是hive从目录名中读取的,因为他们在数据文件中并不存在。
桶:

把表(或分区)组织成桶(bucket)有两个理由。第一理由是获得更高效的查询处理效率,第二个理由是取样更高效。

使用clustered by子句来指定划分桶所在的列和要划分为桶的个数:

create table bucketed_users (id int, name string)
clustered by (id) into 4 buckets;

可以使用HiveQL对两个划分了桶的表进行连接。

桶中的数据可以根据一个或者多个列另外进行排序,所以这样对每个桶的连接就编程了高效的合并排序,因此可以进一步提升map端连接的效率。以下语法说明一个连接使其使用排序桶。

create table bucketed_users(id int, name string)
clustered by (id) sorted by (id asc) into 4 buckets;

有两种方式将表中的数据划分成桶:一是将Hive外的数据加载到划分成桶的表中,二是针对已有的表可以用Hive来划分桶。
建议用hive来划分桶,以为hive不检查数据文件中的桶是否和表定义中的桶一致。

有个没有划分桶的表格:

hive> select * from user;
OK
0    Nat
2    Joe
3    Kay
4    Ann
Time taken: 2.178 seconds

要将桶内填充成员,需要将hive.enforce.bucketing的属性设置为true。
这样hive就知道使用表定义中生命的变量来创建桶。然后使用insert命令创建即可:

hive> insert overwrite table bucketed_users 
    > select * from user;

物理上每个桶就是表(或分区)里的一个文件。但是桶n是按照字典排列的第n个文件。事实上,桶对应于MapReduce的输出文件分区,一个作业产生的桶(输出文件)和reduce任务个数相等。从下面执行的MapReduce程序中可以看出:

Total MapReduce jobs = 1
Launching Job 1 out of 1
Number of reduce tasks determined at compile time: 4
In order to change the average load for a reducer (in bytes):
  set hive.exec.reducers.bytes.per.reducer=<number>
In order to limit the maximum number of reducers:
  set hive.exec.reducers.max=<number>
In order to set a constant number of reducers:
  set mapred.reduce.tasks=<number>
Starting Job = job_201306210458_0022, Tracking URL = http://master:50030/jobdetails.jsp?jobid=job_201306210458_0022
Kill Command = /opt/cloudera/parcels/CDH-4.3.0-1.cdh4.3.0.p0.22/lib/hadoop/bin/hadoop job  -kill job_201306210458_0022
Hadoop job information for Stage-1: number of mappers: 1; number of reducers: 4

查看bucketed_users表的布局可以得到

hive> dfs -ls /user/hive/warehouse/bucketed_users; 
Found 4 items
-rw-r--r--   2 admin supergroup         12 2013-06-22 22:14 /user/hive/warehouse/bucketed_users/000000_0
-rw-r--r--   2 admin supergroup          0 2013-06-22 22:14 /user/hive/warehouse/bucketed_users/000001_0
-rw-r--r--   2 admin supergroup          6 2013-06-22 22:14 /user/hive/warehouse/bucketed_users/000002_0
-rw-r--r--   2 admin supergroup          6 2013-06-22 22:14 /user/hive/warehouse/bucketed_users/000003_0

4个新建的文件
具体桶内的数据如下所示:

hive> dfs -cat /user/hive/warehouse/bucketed_users/*0_0;
0Nat
4Ann
hive> dfs -cat /user/hive/warehouse/bucketed_users/*1_0;
hive> dfs -cat /user/hive/warehouse/bucketed_users/*2_0;
2Joe
hive> dfs -cat /user/hive/warehouse/bucketed_users/*3_0;
3Kay

使用tablesample子句对表进行取样,我们可以获得相同的结果。这个子句会把查询限定在表的一部分桶内,而不是整个表:

hive> select * from bucketed_users                      
    > tablesample(bucket 1 out of 4 on id);
...........
OK
0    Nat
4    Ann
Time taken: 7.289 seconds

1/4 第一个桶,下面的查询会会返回1/2桶:

hive> select * from bucketed_users         
    > tablesample(bucket 1 out of 2 on ;
.............
OK
0    Nat
4    Ann
2    Joe
Time taken: 10.367 seconds

当然,可以用其他比例对若干个桶进行取样,因为取样并不是一个精确的操作,因此这个比例一定是桶的整数倍。
用此取样分桶表是非常高效的操作,如果使用rand()函数对没有划分成桶的表进行取样,及时只需要读取很小的一部分样本,也要输入整个数据集。所以rand的特点是扫描次数多,效率低,用下面查询结果耗时和上面对比可以得出。

hive> select * from bucketed_users         
    > tablesample(bucket 1 out of 4 on rand());
......................
OK
Time taken: 10.379 seconds

k、存储格式
最简单的是文本格式,同时支持面向行的和面向列的二进制格式。

分隔符的问题,create table ……语句等价于下面的语句:

create table
row format delimited
fields terminated by '\001'
collection iterms terminated by '\002'
map keys terminated by '\003'
lines terminated by '\n' stored as textfile;

注意,可以使用八进制表示分隔符,例如001表示Control-A。
支持顺序文件Sequence File和RCFile,按列记录文件。

在Hvie中可以使用下面的句子还启用面向列的存储:

create table ...........
row format serde 'org.apache.hadoop.hive.seder2.columnar.ColumnarSerDe' 
store as RCFile;

示例:利用正则表达式从一个文本文件中读取定长的观测站数据

create table station (usaf string, wban, name string)
row format serde 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe'
with serdeproperties ( "input.regex"="(\\d{6}) (\\d{5}) (.{29}) .*");

SerDe要设置相应的属性值,在这里要设置RegexSerDe特有的input.regex属性。
用load data向表中输入数据:

load data local inpath “input/ncdc/metadata/stations-fixed-with.txt” into table station;

加载操作并不适用表的SerDe。

从表中检索数据时,用简单的查询所示,反序列化会调用SerDe解析这个字段:

hive> select * from stations limit 4;
10000 99999 BOGUS NORWAY
010003 99999 BOGUS NORWAY
010010 99999 JAN      MAYEN
010013 99999 ROST

l、导入数据

如果想把数据从关系数据库直接导入hive,请参考Sqoop。
insert overwrite table

insert overwrite table target
select col1, col2
from source;

对于分区的表,可以使用partition子句来指明

insert overwrite table target
partition (dt='2010-01-01')
select col1, col2
from source;

使用overwrite会替换掉目标,而如果要向已经填充了内容的表添加记录,可以使用不带overwrite 关键字的load data操作。
从hive 0.6.0开始,可以在select 语句中通过使用分区值来动态指明分区:

insert overwrite table target
partition dt
select col1, col2, dt
from source;

这种方法称为动态分区插入法,这一特性默认是关闭的,可以通过命令set 命令查看开启,将hive.exec.dynamic.partition=true。
当前hive不支持使用insert into values (…….)的形式。

多表插入:

在hive中,可以把insert语句倒过来,把from语句放在最前面,查询的效果是一样的:

from source 
insert overwrite table target
select col1, col2;

在一个表查询中,可以使用多个insert的语句,只要扫描一遍表,就可以生成多个不相交的输出。

FROM records2
INSERT OVERWRITE TABLE stations_by_year
  SELECT year, COUNT(DISTINCT station)
  GROUP BY year 
INSERT OVERWRITE TABLE records_by_year
  SELECT year, COUNT(1)
  GROUP BY year
INSERT OVERWRITE TABLE good_records_by_year
  SELECT year, COUNT(1)
  WHERE temperature != 9999
    AND (quality = 0 OR quality = 1 OR quality = 4 OR quality = 5 OR quality = 9)
  GROUP BY year;

这里有一个源表,三个目标表。
create table ……as select…….

create table target
as
select col1, col2
from source;

m、表的修改
重命名表

alter table source rename to target;

添加新的列

alter table target add columns (col3 string);

n、表的丢弃
drop table删除表的元数据和数据

也可以仅仅删除数据文件,保留表结构,默认为空表

hive > dfs -rmr /user/hive/warehouse/my_table;

这时候,可以使用like关键字创建一个与第一个表模式相同的新表:

create table new_table like existing_table;

o、查询数据

排序和聚集

可以用order by子句对数据进行全局排序,但是它只是用一个reducer完成的。在多数情况下不需要全局排序的情况下,可以使用sort by局部排序,为每一个reduce产生一个排序文件。有些时候需要控制某个特定行应该到哪个reducer,通常是为了后续的聚集操作,这就是hive的 distribute by所做的事情,下面的例子根据年份和气温对气象数据进行排序,以确保所有年份所在的行,最终都在一个reduce分区中。

hive> from records2
      >select year, temperature
      > distribute by year
      > sort by year asc, temperature desc;
1949  111
1949  78
1950  22
1950  0
1950  11

如果sort by 和distribute by中所用到的列相同,可以缩写为cluster by一遍同时制定两者相同的列。
使用Hadoop Streaming 、transform 、map、reduce子句这样的方法,便可以在hive中调用外部脚本。

p、连接

同mapreduce相比,hive的好处是简化了常用操作。

内连接:

hive> SELECT * FROM sales;
Joe    2
Hank   4
Ali    0
Eve    3
Hank   2
hive> SELECT * FROM things;
2    Tie
4    Coat
3    Hat
1    Scarf

sales:人名及所购商品的id,sales:上平id及名称

hive> SELECT sales.*, things.*
    > FROM sales JOIN things ON (sales.id = things.id);
Joe     2    2    Tie
Hank    2    2    Tie
Eve     3    3    Hat
Hank    4    4    Coat

hive只支持等值连接,条件是两个表的id必须相等。
与数据库不同,hive不支持where子句,且只允许在from子句中出现一个表。

用explain 关键字可以查询连接的过程中使用多少个MapReduce,可以用explain extended查看更详细的信息。

EXPLAIN
SELECT sales.*, things.*
FROM sales JOIN things ON (sales.id = things.id);

外连接:
使用left outer join,查询会返回左侧表(sales)中的每一个数据行,及时这些行与这各表索要连接的表(things)中的任何数据对应。

hive> SELECT sales.*, things.*
    > FROM sales LEFT OUTER JOIN things ON (sales.id = things.id);
Ali     0    NULL NULL
Joe     2    2    Tie
Hank    2    2    Tie
Eve     3    3    Hat
Hank    4    4    Coat

hive也支持right outer join右外连接

hive> SELECT sales.*, things.*
    > FROM sales RIGHT OUTER JOIN things ON (sales.id = things.id);
NULL    NULL 1    Scarf
Joe     2    2    Tie
Hank    2    2    Tie
Eve     3    3    Hat
Hank    4    4    Coat

全外连接,full outer join

hive> SELECT sales.*, things.*
    > FROM sales FULL OUTER JOIN things ON (sales.id = things.id);
Ali     0    NULL NULL
NULL    NULL 1    Scarf
Joe     2    2    Tie
Hank    2    2    Tie
Eve     3    3    Hat
Hank    4    4    Coat

半连接:
下面的in 子句能够查找things表中在sales表中出现过的所有商品:

select *
from things
where things.id in (select id from sales);

但是hive不支持in子句查询,所以要对其进行改写,改写后如下:

hive> select * from things;
OK
2    Tie
4    Coat
3    Hat
1    Scarf
Time taken: 0.282 seconds
hive> select * from sales; 
OK
Joe    2
Hank    4
Ali    0
Eve    3
Hank    2
Time taken: 0.227 seconds

对上述表操作,左半连接,只要左半自身。

hive> select *
    > from things left semi join sales on (sales.id=things.id);
..................
OK
2    Tie
3    Hat
4    Coat
Time taken: 14.528 seconds

map连接:
如果要指定使用map连接,需要在sql中使用C语言风格的注释,从而给出提示:

select /* mapjoin(things) */ sales.*, things.*
from sales join things on (sales.id=things.id);

执行这个查询不适用reducer,只在所有输入上进行聚集,使用下面的语法启用优化选项:set hive.optimize.bucketmapjoin=true;
q、子查询

hive对子查询支持有限,只允许出现在select 语句的from子句中。

下面的语句可以查出每年每个气象站最高气温的均值:

SELECT station, year, AVG(max_temperature)
FROM (
  SELECT station, year, MAX(temperature) AS max_temperature
  FROM records2
  WHERE temperature != 9999
    AND (quality = 0 OR quality = 1 OR quality = 4 OR quality = 
  GROUP BY station, year
) mt
GROUP BY station, year;

内层查询查询出每个气象站的最高气温,外层查询使用AVG聚集函数计算这些最高读数的均值。

你可能感兴趣的:(cdh)