大数据仓库Hive

大自然的搬运工又又又又又来啦!!!,实验课实在是不知道该干嘛了,那就做一个合格的搬运工吧!(手动狗头)

Hive初识

Hive 简介

Hive官方网址
Hive是基于Hadoop(HDFS, MapReduce)的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能。本质上是把HQL语句转换成MapReduce程序。

Hive本身是建立在 Hadoop体系结构上的数据仓库基础构架,可以将结构化的数据文件映射为一张数据库表,并提供完整的QL语句,把QL语句转化成MapReduce程序提交给Hadoop集群完成相关任务。它提供了一系列的工具,可以用来进行数据提取转化加载(ETL ),这是一种可以存储、查询和分析存储在 Hadoop中的大规模数据处理的机制。Hive 定义了简单的类SQL查询语言,称为 QL ,它允许熟悉SQL的用户查询数据。同时,这个语言也允许熟悉 MapReduce开发者的开发自定义的 mapper和 reducer来处理内建的 mapper 和 reducer无法完成的复杂的分析工作。

在这里插入图片描述

Hive的特点

1、Hive是SQL解析引擎,它将SQL语句转译成M/R Job然后在Hadoop执行。

2、Hive的表其实就是HDFS的目录/文件,按表名把文件夹分开。如果是分区表,则分区值是子文件夹,可以直接在M/R Job里使用这些数据。

3、Hive的设计目的是让精通SQL技能的(java编程能力相对较弱)分析师能够对放在HDFS上的海量数据集能够进行查询。目前企业都把它当做一个通用,可伸缩的数据处理平台。

4、学习hive的前提条件:熟悉SQL和数据库体系结构。

5、Hive执行原理:把SQL查询转换为一系列在Hadoop集群上运行的MapReduce作业。Hive把数据组织能表,通过这种方式为存储在HDFS的数据赋予结构。
在这里插入图片描述

Hive的基本组件

在这里插入图片描述

1、 用户接口,包括 CLI,JDBC/ODBC,WebUI;
2、 元数据存储,通常是存储在关系数据库如 MySQL, derby 中;
3、解释器、编译器、优化器、执行器。

Hive的数据存储

Hive 将元数据存储在数据库中(metastore),目前只支持MySQL、derby。Hive 中的元数据包括表的名字,表的列和分区及其属性,表的属性(是否为外部表等),表的数据所在目录等。

解释器、编译器、优化器完成 HQL 查询语句从词法分析、语法分析、编译、优化以及查询计划(plan)的生成。生成的查询计划存储在 HDFS 中,并在随后有 MapReduce 调用执行。

Hive的SQL方言称为HiveQL,它并不完全支持SQL-92标准。例如:HiveSQL并不支持Having子句,但支持子查询。

Hive 的数据存储在 HDFS 中,大部分的查询由 MapReduce 完成(包含 * 的查询,比如 select * from table 不会生成 MapRedcue 任务)。

Hive与Hadoop之间的关系

1、Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供完整的SQL查询功能,可以将SQL语句转换为MapReduce任务进行运行。其优点是学习成本低,可以通过类SQL语句快速实现简单的MapReduce统计,不必开发专门的MapReduce应用,十分适合数据仓库的统计分析。

2、Hive是建立在 Hadoop 上的数据仓库基础构架。它提供了一系列的工具,可以用来进行数据提取转化加载(ETL),这是一种可以存储、查询和分析存储在 Hadoop 中的大规模数据的机制。Hive 定义了简单的类 SQL 查询语言,称为 HQL,它允许熟悉 SQL 的用户查询数据。同时,这个语言也允许熟悉 MapReduce 开发者的开发自定义的 mapper 和 reducer 来处理内置的 mapper 和 reducer 无法完成的复杂的分析工作。

Hive的安装与使用

Hive安装前准备

