作为JAVA的初学者折腾了很久,试了代理服务器等方法,最终发现了这片文章,楼主总结的很不错!
一、概述
hive是一个基于hadoop的数据仓库基础设施, 提供数据的提取转换加载和查询, 不适于少数据量(比如几亿)的数据查询, 也不适于实时或者在线数据的查询, 是一个非实时的, 离线的数据查询工具. hive没有自己的文件格式, 只需要普通的文件格式或者用户自定义的格式就可以了.
二、环境搭建
hive不需要神马集群配置, 只是需要编译一个环境就好了, 编译的过程, 国人表示很蛋疼, 因为他的ant脚本中, 使用的镜像居然是facebook的, FQ了都没用表示很纠结. 所以需要把facebook的镜像改为可用的(最好是国内的, 诸如 人人网, 北京交通大学等等镜像), 镜像的选择可以根据个人喜好和地理位置自由选取, 当然是不能被GFW墙了的.(参考http://www.apache.org/dyn/closer.cgi/hadoop/core/)
1. 下载源代码: svn co http://svn.apache.org/repos/asf/hive/trunk hive
2. 安装ant, 过程简单, 略去 (只要解压就行了)
3. 修改 hive/build.properties 文件, 将
a). hadoop.mirror的值修改为人人网镜像 : hadoop.mirror=http://labs.renren.com/apache-mirror
b). hadoop.security.url的值修改为可用的地址, 在网上找了个: hadoop.security.url=http://people.apache.org/~todd/snapshot-for-hive-build/hadoop-0.20.3-CDH3-SNAPSHOT.tar.gz
(这个东东不是一般的镜像能有的,囧)
c). 将hadoop的版本修改为0.20.2, (貌似0.20.0的地址都不可用了, 难道有大bug?): hadoop.version=0.20.2
4. 修改hive/shims/ 下的ivy.xml 和 build.xml
将对应的hadoop的版本修改为 0.20.2
a) ivy.xml
|
b) build.xml
(line 61)
param
=
value
"0.20.2"
3
5
TABLE
INT
BIGINT
PARTITIONED
(dt STRING, country STRING)
STORED
SEQUENCEFILE;
|
partitioned by 是创建分区(什么是分区?下边说明)
没有指定字段分隔符的话, 默认是使用^A(ctrl-A)为字段分隔符, 换行为记录分隔符. 指定分隔符用ROW FORMAT row_format 语句
分区: partitioned by , 其实就是在数据的目录下, 用不同目录来区分, 比如, dt, 就是按日期(date)来区分, country 国家, hour 小时等等.对应的会在数据的目录下有分区目录. 可以建双分区, 就是子目录下再分区(其实就是一棵目录树).
参考: http://blog.youkuaiyun.com/dajuezhao/archive/2010/07/21/5753055.aspx
高级用法:
2
4
6
8
10
TABLE
INT
BIGINT
PARTITIONED
(dt STRING, country STRING)
CLUSTERED
(userid) SORTED
(viewTime)
32 BUCKETS
ROW FORMAT DELIMITED
FIELDS TERMINATED
'1'
COLLECTION ITEMS TERMINATED
'2'
MAP KEYS TERMINATED
'3'
STORED
SEQUENCEFILE;
|
clustered by 是按照某个字段来进行hash集群
2. 查看表和表结构
SHOW TABLES
;
|
列出所有以”page”为前缀的表, ‘page.*’ 用法和java正则表达式相同
DESCRIBE page_view;
|
与普通DBMS的desc一样, 列出指定表的所有字段和字段类型.
DESCRIBE EXTENDED page_view PARTITION (ds=
);
|
列出指定表指定分区的搜有字段和字段类型, 以及其他所有属性.(一般也是用于调试)
3. 装载数据
装载数据有很多方法:
a. 通过创建一个扩展表, 并指定其location, 然后通过hadoop 的 dfs -put命令将数据放到location指定的位置即可.
2
4
6
8
|
CREATE
TABLE
INT
BIGINT
|
LOAD
LOCAL
INTO
page_view PARTITION(
=
, country=
)
|
加载本地文件到指定的表中, 还可以指定表的分区.
DATA INPATH
INTO
page_view PARTITION(
=
, country=
)
|
加载hdfs文件到指定的表中, 还可以指定表的分区.
这里的inpath 后便的参数, 可以普通文件路径(单文件), 也可以是一个目录的路径(该目录下的文件都会被加载, 但要求该目录下没有子目录), 也可以是通配符(如 page_view*.txt, 但通配符匹配的也只是普通文件, 不匹配目录)
4. 简单查询
2
4
|
INSERT
TABLE
WHERE
.active = 1;
|
与SQL不同的是, 我们将查询结果插入到一个表中, 后续会讲到如何查看这个结果表的数据, 或者如何dump到本地文件中.
如果是在hive的control端 hive cli中查询并查看数据, 就不需要插入到某个表中了, 可以直接查看, 如:
2
user
WHERE
.active = 1;
|
5. 基于分区的查询
似乎只能通过where语句来解决
2
4
OVERWRITE
xyz_com_page_views
SELECT
WHERE
date
'2008-03-01'
page_views.
<=
AND
|
如果想要做外连接, 则可以用 left outer join, right outer join 和 full outer join 等关键字来查询, 例如:
2
4
|
INSERT
TABLE
FROM
u
OUTER
page_view pv
(pv.userid = u.id)
|
另外, 像SQL一样, 一次查询可以有多个连接的, 一直join下去都没问题.
7. 聚集函数
2
4
|
INSERT
TABLE
FROM
3
5
7
pv_users
INSERT
TABLE
GROUP
pv_users.gender
OVERWRITE DIRECTORY
GROUP
pv_users.age;
|
9. 动态分区插入(hive 0.6.0)
没有使用动态分区插入的情况下:
2
4
6
page_view_stg pvs
INSERT
TABLE
'2008-06-08'
'US'
SELECT
null
null
WHERE
'CA'
INSERT
TABLE
'2008-06-08'
'UK'
|
如果想要将计算的分类结果分别保存到不同类别的分区中, 按照上面的写法, 必须有多少分区插入多少次, 这样的写法是不方便的, 而且多个insert操作对应多个map reduce job, 这样对系统的性能也有影响. 在hive的0.6.0以上版本中, 增加了动态分区插入的特性, 在计算过程中, hive会自动识别当前字段属于哪个分区的, 然后插入的时候会插入到对应的分区中(如果该分区还没创建, 那hive会自动创建这个分区的).
使用动态分区插入之后, 只需要一个insert操作, 也就是只对应一个map reduce job
2
page_view_stg pvs
INSERT
TABLE
'2008-06-08'
|
这里再partition定义中, 不指定值, select语句中也少了where语句的判断.
在partition中, country字段没有指定值, 说明这是一个动态的分区字段, 但dt就有一个值, 说明这是静态分区字段. 而且在where语句中不需要增加dt的判断, 因为在partition中已经指定了.目前hive只允动态分区字段出现在partition语句中的最后面(可以多个), 因为分区字段的先后顺序表明了他们之间的层级关系.Note that the dynamic partition values are selected by ordering, not name, and taken as the last columns from the select clause.
insert语句中几个语义上要注意的地方
a.如果查询结果对应的分区原来存在的话, 将被覆盖, 如果原来存在的分区, 但是查询结果中没有属于这个分区的, 将不被覆盖.
b.partition语句中的值最终对应的是hdfs上的path, 所以必须这些值必须满足path的命名规范, 否则将被urlencode.
c.如果输入的字段不是string类型, 将会被强制先装换为string类型.
d.如果输入的字段值是NULL或者空(empty),记录将会被放到一个特殊的分区, 这个分区在hive的配置参数中可以得到.
e.动态分区插入的时候可能会在短时间内创建大量的分区, 如果需要自己控制, 可以配置hive.exec.max.dynamic.partitions和 hive.exec.max.dynamic.partitions.pernode这两个参数, 前者是配置动态分区时最多产生的分区数, 后者是在每个M/R job中产生的最多的分区数, 但计算过程中超过这些数时, 将会产生致命性的错误, 并停止job的运行.
f.在动态分区插入中, 有一种情况是搜索的partition参数都是动态的, 这样是没有意义的, 所以hive中提供了一个参数来限制这种事的发 生:hive.exec.dynamic.partition.mode=strict/nonstrict 默认值strict就是要求至少有一个是静态的分区字段.另外还有一个参数来配置是否支持动态分区插入 hive.exec.dynamic.partition=true/false , 默认是关闭的(false)
g.目前, 如果hive开启了hive.merge.mapfiles=true 或者 hive.merge.mapredfiles=true 会导致不支持动态分区插入, 因为开启了其中一个在job执行的时候就会把文件合并为一个, 这样不利于我们的分区, 因为分区其实也是对应到hadoop的hdfs上的.
10. 插入到本地文件
2
OVERWRITE
DIRECTORY
|
INSERT
TABLE
FROM
OUT
32);
|
抽取总共32桶中的第三桶
抽样语句的语法如下:
TABLESAMPLE(BUCKET x OUT OF y)
其中, x必须比y小, y必须是在创建表的时候bucket on的数量的因子或者倍数, hive会根据y的大小来决定抽样多少, 比如原本分了32分, 当y=16时, 抽取32/16=2分, 这时TABLESAMPLE(BUCKET 3 OUT OF 16) 就意味着要抽取第3和第16+3=19分的样品. 如果y=64, 这要抽取 32/64=1/2份数据, 这时TABLESAMPLE(BUCKET 3 OUT OF 64) 意味着抽取第3份数据的一半来进行.
12. Union all
类似于SQL
2
4
6
8
10
12
OVERWRITE
actions_users
SELECT
date
FROM
FROM
UNION
SELECT
AS
WHERE
date
'2008-06-03'
) actions
users u
(u.id = actions.uid);
|
13. 数组操作.
但一个字段的数据类型时数组时, 可以通过数组的索引来访问该字段的某个索引值.
2
|
SELECT
|
另外还提供了一个函数 size, 可以求出数组的大小
2
|
SELECT
size
|
14. Map(关联性数组)操作
map的访问类似于 php中对数组的访问, 直接用key作为索引来访问数组即可.
2
OVERWRITE page_views_map
SELECT
'page type'
|
与数组类似, 也提供了一个求大小的函数 size
2
|
SELECT
(pv.properties)
FROM <code plain"="">page_view pv;
|
15. 自定义map/reduce脚本 & cogroups, 太高级了, 还没看懂, 先晾着.
16. 变更表(altering table)
a, ALTER TABLE old_table_name RENAME TO new_table_name; 表重命名
b, ALTER TABLE old_table_name REPLACE COLUMNS (col1 TYPE, …); 字段重命名
c, ALTER TABLE tab1 ADD COLUMNS (c1 INT COMMENT ‘a new int column’, c2 STRING DEFAULT ‘def val’); 增加新的字段.
16. 删除表和分区(drop)
a, DROP TABLE pv_users; 删除表
b, ALTER TABLE pv_users DROP PARTITION (ds=’2008-08-08′)删除分区
操作不可恢复
以上手册本人参考和翻译自 http://wiki.apache.org/hadoop/Hive/Tutorial
转自http://www.jiacheo.org/blog/126