我们从这里开始?
what is hive?

Hive最初是应Facebook每天产生的海量新兴社会网络数据进行管理和机器学习的需求而产生和发展的。那么,到底什么是Hive,我们先看看Hive官网Wiki是如何介绍Hive的:
https://cwiki.apache.org/confluence/display/Hive/hive

英文定义:

The Apache Hive data warehouse software facilitates querying and managing large datasets residing in distributed storage. Built on top of Apache HadoopTM, it provides:

(1)、Tools to enable easy data extract/transform/load (ETL)
(2)、A mechanism to impose structure on a variety of data formats
(3)、Access to files stored either directly in Apache HDFSTM or in other data storage systems such as Apache HBaseTM
(4)、Query execution via MapReduce

中文翻译:

Apache Hive数据仓库软件提供对存储在分布式中的大型数据集的查询和管理,它本身是建立在Apache Hadoop之上,主要提供以下功能:
(1)它提供了一系列的工具,可用来对数据进行提取/转化/加载(ETL);
(2)是一种可以存储、查询和分析存储在HDFS(或者HBase)中的大规模数据的机制;
(3)查询是通过MapReduce来完成的(并不是所有的查询都需要MapReduce来完成,比如select * from XXX就不需要;)
(4)在Hive0.11对类似select a,b from XXX的查询通过配置也可以不通过MapReduce来完成

总结为一句话:hive是基于hadoop的数据仓库。


那么,我们如何来分析和管理那些数据呢?
  Hive定义了一种类似SQL的查询语言,被称为HQL,对于熟悉SQL的用户可以直接利用Hive来查询数据。同时,这个语言也允许熟悉 MapReduce 开发者们开发自定义的mappers和reducers来处理内建的mappers和reducers无法完成的复杂的分析工作。
Hive可以允许用户编写自己定义的函数UDF,来在查询中使用。
Hive中有3种UDF:
User Defined Functions(UDF)用户定义函数
User Defined Aggregation Functions(UDAF)用户定义聚合函数
User Defined Table Generating Functions(UDTF)用户自定义表生成函数

今天,Hive已经是一个成功的Apache项目,很多组织把它用作一个通用的、可伸缩的数据处理平台。
  当然,Hive和传统的关系型数据库有很大的区别,Hive将外部的任务解析成一个MapReduce可执行计划,而启动MapReduce是一个高延迟的一件事,每次提交任务和执行任务都需要消耗很多时间,这也就决定Hive只能处理一些高延迟的应用(如果你想处理低延迟的应用,你可以去考虑一下Hbase)。同时,由于设计的目标不一样,Hive目前还不支持事务;不能对表数据进行修改(不能更新、删除、插入;只能通过文件追加数据、重新导入数据);不能对列建立索引(但是Hive支持索引的建立,但是不能提高Hive的查询速度。如果你想提高Hive的查询速度,请学习Hive的分区、桶的应用)。

同时补充一下hive与hbase的联系与区别:
共同点:
1.hbase与hive都是架构在Hadoop之上的。都是用hadoop作为底层存储

区别:

1.Hive是建立在Hadoop之上为了减少MapReduce jobs编写工作的批处理系统,HBase是为了支持弥补Hadoop对实时操作的缺陷的项目 。
2.想象你在操作RMDB数据库,如果是全表扫描,就用Hive+Hadoop,如果是索引访问,就用HBase+Hadoop 。
3.Hive query就是MapReduce jobs可以从5分钟到数小时不止,HBase是非常高效的,肯定比Hive高效的多。
4.Hive本身不存储和计算数据,它完全依赖于HDFS和MapReduce,Hive中的表纯逻辑。
5.hive借用hadoop的MapReduce来完成一些hive中的命令的执行
6.hbase是物理表,不是逻辑表,提供一个超大的内存hash表,搜索引擎通过它来存储索引,方便查询操作。
7.hbase是列存储。
8.hdfs作为底层存储,hdfs是存放文件的系统,而Hbase负责组织文件。
9.hive需要用到hdfs存储文件,需要用到MapReduce计算框架

HIVE基本操作:

本地运行
set hive.exec.mode.local.auto=true;

创建表:
hive> CREATE TABLE pokes (foo INT, bar STRING); 
      Creates a table called pokes with two columns, the first being an integer and the other a string