Hive依赖于Hadoop,而Hadoop依赖于java。用户需要确认使用的操作系统中安装有V1.7.*或者V1.8.*版本的JVM(java虚拟机)。在第一章中我们搭建好了Hadoop环境。在此我们就在第一章搭建的Hadoop环境上,安装和配置Hive

安装Hive的注意事项

1、安装Hive时,首先确保Hadoop已经安装完毕并且能正确使用

2、 因为Hive是基于Hadoop平台,安装Hive之后需要进行相关配置,相关文件:hive-evn.sh和hive-site.xml

3、建议配置Hive的path环境:HIVE_HOME在/etc/profile

Hive有自带的一个关系型数据库derby,如果使用自带的数据库,需要进行数据库的相关配置。如果开发者想更换数据库,例如更换MySQL数据库,则需要进行配置文件的修改并且需要提供MySQL数据库驱动放到Hive_home/lib下。目前Hive主要是支持derby和MySQL数据库。

Hive安装步骤(基于自带数据库derby)

1、解压hive-0.13.1-cdh5.3.6.tar.gz,命令如下:

tar -zxvf hive-0.13.1-cdh5.3.6.tar.gz -C /iflytek

将hive-0.13.1-cdh5.3.6修改为hive-0.13.1,命令如下:

mv hive-0.13.1-cdh5.3.6 hive-0.13.1

2、配置hive-evn.sh
在Hive的安装目录下的conf文件中修改hive-env.sh文件,如果该目录不存在该文件,可使用如下命令复制:

cp hive-env.sh.template hive-env.sh (hive-evn.sh文件名是固定的,不得随意修改)

复制完毕之后 vim hive-evn.sh,增加hadoop的安装目录 如:HADOOP_HOME=/iflytek/hadoop-2.5.0

3、修改环境变量:vim /etc/profile .添加hive的安装目录和path路径

export HIVE_HOME=/iflytek/hive-0.13.1(新添加)

export PATH=$JAVA_HOME/bin:$HIVE_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH

在这里插入图片描述
4、刷新/etc/profile文件,命令如下:

source /etc/profile

5、测试Hive的使用,需首先将hadoop进程开启。
6、Hadoop进程成功开启后,使用如下命令进入Hive:hive

Hive的文件管理

bin:可执行文件(二进制),例如:hive hiveserver2 hive-config.sh等;
conf:hive的配置文件,里面的配置文件都是默认的配置文件,它是缺省配置服务的。如果需要自定义,配置文件需要创建一个hive-site.xml;
docs:hive的参考文档;
lib:存放jar的地方;
metastore_db:该目录是启动hive的时候,自动生成的一个目录,是用来存放hive的元数据信息。

元数据信息metastore

Hive中metastore(元数据存储)的三种方式:

1、内嵌Derby方式

2、Local方式

3、Remote方式

Metastor是hive元数据的集中存放地。Metastore包括两部分:服务和后台数据的存储。

内置默认的metastore即使用derby作为元数据库存在问题:

1、换执行路径后,原来的表不存在了。

2、只能有一个用户访问同一个表。

因此derby只支持单连接,如果采用多连接的话需要进行切换目录。在生产环境中一般不使用derby作为我们的元数据库,采用MySQL的居多,能够多用户同时访问

Metastor常见配置项:

Ø hive.metastore.warehouse.dir 存储表格数据的目录

Ø hive.metastore.local 使用内嵌的metastore服务(默认为true)

Ø hive.metastore.uris 如果不使用内嵌的metastore服务,需指定远端服务的uri

Ø javax.jdo.option.ConnectionURL 所使用数据库的url

Ø javax.jdo.option.ConnectionDriverName 数据库驱动类

Ø javax.jdo.option.ConnectionUserName 连接用户名

Ø javax.jdo.option.ConnectionPassword 连接密码
说明:derby数据库默认创建在当前目录下。 在做hive操作命令时,先把hadoop服务启动起来,否则,操作dml语句时,报错。

Hive的基本操作

#创建数据库

create database tabletest;

