Hive 总结

在 Thu 27 August 2015 发布于 大数据 分类

安装

1.因为要把元数据存入mysql,需要下载mysql的jar包并移动到hive的lib目录下

2.进入conf文件夹把hive-default.xml.template 拷贝一份,重命名为hive-site.xml

3.修改hive-site.xml配置文件中的几个重要的参数

4.hive.metastore.warehouse.dir 这个hive的数据仓库的存储位置,其值一般都是HDFS中的路径,如:/user/hive/warehouse

5.javax.jdo.option.ConnectionURL,这个参数需要填写的时JDBC连接字符串,如:jdbc:mysql://localhost:3306/hive?characterEncoding=UTF-8

6.javax.jdo.option.ConnectionDriverName,设置JDBC的Driver,如:com.mysql.jdbc.Driver

7.javax.jdo.option.ConnectionUserName 和 javax.jdo.option.ConnectionPassword 这两个属性是设置连接mysql数据库用的username 和 password

8.修改/etc/profile添加一面这两行

export HIVE_HOME=/path/to/hive-xx.xx.xx
export PATH=$PATH:$HIVE_HOME/bin
Hive 中的概念

1.元数据:Hive中的元数据包括表的名字,表的列和分区及其属性,表的属性(是否为外部表等),表的数据所在目录等。 由于Hive的元数据需要不断的更新、修改。可以把Hive的元数据存储在数据库中,如Mysql中。

2.表: Hive中的表和关系型数据库中的表在概念上很类似,其数据存储在hive.metastore.warehouse.dir配置的目录下面

3.外部表:Hive中的外部表和表很类似,但是其数据不是放在自己表所属的目录中,而是存放到别处,这样的好处是如果你要删除这个外部表,该外部表所指向的数据是不会被删除的,它只会删除外部表对应的元数据;而如果你要删除表,该表对应的所有数据包括元数据都会被删除。 外部表创建的方法是:

create external table xx_ab.xx_table(
.....
)partitioned by (date string) location '/path/to/datadir';

4.分区: 在Hive中,表的每一个分区对应表下的相应目录,所有分区的数据都是存储在对应的目录中。这这我们在查找统计的时候就可以按分区来操作了,就不需要扫描整张表,减少资源消耗

Hive的使用

1.hive查询结果保存到指定文件并指定分隔符

insert overwrite local directory '/path/to/file'
row format delimited
FIELDS TERMINATED BY '\t' --域分割符
COLLECTION ITEMS TERMINATED BY ',' --集合分隔符
MAP KEYS TERMINATED BY ':' --map分隔符
select * from xxdb.xx_table;

2.在一个表格里面追加数据 insert into

--查看 hour_ad_request 表
hive> select * from hour_ad_request;
OK
2015060420  MOGO    526290
2015060419  MOGO    790119
2015060323  TANX    2
2015060400  TANX    8447052
2015060411  TANX    7846451
2015060412  MOGO    775668
2015060416  TANX    8401160
2015060417  MOGO    767131
2015060422  TANX    10915802
2015060418  LETV    10931
2015060408  TANX    6509808
2015060410  MOGO    570437
2015060414  TANX    8631478
2015060415  MOGO    786077
2015060420  TANX    10407739
2015060419  TANX    9505280
2015060416  LETV    3285
2015060401  TANX    6550079
2015060412  TANX    9214199
--查看 hour_ad_win表
hive> select * from hour_ad_win;

OK
2015060416  LETV    2939
2015060417  LETV    5080
--把hour_ad_request 表的数据插入到hour_ad_hour
hive> insert into table hour_ad_win select * from hour_ad_request;
....
--可以看出hour_ad_request 的数据已经插入到hour_ad_hour表中
hive> select * from hour_ad_win;

OK
2015060416  LETV    2939
2015060417  LETV    5080
2015060419  MOGO    790119
2015060323  TANX    2
2015060400  TANX    8447052
2015060411  TANX    7846451
2015060410  MOGO    570437
2015060415  MOGO    786077
2015060401  TANX    6550079
2015060412  TANX    9214199
2015060413  MOGO    761582
2015060423  TANX    10701597
2015060420  LETV    10694
2015060411  MOGO    761545
2015060415  TANX    7858653
2015060417  LETV    7596
2015060402  TANX    2281495
2015060413  TANX    9059986
2015060417  MOGO    767131
2015060414  TANX    8631478

3.在一个表格里面追加数据 insert overwrite, 这个和insert into 语句明显不同,强调的是覆盖,它可以和partition语句一块使用向一个已经有分区属性的表中写入新的数据

--还使用上面例子中的表
--查看hour_ad_win表
hive> select * from hour_ad_win;