创建一个新表,结构与其他一样
hive> create table new_table like records;

创建分区表:
hive> create table logs(ts bigint,line string) partitioned by (dt String,country String);

加载分区表数据:
hive> load data local inpath '/hive/hadoop/input/hive/partitions/file1' into table logs partition (dt='2011-01-01',country='GB');

展示表中有多少分区:
hive> show partitions logs;

展示所有表:
hive> SHOW TABLES;
      lists all the tables
hive> SHOW TABLES '.*s';

lists all the table that end with 's'. The pattern matching follows Java regular
expressions. Check out this link for documentation 

显示表的结构信息
hive> DESCRIBE invites;
      DESC TABLE_NAME
      shows the list of columns

更新表的名称:
hive> ALTER TABLE source RENAME TO target;

添加新一列
hive> ALTER TABLE invites ADD COLUMNS (new_col2 INT COMMENT 'a comment');

删除表:
hive> DROP TABLE records;
删除表中数据,但要保持表的结构定义
hive> dfs -rmr /user/hive/warehouse/records;

从本地文件加载数据:
hive> LOAD DATA LOCAL INPATH '/hive/hadoop/input/ncdc/micro-tab/sample.txt' OVERWRITE INTO TABLE records;

显示所有函数:
hive> show functions;

查看函数用法:
hive> describe function substr;

查看数组、map、结构
hive> select col1[0],col2['b'],col3.c from complex;


内连接:
hive> SELECT sales.*, things.* FROM sales JOIN things ON (sales.id = things.id);

查看hive为某个查询使用多少个MapReduce作业
hive> Explain SELECT sales.*, things.* FROM sales JOIN things ON (sales.id = things.id);

外连接:
hive> SELECT sales.*, things.* FROM sales LEFT OUTER JOIN things ON (sales.id = things.id);
hive> SELECT sales.*, things.* FROM sales RIGHT OUTER JOIN things ON (sales.id = things.id);
hive> SELECT sales.*, things.* FROM sales FULL OUTER JOIN things ON (sales.id = things.id);

in查询:Hive不支持,但可以使用LEFT SEMI JOIN
hive> SELECT * FROM things LEFT SEMI JOIN sales ON (sales.id = things.id);


Map连接:Hive可以把较小的表放入每个Mapper的内存来执行连接操作
hive> SELECT /*+ MAPJOIN(things) */ sales.*, things.* FROM sales JOIN things ON (sales.id = things.id);

INSERT OVERWRITE TABLE ..SELECT:新表预先存在
hive> 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:新表表预先不存在
hive> CREATE TABLE target AS SELECT col1,col2 FROM source;不只是复制表结构,数据也来了

创建视图:
hive> CREATE VIEW valid_records AS SELECT * FROM records2 WHERE temperature !=9999;

查看视图详细信息:
hive> DESCRIBE EXTENDED valid_records;


HIVE的工作原理和解析过程:

1、组件:

元存储(Metastore )-存储“系统目录以及关于表、列、分区等的元数据”的组件。
驱动(Driver )- 控制 HiveQL 生命周期的组件,当 HiveQL 查询穿过 Hive时。该驱动管理着会话句柄以及任何会话的统计。
查询编译器(Query Compiler) - 是一个组件,将HiveQL编译成有向无环图(directed acyclic graph, DAG)形式的map/reduce任务。
执行引擎 Execution Engine - 是一个组件,依相依性顺序(dependency order)执行由编译器产生的任务。
Hive 服务器 HiveServer - 一个提供“健壮的接口(thrift interface )、JDBC/ODBC 服务器以及提供一种整合 Hive 和其它应用的”组件。
客户端组件 -类似命令行接口CLI(Command Line Interface), web UI 以及JDBC/ODBC驱动。包含了正反序列化(SerDe)以及对象观察器(ObjectInspector)接口的可扩展接口,类似于前述用户定义函数 UDF (User Defined Function)以及用户定义聚合函数UDAF(User Defined AggregateFunction)接口,允许用户定义自己的列函数。


2、执行的过程:

HiveQL通过CLI/web UI或者thrift 、 odbc 或 jdbc接口的外部接口提交,经过complier编译器,运用Metastore中的云数据进行类型检测和语法分析,生成一个逻辑方案(logicalplan),然后通过简单的优化处理,产生一个以有向无环图DAG数据结构形式展现的map-reduce任务