在这里插入图片描述
#创建一个新表,创建表的同时,指定数据字段之间的分割符:
在这里插入图片描述
#导入数据

在/opt/data下准备user.txt。如:
在这里插入图片描述

load data local inpath '/opt/data/user.txt' overwrite into table user;

在这里插入图片描述
#增加一个字段:
在这里插入图片描述
#将HDFS上的文件加载到hive中

复制一个表结构不导数据:
在这里插入图片描述
在/opt/data下创建数据文件:stu.txt。如下:
在这里插入图片描述
将stu.txt导入HDFS,命令如下:

hdfs dfs -put /opt/data/stu.txt /

文件导入数据

load data inpath '/stu.txt' overwrite into table stu;  

在这里插入图片描述
#导出到本地文件系统
在这里插入图片描述
在本地可以查看导出的文件内容:
在这里插入图片描述

#删除表
drop table if exists 表名
离开hive环境
exit;

Hive的数据类型

在这里插入图片描述
复杂数据类型:

== ARRAY:== ARRAY类型是由一系列相同数据类型的元素组成,这些元素可以通过下标来访问。比如有一个ARRAY类型的变量fruits,它是由[‘apple’,‘orange’,‘mango’]组成,那么我们可以通过fruits[1]来访问元素orange,因为ARRAY类型的下标是从0开始的;
== MAP:== MAP包含key->value键值对,可以通过key来访问元素。比如“userlist”是一个map类型,其中username是key,password是value;那么我们可以通过userlist[‘username’]来得到这个用户对应的password;
STRUCT: STRUCT可以包含不同数据类型的元素。这些元素可以通过“点语法”的方式来得到所需要的元素,比如user是一个STRUCT类型,那么可以通过user.address得到这个用户的地址。
UNION: UNIONTYPE,他是从Hive 0.7.0开始支持的。

Hive与传统数据库的区别

在这里插入图片描述

常见的数据库查询

1、基本查询


1)select * from stu;

2)where子句
select * from stu where 字段=值;

3)Limit查询
select * from stu limit 3;//查询所有数据的前三条
说明:limit的使用和MySQL稍微有点区别。hive中的limit只有一个参数

4)区间查询between and 
select * from stu s where s.age between s.age=20 and s.age =25;

5)集合查询in  
select * from stu s where s.name in ('lisi','zhaoliu');

2、函数查询

select count(*) from stu;   //总人数
select sum(字段1) from stu; //总和
select max(字段1)  from stu;  //最大值
select min(字段1)  from stu;  //最小值
select avg(字段1)  from stu;  //平均值

3、高级查询


1)分组group by
select * from stu group by addr;

2)having
where:是针对单条记录进行筛选。
having是针对分组数据进行筛选
select name,sum(score) from stu group by name having sum(score)>90;
3)order by查询
select * from stu order by name asc[desc];

4)  join
两个表进行连接,例如有两个表m n ,m表中的一条记录和n表中的一条记录组成一条记录。
内连接
select b.name,a.* from stu a join score b on(a.id=b. id) limit 10;
左外连接
select b.name,a.* from stu a left outer join score b on a. id =b. id limit 10;
右外连接
select b.name,a.* from stu a right outer join score b on a. id =b. id limit 10;

5)Like模糊查询
select * from stu where name like '%ang%';

数据库

1、类似传统数据库的DataBase;

2、默认数据库"default";

3、使用#hive命令后,不使用hive>use <数据库名>,系统默认的数据库。可以显式使用hive> use default

Hive表逻辑上由存储的数据和描述表格形式的相关元数据组成。数据一般放在HDFS上。Hive把元数据放在关系型数据库中,并不是放在HDFS上。

1、Table内部表(托管表):当删除内部表时,HDFS上的数据以及元数据都会被删除。

create table student(id int,name string);

2、Partition分区表:Hive把表组织成分区,分区可以加快分片的查询速度。将一批数据分成多个目录来存储。