OK
2015060416  LETV    2939
2015060417  LETV    5080
2015060419  MOGO    790119
2015060323  TANX    2
2015060400  TANX    8447052
2015060411  TANX    7846451
2015060410  MOGO    570437
2015060415  MOGO    786077
2015060401  TANX    6550079
2015060412  TANX    9214199
2015060413  MOGO    761582
2015060423  TANX    10701597
2015060420  LETV    10694
2015060411  MOGO    761545
2015060415  TANX    7858653
--用hour_ad_request覆盖hour_ad_win表
hive> insert overwrite table hour_ad_win select * from hour_ad_request;
...
hive> select * from hour_ad_win;

OK
2015060419  MOGO    790119
2015060323  TANX    2
2015060400  TANX    8447052
2015060411  TANX    7846451
2015060410  MOGO    570437
2015060415  MOGO    786077
2015060401  TANX    6550079
2015060412  TANX    9214199
2015060413  MOGO    761582
2015060423  TANX    10701597
2015060420  LETV    10694
2015060411  MOGO    761545
2015060415  TANX    7858653
2015060417  LETV    7596
---表分区
CREATE TABLE IF NOT EXISTS xx_db.xx_table (
...
)partitioned by(date string);
--xx_db.xx_table以date字段分区,我们可以在每天做完统计的时候把统计结果按天分区如
INSERT OVERWRITE TABLE xx_db.xx_table PARTITION(date='20150601')
SELECT * FROM XXX
....

4.简单查询不启用Mapreduce job而启用Fetch task

当我们在查询某个表的某一列,Hive默认是会启用MapReduce Job来完成这个任务,我们可通过设置 hive.fetch.task.conversion来启用Fetch task,从而达到不需要启动MapReduce Job来消耗资源 启动的方法有:

1. 修改配置文件,设置hive.fetch.task.conversion的值为more
2. 在hive命令行下执行
hive> set hive.fetch.task.conversion=more;
3. hive命令行启动情况下执行bin/hive –hiveconf hive.fetch.task.conversion=more
  • 日志调试

有时候我们在执行hive sql的时候会出错,但是给出的信息很少。Hive在默认的日志级别下是不输出DEBUG的信息的,但是我们可以通过以下两种方法修改log4j的输出日志级别 方法1:

[root@localhost ~]hive --hiveconf hive.root.logger=DEBUG, console

方法二:

在${HIVE_HOME}/conf/hive-log4j.properties中找到hive.root.logger的属性,并修改为DEBUG,console 我更建议使用第一种方法,因为第二中方法是永久生效的,一般我们只有在hive脚本调用出错的时候才会通过DEBUG信息去查找错误原因 平时,过多的debug信息反而是一种负担。

HiveQL的扩展开发
  • 内置函数

1.可以通过 SHOW FUNCTIONS 查看内置函数

hive> show FUNCTIONS;
>=
^
abs
acos
and
array
array_contains
ascii
asin
assert_true
atan
avg
....

2.通过DESCRIBE 查看内置函数的文档

hive> DESCRIBE FUNCTION concat;
concat(str1, str2, ... strN) - returns the concatenation of str1, str2, ... strN

3.内置函数可能有扩展文档,可以通过DESCRIBE FUNCTION EXTENDED查看

hive> DESCRIBE FUNCTION EXTENDED concat;
concat(str1, str2, ... strN) - returns the concatenation of str1, str2, ... strN
Returns NULL if any argument is NULL.
Example:
> SELECT concat('abc', 'def') FROM src LIMIT 1;
'abcdef'
  • 用户自定义函数

用户自定义函数(UDFs扩展)是hive里面的一个非常强大的特性,它能够让用户扩展HiveQL。用户只需要通过java编写实现并在执行HiveQL的时候叫载进去,用户编写的功能就像Hive内置的函数一样运行的很好。

在Hive中加载用户自定义函数

add jar /path/to/yourfunction.jar;
create temporary function function as 'com.sinaapp.zhangzewen.yourfunction';
--然后就可以在HiveQL中使用用户自定义函数了如
SELECT function(s1)
from xx_db.xx_table;

编写UDFs扩展需要继承UDF类并实现evaluate()方法,evaluate()函数在处理每个输入行时都会被调用,它执行的结果会返回给Hive,重载evaluate方法是合法的,Hive会自动调用最匹配的evaluate函数。 下面是个例子

package com.sinaapp.zhangzewen;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.hadoop.hive.ql.exec.UDF;
public class ConvertToHour extends UDF{
    public static String evaluate(String datetime) {
        SimpleDateFormat formater=new SimpleDateFormat("yyyy-MM-ddHH");
        Date d=null;
        try {
            d = formater.parse(datetime);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        String hour = formater.format(d);
        return hour.replaceAll("-", "");
    }
    public static void main(String[] args) {
        String datetime="2019-12-30 22:16:32.882038";
        System.out.println(evaluate(datetime));
    }
}