3、元存储(Metastore)

存储列所有关于表、表的分区、模式、列及其类型、表地址等的表的元数据,可以通过thrift接口查询得到,由于需要快速的提供到编译器中,所以使用RDBMS

4、查询编译器(query complier)

用云存储中的元数据来生成执行计划,步骤如下:
1).解析(parse)-anlr解析其生成语法树AST(hibernate也是这个):将HQL转化为抽象语法树AST
2).类型检查和语法分析(type checking and semantic analysis):将抽象语法树转换此查询块(query block tree),并将查询块转换成逻辑查询计划(logic plan Generator);
3).优化(optimization):重写查询计划(logical optimizer)-->将逻辑查询计划转成物理计划(physical plan generator)-->选择最佳的join策略(physical optimizer)

     parse   sa    lpg       lo        ppg          po
hql------->AST------>QB----->OP TREE------->OP TREE------->task tree------->task tree

首先进行hql语句解析,构造一颗AST树,从AST树中得到QueryBlock,再将QB转为对应的操作符,生成逻辑查询计划,对逻辑查询计划进行优化(谓词下推),生成物理查询计划,对物理查询计划进行优化(MapJoinResolver/SkewJoinResolver/CommonJoinResolver),得到最后的执行计划。

MapJoinResolver:将小表的MR结果放入HashTableFiles-->DistributedCache,大表从分布式缓存中取得数据进行join;当hash数据较大时,分布式缓存查询效率降低,同时大表的Map都>在等待hash files;所以对其进行列优化处理小表的结果放到DC中进行压缩和更新,大表遍历时从DC中取出tar包>,然后解压读取本地的hash files


Hive完成列以下转换,作为优化阶段的一部分:
1).列剪辑(column pruning):查询处理中唯一需要的列确实从行中投射出去
2).谓语下推(Predicate pushdown):将只于一张表有关的过滤操作下推至TableScanOperator之后,
3).分区剪辑(Partition pruning):过滤掉分区上不符合条件的字段
4).Map 端的连接(Map side joins):当join的表很小时,在map段先复制它然后再进行join,格式如下:
 SELECT /*+ MAPJOIN(t2) */ t1.c1, t2.c1 FROM t1 JOIN t2 ON(t1.c2 = t2.c2);
 由hive.mapjoin.size.key以及hive.mapjoin.cache.numrows控制“任何时间保存在内存中的”表中行的数量,以及提供给系统联合键的大小
5).连接再排序(Join reordering):把较小的表保存在内存中,较大的表进行遍历操作,保证系统内存不溢出

5、MapJoin的进一步优化

1).数据再分区以把控GROUPBY形成的非对称(skews):用两个MapReduce来做,第一个阶段将数据随机分发(或者按DISTINCT列分发在DISTINCT聚合的情况下)至reducers,并且计算聚合值;然后这些聚合结果按照GROUP BY 列分发给在第二个Reducer;

     set hive.groupby.skewindata= true ;
    SELECT t1.c1, sum(t1.c2)
    FROM t1
    GROUP BY t1.c1;

2).mappers中的基于哈希的局部聚合:相当于combiner,在map端内存中进行聚合,然后发送给reducers,参数hive.map.aggr.hash.percentmemory说明了mapper 内存中可用于把控哈希表那部分的数量。如0.5能确保哈希表大小一旦超过用于mapper的最大内存的一半,存储在那儿的部分聚合就被发送到reducers了。hive.map.aggr.hash.min.reduction参数同样也用来控制用于mappers的内存数量



6、执行引擎(execution engine):

按照任务的依赖关系序列来执行


7.其它优化:

1).Left Semi Join实现in/exists子查询:
SELECT A.* FROM A LEFT SEMI JOIN B ON(A.KEY = B.KEY AND B.KEY > 100);
等同于SELECT A.* FROM A WHERE A.KEY IN(SELECT B.KEY FORM B WHERE B.KEY > 100);
作用:map端用group by减少流入reduce端的数据量

2).Bucket Map Join:
set hive.optimize.bucketmapjoin = true;
和Map join一起工作;
所有join的表都做列分桶,同时大表桶的数量是小表桶的整数倍;
做bucket的列必须是join的列;