Create table day_table (id int, content string)
partitioned by (dt string)  //指定分区
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' ;

以分区的常用情况为例。考虑日志文件,其中每条记录包含一个时间戳。如果我们根据日期进行分区,那么同一天的记录就会被存放在同一个分区中。这样对于限定某个条件的查询,效率会非常高,因为它只需要扫描查询范围内的文件。

3、External Table外部表

Create external table student(id int,name string)location ‘路径’;//创建外部表时指定位置。

创建表时使用external关键字时,hive知道数据并不属于自己管理,不会把数据移到自己的数据仓库中。当删除外部表的时候,HDFS上的数据不会被删除,但是元数据会被删除。

说明:在创建外部表时,要先在路径下准备数据,然后再创建表。

4、Bucket Table 桶表:分桶表是对列值取哈希值的方式,将不同数据放到不同文件中存储,一个文件对应一个桶,由列的哈希值除以桶的个数来决定每条数据划分在哪个桶中,对于hive中每一个表、分区都可以进一步进行分桶。

好处:提高了join的效率;提高了随机抽样的效率。
使用分桶表要修改set hive.enforce.bucketing=true;
桶表会为数据提供额外的结构以获得更高效的查询处理。

内表

内部表与数据库中的表在概念上是类似的,每一个表在Hive中都有一个相应的目录存储数据。例如,一个表 test,它在 HDFS 中的路径为:/ warehouse/test。 warehouse是在 hive-site.xml 中由 ${hive.metastore.warehouse.dir} 指定的数据仓库的目录。所有的表数据(不包括外部表)都保存在这个目录中。删除表时,元数据与数据都会被删除
示例如下:
1、创建表

CREATE TABLE inner_table( //table前没有修饰符,说明创建的是一个内部表
  id INT,
  name STRING,
  age INT
 )
ROW FORMAT DELIMITED 
    FIELDS TERMINATED BY '\t'  //字段间的分隔符
    COLLECTION ITEMS TERMINATED BY ','  //集合元素之间的分隔符
    MAP KEYS TERMINATED BY ':'   //map中key和value之间的分隔符
    LINES TERMINATED BY '\n';   //行与行之间的分隔符
LOCATION "/test" //可以设置源数据的位置,若不设置默认就在Hive的工作目录区

2、导入数据

load data local inpath '/opt/data/user.txt' overwrite into table inner_table;

3、查询表中字段的值

select * from inner_table;

在HDFS目录查看:
在这里插入图片描述
4、删除表 drop table inner_table;
删除后HDFS目录:
在这里插入图片描述
由此,可以看出当删除内部表后,HDFS上的数据和元数据都会被删除。

外部表

外部表指向已经在 HDFS 中存在的数据,可以创建 Partition。它和内部表在元数据的组织上是相同的,而实际数据的存储则有较大的差异。内部表的创建过程和数据加载过程(这两个过程可以在同一个语句中完成),在加载数据的过程中,实际数据会被移动到数据仓库目录中;之后对数据对访问将会直接在数据仓库目录中完成。删除表时,表中的数据和元数据将会被同时删除。外部表只有一个过程,加载数据和创建表同时完成,并不会移动到数据仓库目录中,只是与外部数据建立一个链接。当删除一个外部表时,仅删除该链接

示例如下:
1、创建表

create external table external_table(
id int,
name string,
age int)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' location '/iflytek/';

在HDFS创建目录/iflytek


hdfs dfs -mkdir /iflytek

2、加载数据

load data local inpath '/opt/data/user.txt' overwrite into table external_table;

3、查看数据

    select * from external_table;

在HDFS中查看数据:
在这里插入图片描述
4、删除表

drop table external_table;

在这里插入图片描述
由此,可以看出当删除外部表时,仅会删除元数据,但并不会删除HDFS上的数据。

分区表

Partition对应于数据库的Partition列的密集索引,在Hive中,表中的一个Partition对应于表下的一个目录,所有的Partition的数据都存储在对应的目录中。
语法:

CREATE TABLE tmp_table      #表名
    (
    title   string,              # 字段名称 字段类型
    minimum_bid     double,
    quantity        bigint,
    have_invoice    bigint
    )COMMENT '注释:XXX'      #表注释
    PARTITIONED BY(pt STRING)  #分区表字段(如果你文件非常之大的话,采用分区表可以快过滤出按分区字段划分的数据)
    ROW FORMAT DELIMITED 
    FIELDS TERMINATED BY '\001'  # 字段是用什么分割开的
    STORED AS SEQUENCEFILE;    #用哪种方式存储数据,SEQUENCEFILE是hadoop自带的文件压缩格式

一些相关命令:

SHOW TABLES; # 查看所有的表
SHOW TABLES '*TMP*'; #支持模糊查询
SHOW PARTITIONS TMP_TABLE; #查看表有哪些分区
DESCRIBE TMP_TABLE; #查看表结构

实例如下:创建数据文件partition_table.txt
1、创建表

create table partition_table(
      id int,
      name string,
      age int
       )
    partitioned by(addr string)
    row format delimited fields terminated by '\t' stored as TEXTFILE;

2、加载数据到分区

  load data local inpath '/opt/data/partition_table.txt' into table partition_table partition (addr='beijing');

3、查看数据

select * from partition_table;

4、添加分区

 alter table partition_table add partition (addr='shanghai');

5、删除分区:元数据,数据文件删除,但目录还在

alter table partition_table drop partition (addr='beijing');\

6、查看HDFS:
在这里插入图片描述
7、删除表

  drop table partition_table;

桶表

桶表是对数据进行哈希取值,然后放到不同文件中存储。

1、创建表

 create table bucket_table(id string) clustered by(id) into 4 buckets;  

2、加载数据

   set hive.enforce.bucketing = true;
   insert into table bucket_table select name from stu;
   insert overwrite table bucket_table select name from stu;

3、数据加载到桶表时,会对字段取hash值,然后与桶的数量取模。把数据放到对应的文件中。

4、抽样查询

   select * from bucket_table tablesample(bucket 1 out of 4 on id);

基于Mysql的Hive环境部署

Hive配置(本地模式)

1、解压hive-0.13.1-cdh5.3.6.tar.gz,命令如下:

tar -zxvf hive-0.13.1-cdh5.3.6.tar.gz -C /iflytek
将hive-0.13.1-cdh5.3.6修改为hive-0.13.1,命令如下:
mv hive-0.13.1-cdh5.3.6 hive-0.13.1

2、配置hive-evn.sh
在Hive的安装目录下的conf文件中修改hive-env.sh文件,如果该目录不存在该文件,可使用如下命令复制:

cp hive-env.sh.template hive-env.sh (hive-evn.sh文件名是固定的,不得随意修改)

复制完毕之后 vim hive-evn.sh,增加hadoop的安装目录 如:HADOOP_HOME=/iflytek/hadoop-2.5.0

3、修改环境变量:vim /etc/profile .添加hive的安装目录和path路径

export HIVE_HOME=/iflytek/hive-0.13.1(新添加)

export PATH=$JAVA_HOME/bin:$HIVE_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH

如下图:
在这里插入图片描述
4、刷新/etc/profile文件,命令如下:source /etc/profile

MySQL的卸载与安装

1、rpm -qa |grep -i MySQL //查看是否存在安装MySQL
如果存在,则需要卸载:


rpm -e MySQL-libs-5.1.71-1.el6.x86_64

rpm -e MySQL-server-5.1.73-1.glibc23.x86_64

rpm -e MySQL-client-5.1.73-1.glibc23.x86_64

如果在安装过程出现包的冲突或者包的依赖


rpm -e MySQL-libs-5.1.71-1.el6.x86_64--nodeps

rpm -e MySQL-server-5.1.73-1.glibc23.x86_64--nodeps