SELECT /*+MAPJOIN(a,c)*/ a.*, b.*, c.*
a join b on a.key = b.key
join c on a.key=c.key;
在现实的生产环境中,会有成百上千个buckets;

3).Skew join:
join时数据倾斜,造成Reduce端OOM
set hive.optimize.skewjoin = true;
set hive.skewjoin.key = 阀值;
当JOIN得到的map超过阀值时,将内存中的a-k1/b-k1数据分别存入hdfs中,然后遍历完后再对hdfs上的两块数据做Map Join,和其它key一起组成最后结果

HIVE数据导入

Hive的几种常见的数据导入方式
这里介绍四种:
(1)、从本地文件系统中导入数据到Hive表;
(2)、从HDFS上导入数据到Hive表;
(3)、从别的表中查询出相应的数据并导入到Hive表中;
(4)、在创建表的时候通过从别的表中查询出相应的记录并插入到所创建的表中。


一、从本地文件系统中导入数据到Hive表

先在Hive里面创建好表,如下:
hive> create table bsr
    > (id int, name string,
    > age int, tel string)
    > ROW FORMAT DELIMITED
    > FIELDS TERMINATED BY '\t'
    > STORED AS TEXTFILE;
OK
Time taken: 2.832 seconds
 

这个表很简单,只有四个字段,具体含义我就不解释了。本地文件系统里面有个/hive/bsr/bsr.txt文件,内容如下:
[bsr@master ~]$ cat bsr.txt
1       bsr     25      13188888888888
2       test    30      13888888888888
3       zs      34      899314121
 

bsr.txt文件中的数据列之间是使用\t分割的,可以通过下面的语句将这个文件里面的数据导入到bsr表里面,操作如下:
hive> load data local inpath 'bsr.txt' into table bsr;
Copying data from file:/hive/bsr/bsr.txt
Copying file: file:/hive/bsr/bsr.txt
Loading data to table default.bsr
Table default.bsr stats:
[num_partitions: 0, num_files: 1, num_rows: 0, total_size: 67]
OK
Time taken: 5.967 seconds
 

这样就将bsr.txt里面的内容导入到bsr表里面去了,可以到bsr表的数据目录下查看,如下命令:

hive> dfs -ls /user/hive/warehouse/bsr ;
Found 1 items
-rw-r--r--3 bsr supergroup 67 2014-02-19 18:23 /hive/warehouse/bsr/bsr.txt
 

需要注意的是:

和我们熟悉的关系型数据库不一样,Hive现在还不支持在insert语句里面直接给出一组记录的文字形式,也就是说,Hive并不支持INSERT INTO …. VALUES形式的语句。

二、HDFS上导入数据到Hive表

从本地文件系统中将数据导入到Hive表的过程中,其实是先将数据临时复制到HDFS的一个目录下(典型的情况是复制到上传用户的HDFS的目录下比如/hive/bsr/),然后再将数据从那个临时目录下移动(注意,这里说的是移动,不是复制!)到对应的Hive表的数据目录里面。既然如此,那么Hive肯定支持将数据直接从HDFS上的一个目录移动到相应Hive表的数据目录下,假设有下面这个文件/hive/bsr/add.txt,具体的操作如下:
hadoop fs -cat /hive/bsr/add.txt
5       bsr1    23      131212121212
6       bsr2    24      134535353535
7       bsr3    25      132453535353
8       bsr4    26      154243434355


上面是需要插入数据的内容,这个文件是存放在HDFS上/hive/bsr目录(和一中提到的不同,一中提到的文件是存放在本地文件系统上)里面,我们可以通过下面的命令将这个文件里面的内容导入到Hive表中,具体操作如下:

hive> load data inpath '/hive/bsr/add.txt' into table bsr;
Loading data to table default.bsr
Table default.bsr stats:
[num_partitions: 0, num_files: 2, num_rows: 0, total_size: 215]
OK
Time taken: 0.47 seconds

hive> select * from bsr;
OK
5       bsr1    23      131212121212
6       bsr2    24      134535353535
7       bsr3    25      132453535353
8       bsr4    26      154243434355
1       bsr     25      13188888888888
2       test    30      13888888888888
3       zs      34      899314121
Time taken: 0.096 seconds, Fetched: 7 row(s)


从上面的执行结果我们可以看到,数据的确导入到bsr表中了!请注意load data inpath ‘/hive/bsr/add.txt’ into table bsr;里面是没有local这个单词的,这个是和一中的区别。

三、从别的表中查询出相应的数据并导入到Hive表中

假设Hive中有test表,其建表语句如下所示:

hive> create table test(
    > id int, name string
    > ,tel string)
    > partitioned by
    > (age int)
    > ROW FORMAT DELIMITED
    > FIELDS TERMINATED BY '\t'
    > STORED AS TEXTFILE;
OK
Time taken: 0.261 seconds


大体和bsr表的建表语句类似,只不过test表里面用age作为了分区字段。对于分区,这里在做解释一下:
分区:在Hive中,表的每一个分区对应表下的相应目录,所有分区的数据都是存储在对应的目录中。比如bsr表有dt和city两个分区,则对应dt=20131218,city=BJ对应表的目录为/user/hive/warehouse/dt=20131218/city=BJ,所有属于这个分区的数据都存放在这个目录中。

下面语句就是将bsr表中的查询结果并插入到test表中:
hive> insert into table test
    > partition (age='25')
    > select id, name, tel
    > from bsr;
#####################################################################
           这里输出了一堆Mapreduce任务信息,这里省略
#####################################################################
Total MapReduce CPU Time Spent: 1 seconds 310 msec
OK
Time taken: 19.125 seconds

hive> select * from test;
OK
5       bsr1    131212121212    25
6       bsr2    134535353535    25
7       bsr3    132453535353    25
8       bsr4    154243434355    25
1       bsr     13188888888888  25
2       test    13888888888888  25
3       zs      899314121       25
Time taken: 0.126 seconds, Fetched: 7 row(s)
 
这里做一下说明:
我们知道我们传统数据块的形式insert into table values(字段1,字段2),这种形式hive是不支持的。

通过上面的输出,我们可以看到从bsr表中查询出来的东西已经成功插入到test表中去了!如果目标表(test)中不存在分区字段,可以去掉partition (age=’25′)语句。当然,我们也可以在select语句里面通过使用分区值来动态指明分区:
hive> set hive.exec.dynamic.partition.mode=nonstrict;
hive> insert into table test
    > partition (age)
    > select id, name,
    > tel, age
    > from bsr;
#####################################################################
           这里输出了一堆Mapreduce任务信息,这里省略
#####################################################################
Total MapReduce CPU Time Spent: 1 seconds 510 msec
OK
Time taken: 17.712 seconds


hive> select * from test;
OK
5       bsr1    131212121212    23
6       bsr2    134535353535    24
7       bsr3    132453535353    25
1       bsr     13188888888888  25
8       bsr4    154243434355    26
2       test    13888888888888  30
3       zs      899314121       34
Time taken: 0.399 seconds, Fetched: 7 row(s)
 

这种方法叫做动态分区插入,但是Hive中默认是关闭的,所以在使用前需要先把hive.exec.dynamic.partition.mode设置为nonstrict。当然,Hive也支持insert overwrite方式来插入数据,从字面我们就可以看出,overwrite是覆盖的意思,是的,执行完这条语句的时候,相应数据目录下的数据将会被覆盖!而insert into则不会,注意两者之间的区别。例子如下:

hive> insert overwrite table test
    > PARTITION (age)
    > select id, name, tel, age
    > from bsr;
 

更可喜的是,Hive还支持多表插入,什么意思呢?在Hive中,我们可以把insert语句倒过来,把from放在最前面,它的执行效果和放在后面是一样的,如下:
hive> show create table test3;
OK
CREATE  TABLE test3(
  id int,
  name string)
Time taken: 0.277 seconds, Fetched: 18 row(s)

hive> from bsr
    > insert into table test
    > partition(age)
    > select id, name, tel, age
    > insert into table test3
    > select id, name
    > where age>25;

hive> select * from test3;
OK
8       bsr4
2       test
3       zs
Time taken: 4.308 seconds, Fetched: 3 row(s)
 

可以在同一个查询中使用多个insert子句,这样的好处是我们只需要扫描一遍源表就可以生成多个不相交的输出。这个很酷吧!

四、在创建表的时候通过从别的表中查询出相应的记录并插入到所创建的表中