rpm -e MySQL-client-5.1.73-1.glibc23.x86_64--nodeps

2、一般情况下Linux在写入完毕之后,有些文件需要手动删除,找到相关MySQL文件
一般(centos)/usr/lib/MySQL or /var/lib/MySQL or /usr/lib/MySQL/MySQL
如果找MySQL相关文件,执行命令 find /-name MySQL.
通过以上命令找到的MySQL进行手工删除

rm -rf /usr/lib/MySQL
rm -rf /var/lib/MySQL

3、安装MySQL

rpm -ivh MySQL-server-5.1.73-1.glibc23.x86_64
rpm -ivh MySQL-client-5.1.73-1.glibc23.x86_64

在安装过程中,有可能碰到权限问题或者用户所属问题,文件用户所属和文件权限修改chmod -R 777 /xxx
4、安装完MySQL服务端和客户端之后,需要进行配置,执行命令:

/usr/bin/MySQL_secure_installation

#验证MySQL是否安装成功

service MySQL status | start |stop
chkconfig MySQL --list

#测试安装的数据库

5、测>MySQL

1)建库建表来测试
2)测试我们MySQL-front客服端有没链接上我们的linux
6、如果远程连接数据库时,出现不允许访问的时候,需要对连接用户赋予权限

进入MySQL命令:

MySQL -uroot -psimple
grant all privileges on *.* to 'root'@'%' identified by 'simple' with grant option;
flush privileges;

7、权限刷新之后,重启MySQL服务


service MySQL restart(推荐)

Hive环境变量配置

#解压、重命名、设置环境变量(上面已经配置了,本地模式)
#在目录 $HIVE_HOME/conf 下,执行命令 mv hive-default.xml hive-site.xml重命名
并修改 $HIVE_HOME/conf/hive-site.xml

#vim /iflytek/hive-0.13.1/conf/hive.site.xml
<configuration>
    <property>
        <name>javax.jdo.option.ConnectionURL</name>
        < !-- 所使用的数据库的url -- >
        <value>jdbc:mysql://localhost:3306/hivemeta?
         createDatabaseIfNotExist=true</value>
    </property>
    <property>
        <name>javax.jdo.option.ConnectionDriverName</name>
        < !-- 数据库驱动类-- >
        <value>com.mysql.jdbc.Driver</value>
    </property>
    <property>
        <name>javax.jdo.option.ConnectionUserName</name>
        < !-- 连接用户名-- >
        <value>root</value>
    </property>
    <property>
        <name>javax.jdo.option.ConnectionPassword</name>
        < !-- 连接密码-- >
        <value>123456</value>
    </property>
    <property>
        <name>hive.metastore.schema.verification</name>
        <value>false</value>
    </property>
</configuration>

Hive环境配置说明

1、hive-0.13.1/conf目录下hive-default.xml.template文件,在不修改文件名的情况下,该文件中的默认配置是不能改变的,即使该文件的内容改变,但是不会起到任何作用 ;除非修改还文件命名才有效,如果希望自动是该文件有效,命名必须为hive-site.xml。

#配置MySQL url路径时,metastore的数据库名尽量不要包含特殊字符(例如:-_ .等),在目录$HIVE_HOME/conf 下,执行命令mv hive-env.sh.template hive-env.sh重命名

2、修改hadoop的配置文件hadoop-env.sh,修改内容如下:

HADOOP_HOME=/usr/local/hadoop

3、在目录下$HIVE_HOME/bin下面,修改文件hive-config.sh,增加以下内容:


export JAVA_HOME=/iflytek/jdk1.8.0_11

export HIVE_HOME=/iflytek/hive-0.13.1

export HADOOP_HOME=/iflytek/Hadoop-2.5.0

4、MySQL的驱动MySQL-connector-java-5.1.28.jar加到/usr/local/hive-0.13.0/lib/

#测试是否配置成功(测试之前一定不要忘记启动hadoop)