在实际情况中,表的输出结果可能太多,不适于显示在控制台上,这时候,将Hive的查询输出结果直接存在一个新的表中是非常方便的,我们称这种情况为CTAS(create table .. as select)如下:

hive> create table test4
    > as
    > select id, name, tel
    > from bsr;

hive> select * from test4;
OK
5       bsr1    131212121212
6       bsr2    134535353535
7       bsr3    132453535353
8       bsr4    154243434355
1       bsr     13188888888888
2       test    13888888888888
3       zs      899314121
Time taken: 0.089 seconds, Fetched: 7 row(s)
 

数据就插入到test4表中去了,CTAS操作是原子的,因此如果select查询由于某种原因而失败,新表是不会创建的!

Hive数据导出三种方式 

今天我们再谈谈Hive中的三种不同的数据导出方式。
根据导出的地方不一样,将这些方式分为三种:
(1)、导出到本地文件系统;
(2)、导出到HDFS中;
(3)、导出到Hive的另一个表中。
为了避免单纯的文字,我将一步一步地用命令进行说明。


一、导出到本地文件系统

      
    hive> insert overwrite local directory '/home/bsr/bsr'
        > select * from bsr;



这条HQL的执行需要启用Mapreduce完成,运行完这条语句之后,将会在本地文件系统的/home/bsr/bsr目录下生成文件,这个文件是Reduce产生的结果(这里生成的文件名是000000_0),我们可以看看这个文件的内容:

    [bsr@master ~/bsr]$ vim 000000_0
    5^Absr1^A23^A131212121212
    6^Absr2^A24^A134535353535
    7^Absr3^A25^A132453535353
    8^Absr4^A26^A154243434355
    1^Absr^A25^A13188888888888
    2^Atest^A30^A13888888888888
    3^Azs^A34^A899314121



可以看出,这就是bsr表中的所有数据。数据中的列与列之间的分隔符是^A(ascii码是\00001)。

和导入数据到Hive不一样,不能用insert into来将数据导出:

      
    hive> insert into local directory '/home/bsr/bsr'
        > select * from bsr;
    NoViableAltException(79@[])
            at org.apache.hadoop.hive.ql.parse.HiveParser_SelectClauseParser.selectClause(HiveParser_SelectClauseParser.java:683)
            at org.apache.hadoop.hive.ql.parse.HiveParser.selectClause(HiveParser.java:30667)
            at org.apache.hadoop.hive.ql.parse.HiveParser.regular_body(HiveParser.java:28421)
            at org.apache.hadoop.hive.ql.parse.HiveParser.queryStatement(HiveParser.java:28306)
            at org.apache.hadoop.hive.ql.parse.HiveParser.queryStatementExpression(HiveParser.java:28100)
            at org.apache.hadoop.hive.ql.parse.HiveParser.execStatement(HiveParser.java:1213)
            at org.apache.hadoop.hive.ql.parse.HiveParser.statement(HiveParser.java:928)
            at org.apache.hadoop.hive.ql.parse.ParseDriver.parse(ParseDriver.java:190)
            at org.apache.hadoop.hive.ql.Driver.compile(Driver.java:418)
            at org.apache.hadoop.hive.ql.Driver.compile(Driver.java:337)
            at org.apache.hadoop.hive.ql.Driver.run(Driver.java:902)
            at org.apache.hadoop.hive.cli.CliDriver.processLocalCmd(CliDriver.java:259)
            at org.apache.hadoop.hive.cli.CliDriver.processCmd(CliDriver.java:216)
            at org.apache.hadoop.hive.cli.CliDriver.processLine(CliDriver.java:413)
            at org.apache.hadoop.hive.cli.CliDriver.run(CliDriver.java:756)
            at org.apache.hadoop.hive.cli.CliDriver.main(CliDriver.java:614)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
            at java.lang.reflect.Method.invoke(Method.java:597)
            at org.apache.hadoop.util.RunJar.main(RunJar.java:212)
    FAILED: ParseException line 1:12 missing TABLE at 'local' near 'local' in select clause
    line 1:18 cannot recognize input near 'directory' ''/home/bsr/bsr'' 'select' in select clause



二、导出到HDFS中
和导入数据到本地文件系统一样的简单,可以用下面的语句实现:

      
    hive> insert overwrite directory '/home/bsr/hdfs'
        > select * from bsr;