hive //在任何目录下都可以直接启动hive,因为hive配置环境变量

./hive //在没有配置环境变量的情况下,必须在/usr/local/hive-0.13.0/bin目录下执行

5、在测试的过程中有可能文件权限的问题,对应目录主要有两个:
hdfs://192.168.203.100:9000/tmp
/tmp
hdfs dfs -chmod -R 1777 /tmp //hdfs上的文件权限
chmod -R 1777 /tmp //linux文件权限

Hive 测试

使用数据库客户端连接数据库结果查看到(此处使用的是My-front)
在这里插入图片描述
启动hive

hive

创建数据库

hive> create database test_db;

显示所有数据库

show databases;

使用数据库test_db

hive> use test_db;

创建学生表

hive> create table student(id int,name string);

查看是否在HDFS中存有下面文件夹

http://namenode:50070/user/hive/warehouse/test_db.db/student

Hive UDF编程

Hive内置函数

在编写自定义UDF函数之前,我们先熟悉下Hive中自带的那些UDF。需要注意的是在Hive中通用使用“UDF”来表示任意的函数,包括用户自定义的或者内置的。

Show functions命名可以例举出当前Hive会话中所加载的所有函数名称,其中包括内置和用户加载进来的函数,加载方式稍后会进行介绍:
在这里插入图片描述
函数通常都有其自身的使用文档。使用desribe function 命名可以展示对应函数简短的介绍,例如:
在这里插入图片描述
函数也可能包含更多的详细文档,可以通过增加extended 关键字进行查看,如下:
在这里插入图片描述

UDF编程

编程步骤:

1、继承org.apache.hadoop.hive.ql.UDF;

2、需要实现evaluat函数,evaluate函数支持重载。

注意事项:

1、UDF必须要有返回值类型,可以返回null,但是不能为void;

2、UDF中常用Text/LongWritable等类型,不推荐使用Java类型;

下面我们开始编写自己的UDF。假设我们要实现一个自己的小写转换函数lowerUDF,可以这样实现:

#下面是一个样本数据集,我们将其放到/opt/data/下一个名为person.txt的文件:

1 ZHANGSAN 16

2 LISI 28

3 WANGWU 17

4 ZHAOLIU 29

#创建表


create table person(id int,name string ,age int) row format delimited fields terminated by '\t';

#导入数据

load data local inpath '/opt/data/person.txt' overwrite into table person;

#创建java文件把hive中lib包下面的jar包导入到项目中并把hadoop的通用包导入到项目中

/iflytek/hive-0.13.1/lib/xxx.jar    /iflytek/hadoop-2.5.0/share/hadoop/common/xxx.jar

public class LowerUDF extends UDF{
public  Text evaluate(Text str) {
//validate
if(null==str.toString()) {
return null;
}
//lower
return new Text(str.toString().toLowerCase()) ;
}
public static void main(String[] args) {
System.out.println(new LowerUDF().evaluate(new Text( )));
}
}

1、把创建的类导出LowerUDF.jar

2、把打包的jar通过hive命令 添加到path中

hive>add jar /iflytek/LowerUDF.jar;

3、临时函数

create temporary function LowerUDF as 'com.iflytek.udf. LowerUDF';

4、测试查询:

select LowerUDF(name) from person;  

在这里插入图片描述

UDF与GenericUDF编程

前面介绍计算UDF的例子中,我们继承的是UDF类。Hive还提供了一个对应的称为GenericUDF的类。GenericUDF是更为复杂的抽象概念,但是其支持更好的null值处理同时可以处理一些UDF无法支持的编码操作。GenericUDF的一个例子就是Hive中的cass…when语句,其会根据语句中输入的参数二产生复杂的处理逻辑。下面我们将展示如何通过继承GenericUDF类来编写一个用户自定义函数我们称之为nvl(),这个函数传入的值如果是null,那么就会返回一个默认值。
函数nvl要求有2个参数。如果第一个参数就是非null值,那么就会返回这个值,如果第一个参数是null,那么将返回第二个参数的值。GenericUDF框架知识和处理这类问题。通过继承标准的UDF确实是一个解决方案,不过那样就需要针对如此多的输入类型重载众多的evaluate方法,这样显得非常麻烦。而GenericUDF将会以编辑的方式检查输入的数据类型,然后做出合适的反馈。

我们以普通import语句的细目列表开始这个代码:

    package org.apache.hadoop.hive.q1.udf.generic;
    import org.apache.hadoop.hive.q1.exec.Description;
    import org.apache.hadoop.hive.q1.exec.UDFArgumentException;
    import org.apache.hadoop.hive.q1.exec.UDFArgumentLengthException;
    import org.apache.hadoop.hive.q1.exec.UDFArgumenTypeException;
    import org.apache.hadoop.hive.q1.metadata.HiveException;
    import org.apache.hadoop.hive.q1.udf.generic.GenericUDF;
    import org.apache.hadoop.hive.q1.udf.generic.GenericUDFUtils;
    import org.apache.hadoop.hive.serde2.objectinspector.objectInspector;

现在需要这个类继承GenericUDF,然后开发这个类通常需要实现的方法。其中initialize()方法会被输入的每个参数调用,并最终传入方法的类型是不合法的,这时用户同样可以向控制抛出一个Exception异常信息。returnOIResolver是一个内置的类,其通过获取非null的变量的类型并使用这个数据类型来确定返回值类型:


public class GenericUDFNv1 extended GenericUDF{
    private GenericUDFUtils.ReturnObjectInspectorResolver returnOIRsolver;
         private ObjectInspector[] argumentOIs;
         @Override
         public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException{
         arhumentOIs =arguments;
         if(arguments.length !=2){
             throw new UDFArgumenLengthException("The operator 'NVL' accepts 2 arguments.");
             }
         returnOIRsolver=new GenericUDFUtils.ReturnObjectInspectorResolver(true);
         if(!(returnOIRsolver.update(arguments[0])&&returnOIRsolver.update(arguments[1]))){
             throw new UDFArgumenTypeException(2,"The 1st and 2nd args of function NVL"
                  +"should have the same type,but they are differet:\""+arguments[0].getTypeName()
                  +"\"and \""+arguments[1].getTypeName()+"\"");
             }
              return returnOIRsolver.get();
           }
          .....
     }

方法evaluate的输入是一个DeferredObject对象数组,而initialize方法中创建的returnOIResolver对象就是用于从DeferredObjects对象中获取到值。在这种情况下,这个函数将会返回第一个非null值:


  @Override
    public Object evaluate(DeferredObject[] arguments) throws HiveException{
         Object retVal=returnOIRsolver.convertIfNecessary(arguments[0].get(),argumentOIs[0]);
         if(retVal == null){
         retVal = returnOIRsolver.convertIfNecessary(arguments[1].get(),argumentOIs[1]);
                }
               return retVal;
           }
    ......
最后一个实现的方法就是getDisplayString(),其中于Hadoop task内部,在使用到这个函数来展示调试信息:
  @Override
     public String getDisplayString(string[] childred){
         StringBuilder sb = new StringBuilder();
         sb.append("if");
         sb.append(children[0]);
         sb.append("is null");
         sb.append("returns");
         sb.append(children[1]);
         return sb.toString();
         }
      }
为了展示这个UDF的通用处理特性,下面的查询中对其调用了多次,每次都传入不同类型的参数,正如下面例子所展示的:
   hive>ADD JAR /path/to/jar.jar

    hive>create temporary function nvl

    >as ‘org.apache.hadoop.hive.q1.udf.generic.GenericUDFNvl’;

    hive>select nvl (1,2) as col1,nvl(null,5) as col2,nvl(null,”stuff”) as col3 from src limit 1;

    1   5   stuff

【Nginx】日志格式

在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃香菜的斌斌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值