将会在HDFS的/home/bsr/hdfs目录下保存导出来的数据。注意,和导出文件到本地文件系统的HQL少一个local,数据的存放路径就不一样了。

三、导出到Hive的另一个表中

这也是Hive的数据导入方式,如下操作:

     
    hive> insert into table test
        > partition (age='25')
        > select id, name, tel
        > from bsr;
    #####################################################################
               这里输出了一堆Mapreduce任务信息,这里省略
    #####################################################################
    Total MapReduce CPU Time Spent: 1 seconds 310 msec
    OK
    Time taken: 19.125 seconds

    hive> select * from test;
    OK
    5       bsr1    131212121212    25
    6       bsr2    134535353535    25
    7       bsr3    132453535353    25
    8       bsr4    154243434355    25
    1       bsr     13188888888888  25
    2       test    13888888888888  25
    3       zs      899314121       25
    Time taken: 0.126 seconds, Fetched: 7 row(s)



细心的读者可能会问,怎么导入数据到文件中,数据的列之间为什么不是bsr表设定的列分隔符呢?其实在Hive 0.11.0版本之间,数据的导出是不能指定列之间的分隔符的,只能用默认的列分隔符,也就是上面的^A来分割,这样导出来的数据很不直观,看起来很不方便!
如果你用的Hive版本是0.11.0,那么你可以在导出数据的时候来指定列之间的分隔符。

下面详细介绍:


    在Hive0.11.0版本新引进了一个新的特性,也就是当用户将Hive查询结果输出到文件,用户可以指定列的分割符,而在之前的版本是不能指定列之间的分隔符,这样给我们带来了很大的不变,在Hive0.11.0之前版本我们一般是这样用的:

            hive> insert overwrite local directory '/home/bsr/Documents/result'
            hive> select * from test;

         
        保存的文件列之间是用^A(\x01)来分割

        196^A242^A3
        186^A302^A3
        22^A377^A1
        244^A51^A2

    

        注意,上面是为了显示方便,而将\x01写作^A,在实际的文本编辑器我们是看不到^A的,而是一个奇怪的符号。

        现在我们可以用Hive0.11.0版本新引进了一个新的特性,指定输出结果列之间的分隔符:

            hive> insert overwrite local directory '/home/bsr/Documents/result'
            hive> row format delimited
            hive> fields terminated by '\t'
            hive> select * from test;

        
        再次看出输出的结果

            196        242        3
            186        302        3
            22        377        1
            244        51        2

        

        结果好看多了。如果是map类型可以用下面语句来分割map的key和value

            hive> insert overwrite local directory './test-04' 
            hive> row format delimited 
            hive> FIELDS TERMINATED BY '\t'
            hive> COLLECTION ITEMS TERMINATED BY ','
            hive> MAP KEYS TERMINATED BY ':'
            hive> select * from src;




根据上面内容,我们来进一步操作:


    hive> insert overwrite local directory '/home/yangping.wu/local'
        > row format delimited
        > fields terminated by '\t'
        > select * from bsr;



    [bsr@master ~/local]$ vim 000000_0
    5       bsr1    23      131212121212
    6       bsr2    24      134535353535
    7       bsr3    25      132453535353
    8       bsr4    26      154243434355
    1       bsr     25      13188888888888
    2       test    30      13888888888888
    3       zs      34      899314121



其实,我们还可以用hive的-e和-f参数来导出数据。其中-e 表示后面直接接带双引号的sql语句;而-f是接一个文件,文件的内容为一个sql语句,如下:

      
    [bsr@master ~/local][        DISCUZ_CODE_26        ]nbsp; hive -e "select * from bsr" >> local/bsr.txt
    [bsr@master ~/local][        DISCUZ_CODE_26        ]nbsp; cat bsr.txt
    5       bsr1    23      131212121212
    6       bsr2    24      134535353535
    7       bsr3    25      132453535353
    8       bsr4    26      154243434355
    1       bsr     25      13188888888888
    2       test    30      13888888888888
    3       zs      34      899314121


得到的结果也是用\t分割的。也可以用-f参数实现:

    [bsr@master ~/local]$ cat bsr.sql
    select * from bsr
    [bsr@master ~/local]$ hive -f bsr.sql >> local/bsr2.txt



上述语句得到的结果也是\t分割的。