欢迎投稿

今日深度:

Hive 操作,

Hive 操作,


(一)表操作
Hive 和 Mysql 的表操作语句类似,如果熟悉 Mysql,学习Hive 的表操作就非常容易了,下面对 Hive 的表操作进行深入讲解。
(1)先来创建一个表名为student1的内部表
hive> CREATE TABLE IF NOT EXISTS student1
> (sno INT,sname STRING,age INT,sex STRING)
> ROW FORMAT DELIMITED
> FIELDS TERMINATED BY ‘\t’
> STORED AS TEXTFILE;
建表规则如下:
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
[(col_name data_type [COMMENT col_comment], …)]
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [COMMENT col_comment], …)]
[CLUSTERED BY (col_name, col_name, …)
[SORTED BY (col_name [ASC|DESC], …)] INTO num_buckets BUCKETS]
[ROW FORMAT row_format]
[STORED AS file_format]
[LOCATION hdfs_path]
•CREATE TABLE 创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常;用户可以用 IF NOT EXIST 选项来忽略这个异常
•EXTERNAL 关键字可以让用户创建一个外部表,在建表的同时指定一个指向实际数据的路径(LOCATION)
•LIKE 允许用户复制现有的表结构,但是不复制数据
•COMMENT可以为表与字段增加描述
•ROW FORMAT DELIMITED [FIELDS TERMINATED BY char] [COLLECTION ITEMS TERMINATED BY char]
[MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]
| SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value, property_name=property_value, …)]
用户在建表的时候可以自定义 SerDe 或者使用自带的 SerDe。如果没有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED,将会使用自带的 SerDe。在建表的时候,用户还需要为表指定列,用户在指定表的列的同时也会指定自定义的 SerDe,Hive 通过 SerDe 确定表的具体的列的数据。
•STORED AS
SEQUENCEFILE
| TEXTFILE
| RCFILE
| INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname
如果文件数据是纯文本,可以使用 STORED AS TEXTFILE。如果数据需要压缩,使用 STORED AS SEQUENCE 。
(2)创建外部表
hive> CREATE EXTERNAL TABLE IF NOT EXISTS student2
> (sno INT,sname STRING,age INT,sex STRING)
> ROW FORMAT DELIMITED
> FIELDS TERMINATED BY ‘\t’
> STORED AS TEXTFILE
> LOCATION ‘/user/external’;
OK
Time taken: 0.331 seconds
hive> show tables;
OK
student1
student2
Time taken: 0.06 seconds, Fetched: 12 row(s)
(3)删除表
首先创建一个表名为test1的表
hive> CREATE TABLE IF NOT EXISTS test1
> (id INT,name STRING);
OK
Time taken: 0.07 seconds
然后查看一下是否有test1表
hive> SHOW TABLES;
OK
student1
student2
test1
Time taken: 0.042 seconds, Fetched: 12 row(s)
用命令删test1表
hive> DROP TABLE test1;
OK
Time taken: 0.191 seconds
查看test1表是否删除
hive> SHOW TABLES;
OK
student1
student2
Time taken: 0.027 seconds, Fetched: 11 row(s)
(4)修改表的结构,比如为表增加字段
首先看一下student1表的结构
hive> DESC student1;
OK
sno int
sname string
age int
sex string
Time taken: 0.886 seconds, Fetched: 4 row(s)
为表student1增加两个字段
hive> ALTER TABLE student1 ADD COLUMNS
> (address STRING,grade STRING);
OK
Time taken: 0.241 seconds
再查看一下表的结构,看是否增加
hive> DESC student1;
OK
sno int
sname string
age int
sex string
address string
grade string
Time taken: 0.154 seconds, Fetched: 6 row(s)
(5)修改表名student1为student3
hive> ALTER TABLE student1 RENAME TO student3;
OK
Time taken: 0.172 seconds
查看一下
hive> SHOW TABLES;
OK
student2
student3
Time taken: 0.088 seconds, Fetched: 11 row(s)
下面我们再改回来
hive> ALTER TABLE student3 RENAME TO student1;
OK
Time taken: 0.153 seconds
查看一下
hive> SHOW TABLES;
OK
student1
student2
Time taken: 0.064 seconds, Fetched: 11 row(s)
(6)创建和已知表相同结构的表
hive> CREATE TABLE copy_student1 LIKE student1;
OK
Time taken: 1.109 seconds
查看一下
hive> SHOW TABLES;
OK
copy_student1
student1
student2
Time taken: 0.083 seconds, Fetched: 12 row(s)
2、加入导入数据的方法,(数据里可以包含重复记录),只有导入了数据,才能供后边的查询使用
(1)加载本地数据load
首先看一下表的结构
hive> DESC student1;
OK
sno int
sname string
age int
sex string
address string
grade string
Time taken: 1.018 seconds, Fetched: 6 row(s)
创建/home/hadoop/data目录,并在该目录下创建student1.txt文件,添加如下内容
201501001 张三 22 男 北京 大三
201501003 李四 23 男 上海 大二
201501004 王娟 22 女 广州 大三
201501010 周王 24 男 深圳 大四
201501011 李红 23 女 北京 大三
加载数据到student1表中
hive> LOAD DATA LOCAL INPATH ‘/home/hadoop/data/student1.txt’ INTO TABLE student1;
Loading data to table default.student1
Table default.student1 stats: [numFiles=1, numRows=0, totalSize=191, rawDataSize=0]
OK
Time taken: 0.766 seconds
查看是否加载成功
hive> SELECT * FROM student1;
OK
201501001 张三 22 男 北京 大三
201501003 李四 23 男 上海 大二
201501004 王娟 22 女 广州 大三
201501010 周王 24 男 深圳 大四
201501011 李红 23 女 北京 大三
Time taken: 0.512 seconds, Fetched: 5 row(s)
(2)加载hdfs中的文件
首先将文件student1.txt上传到hdfs文件系统对应目录上
[hadoop@djt01 hadoop]$ hadoop fs -put /home/hadoop/data/student1.txt /user/hive
16/05/16 17:15:43 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform… using builtin-java classes where applicable
[hadoop@djt01 hadoop]$ hadoop fs -ls /user/hive
16/05/16 17:16:15 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform… using builtin-java classes where applicable
Found 2 items
-rw-r–r-- 3 hadoop supergroup 191 2016-05-19 03:27 /user/hive/student1.txt
drwxr-xr-x - hadoop supergroup 0 2016-05-19 02:46 /user/hive/warehouse
加载hdfs中的文件数据到copy_student1表中
hive> LOAD DATA INPATH ‘/user/hive/student1.txt’ INTO TABLE copy_student1;
Loading data to table default.copy_student1
Table default.copy_student1 stats: [numFiles=1, totalSize=191]
OK
Time taken: 1.354 seconds
查看是否加载成功
hive> SELECT * FROM copy_student1;
OK
201501001 张三 22 男 北京 大三
201501003 李四 23 男 上海 大二
201501004 王娟 22 女 广州 大三
201501010 周王 24 男 深圳 大四
201501011 李红 23 女 北京 大三
Time taken: 0.44 seconds, Fetched: 5 row(s)
(3)表插入数据(单表插入、多表插入)
1)单表插入
首先创建一个表copy_student2,表结构和student1相同
hive> CREATE TABLE copy_student2 LIKE student1;
OK
Time taken: 0.586 seconds
查看一下是否创建成功
hive> SHOW TABLES;
OK
copy_student1
copy_student2
student1
student2
Time taken: 0.073 seconds, Fetched: 13 row(s)
看一下copy_student2表的表结构
hive> DESC copy_student2;
OK
sno int
sname string
age int
sex string
address string
grade string
Time taken: 0.121 seconds, Fetched: 6 row(s)
把表student1中的数据插入到copy_student2表中
hive> INSERT OVERWRITE TABLE copy_student2 SELECT * FROM student1;
查看数据是否插入
hive> SELECT * FROM copy_student2;
OK
201501001 张三 22 男 北京 大三
201501003 李四 23 男 上海 大二
201501004 王娟 22 女 广州 大三
201501010 周王 24 男 深圳 大四
201501011 李红 23 女 北京 大三
Time taken: 0.107 seconds, Fetched: 5 row(s)
2)多表插入
先创建两个表
hive> CREATE TABLE copy_student3 LIKE student1; OK
Time taken: 0.622 seconds
hive> CREATE TABLE copy_student4 LIKE student1;
OK
Time taken: 0.162 seconds
向多表插入数据
hive> FROM student1
> INSERT OVERWRITE TABLE copy_student3
> SELECT *
> INSERT OVERWRITE TABLE copy_student4
> SELECT *;
查看结果
hive> SELECT * FROM copy_student3;
OK
201501001 张三 22 男 北京 大三
201501003 李四 23 男 上海 大二
201501004 王娟 22 女 广州 大三
201501010 周王 24 男 深圳 大四
201501011 李红 23 女 北京 大三
Time taken: 0.103 seconds, Fetched: 5 row(s)
hive> SELECT * FROM copy_student4;
OK
201501001 张三 22 男 北京 大三
201501003 李四 23 男 上海 大二
201501004 王娟 22 女 广州 大三
201501010 周王 24 男 深圳 大四
201501011 李红 23 女 北京 大三
Time taken: 0.071 seconds, Fetched: 5 row(s)
3、有关表的内容的查询
(1)查表的所有内容
hive> SELECT * FROM student1;
OK
201501001 张三 22 男 北京 大三
201501003 李四 23 男 上海 大二
201501004 王娟 22 女 广州 大三
201501010 周王 24 男 深圳 大四
201501011 李红 23 女 北京 大三
Time taken: 1.201 seconds, Fetched: 5 row(s)
(2)查表的某个字段的属性
hive> SELECT sname FROM student1;
OK
张三
李四
王娟
周王
李红
Time taken: 1.22 seconds, Fetched: 5 row(s)
(3)where条件查询
hive> SELECT * FROM student1 WHERE sno>201501004 AND address=“北京”;
OK
201501011 李红 23 女 北京 大三
Time taken: 0.873 seconds, Fetched: 1 row(s)
(4)all和distinct的区别(这就要求表中要有重复的记录,或者某个字段要有重复的数据)
hive> SELECT ALL age,grade FROM student1;
OK
22 大三
23 大二
22 大三
24 大四
23 大三
Time taken: 0.448 seconds, Fetched: 5 row(s)
hive> SELECT age,grade FROM student1;
OK
22 大三
23 大二
22 大三
24 大四
23 大三
Time taken: 0.072 seconds, Fetched: 5 row(s)
hive> SELECT DISTINCT age,grade FROM student1;
OK
22 大三
23 大三
23 大二
24 大四
Time taken: 127.397 seconds, Fetched: 4 row(s)
hive> SELECT DISTINCT age FROM student1;
OK
22
23
24
Time taken: 106.21 seconds, Fetched: 3 row(s)
(5)limit限制查询
hive> SELECT * FROM student1 LIMIT 4;
OK
201501001 张三 22 男 北京 大三
201501003 李四 23 男 上海 大二
201501004 王娟 22 女 广州 大三
201501010 周王 24 男 深圳 大四
Time taken: 0.253 seconds, Fetched: 4 row(s)
(6) GROUP BY 分组查询
group by 分组查询在数据统计时比较常用,接下来讲解 group by 的使用。

4、join的结果
LEFT,RIGHT,FULL OUTER连接存在是为了提供ON语句在没有匹配时的更多控制。例如,这个查询:
hive> SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key)
将会返回a的每一行。如果b.key等于a.key,输出将是a.val,b.val,如果a没有和b.key匹配,输出的行将是 a.val,NULL。如果b的行没有和a.key匹配上,将被抛弃。语法"FROM a LEFT OUTER JOIN b"必须写在一行,为了理解它如何工作——这个查询,a是b的左边,a的所有行会被保持;RIGHT OUTER JOIN将保持b的所有行, FULL OUTER JOIN将会保存a和b的所有行。OUTER JOIN语义应该符合标准的SQL规范。
5、join的过滤
Joins发生在where字句前,所以,如果要限制join的输出,需要写在where字句,否则写在JOIN字句。现在讨论的一个混乱的大点,就是分区表
hive> SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key) WHERE a.ds=‘2009-07-07’ AND b.ds=‘2009-07-07’
将会连接a和b,产生a.val和b.val的列表。WHERE字句,也可以引用join的输出列,然后过滤他们。 但是,无论何时JOIN的行找到a的key,但是找不到b的key时,b的所有列会置成NULL,包括ds列。这就是说,将过滤join输出的所有行,包括没有合法的b.key的行。然后你会在LEFT OUTER的要求扑空。 也就是说,如果你在WHERE字句引用b的任何列,LEFT OUTER的部分join结果是不相关的。所以,当外连接时,使用这个语句
hive> SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key AND b.ds=‘2009-07-07’ AND a.ds=‘2009-07-07’;
join的输出会预先过滤,然后你不用对有a.key而没有b.key的行做过滤。RIGHT和FULL join也是一样的逻辑。
6、join的顺序
join是不可替换的,连接是从左到右,不管是LEFT或RIGHT join。
hive> SELECT a.val1, a.val2, b.val, c.val FROM a JOIN b ON (a.key = b.key) LEFT OUTER JOIN c ON (a.key = c.key)
首先,连接a和b,扔掉a和b中没有匹配的key的行。结果表再连接c。这提供了直观的结果,如果有一个键都存在于A和C,但不是B:完整行(包括 a.val1,a.val2,a.key)会在"a jOIN b"步骤,被丢弃,因为它不在b中。结果没有a.key,所以当它和c做LEFT OUTER JOIN,c.val也无法做到,因为没有c.key匹配a.key(因为a的行都被移除了)。类似的,RIGHT OUTER JOIN(替换为LEFT),我们最终会更怪的效果,NULL, NULL, NULL, c.val。因为尽管指定了join key是a.key=c.key,我们已经在第一个JOIN丢弃了不匹配的a的所有行。
为了达到更直观的效果,相反,我们应该从
hive> FROM c LEFT OUTER JOIN a ON (c.key = a.key) LEFT OUTER JOIN b ON (c.key = b.key).
LEFT SEMI JOIN实现了相关的IN / EXISTS的子查询语义的有效途径。由于Hive目前不支持IN / EXISTS的子查询,所以你可以用 LEFT SEMI JOIN 重写你的子查询语句。LEFT SEMI JOIN 的限制是, JOIN 子句中右边的表只能在 ON 子句中设置过滤条件,在 WHERE 子句、SELECT 子句或其他地方过滤都不行。
hive> SELECT a.key, a.value FROM a WHERE a.key in (SELECT b.key FROM B);
可以重写为
hive> SELECT a.key, a.val FROM a LEFT SEMI JOIN b on (a.key = b.key)
7、map 端 join
但如果所有被连接的表是小表,join可以被转换为只有一个map任务。查询是
hive> SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM a join b on a.key = b.key

不需要reducer。对于每一个mapper,A和B已经被完全读出。限制是a FULL/RIGHT OUTER JOIN b不能使用。
如果表在join的列已经分桶了,其中一张表的桶的数量,是另一个表的桶的数量的整倍,那么两者可以做桶的连接。如果A有4个桶,表B有4个桶,下面的连接:
hive> SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM a join b on a.key = b.key

只能在mapper工作。为了为A的每个mapper完整抽取B。对于上面的查询,mapper处理A的桶1,只会抽取B的桶1,这不是默认行为,要使用以下参数:
hive> set hive.optimize.bucketmapjoin = true;
如果表在join的列经过排序,分桶,而且他们有相同数量的桶,可以使用排序-合并 join。每个mapper,相关的桶会做连接。如果A和B有4个桶
hive> SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM A a join B b on a.key = b.key
只能在mapper使用。使用A的桶的mapper,也会遍历B相关的桶。这个不是默认行为,需要配置以下参数:
hive> set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
hive> set hive.optimize.bucketmapjoin = true;
hive> set hive.optimize.bucketmapjoin.sortedmerge = true;
Hive 内置操作符与函数
字符串函数
1)字符串长度函数:length
语法: length(string A)
返回值: int
说明:返回字符串A的长度
举例:
hive> select length(‘abcedfg’) from dual;
7
2)字符串反转函数:reverse
语法: reverse(string A)
返回值: string
说明:返回字符串A的反转结果
举例:
hive> select reverse(‘abcedfg’) from dual;
gfdecba
3)字符串连接函数:concat
语法: concat(string A, string B…)
返回值: string
说明:返回输入字符串连接后的结果,支持任意个输入字符串
举例:
hive> select concat(‘abc’,'def’,'gh’) from dual;
abcdefgh
4)带分隔符字符串连接函数:concat_ws
语法: concat_ws(string SEP, string A, string B…)
返回值: string
说明:返回输入字符串连接后的结果,SEP表示各个字符串间的分隔符
举例:
hive> select concat_ws(‘,’,'abc’,'def’,'gh’) from dual;
abc,def,gh
5)字符串截取函数:substr,substring
语法: substr(string A, int start),substring(string A, int start)
返回值: string
说明:返回字符串A从start位置到结尾的字符串
举例:
hive> select substr(‘abcde’,3) from dual;
cde
hive> select substring(‘abcde’,3) from dual;
cde
hive> select substr(‘abcde’,-1) from dual; (和ORACLE相同)
e
6)字符串截取函数:substr,substring
语法: substr(string A, int start, int len),substring(string A, int start, int len)
返回值: string
说明:返回字符串A从start位置开始,长度为len的字符串
举例:
hive> select substr(‘abcde’,3,2) from dual;
cd
hive> select substring(‘abcde’,3,2) from dual;
cd
hive>select substring(‘abcde’,-2,2) from dual;
de
7)字符串转大写函数:upper,ucase
语法: upper(string A) ucase(string A)
返回值: string
说明:返回字符串A的大写格式
举例:
hive> select upper(‘abSEd’) from dual;
ABSED
hive> select ucase(‘abSEd’) from dual;
ABSED
8)字符串转小写函数:lower,lcase
语法: lower(string A) lcase(string A)
返回值: string
说明:返回字符串A的小写格式
举例:
hive> select lower(‘abSEd’) from dual;
absed
hive> select lcase(‘abSEd’) from dual;
absed
9)去空格函数:trim
语法: trim(string A)
返回值: string
说明:去除字符串两边的空格
举例:
hive> select trim(‘ abc ‘) from dual;
abc
10)左边去空格函数:ltrim
语法: ltrim(string A)
返回值: string
说明:去除字符串左边的空格
举例:
hive> select ltrim(‘ abc ‘) from dual;
abc
11)右边去空格函数:rtrim
语法: rtrim(string A)
返回值: string
说明:去除字符串右边的空格
举例:
hive> select rtrim(‘ abc ‘) from dual;
abc

集合统计函数

复合类型操作

自定义UDF
package whut;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
//UDF是作用于单个数据行,产生一个数据行
//用户必须要继承UDF,且必须至少实现一个evalute方法,该方法并不在UDF中
//但是Hive会检查用户的UDF是否拥有一个evalute方法
public class Strip extends UDF{
private Text result=new Text();
//自定义方法
public Text evaluate(Text str)
{
if(str==null)
return null;
result.set(StringUtils.strip(str.toString()));
return result;
}
public Text evaluate(Text str,String stripChars)
{
if(str==null)
return null;
result.set(StringUtils.strip(str.toString(),stripChars));
return result;
}
}

注意事项:
1、一个用户UDF必须继承org.apache.hadoop.hive.ql.exec.UDF;
2、一个UDF必须要包含有evaluate()方法,但是该方法并不存在于UDF中。evaluate的参数个数以及类型都是用户自己定义的。在使用的时候,Hive会调用UDF的evaluate()方法。

自定义UDAF找到最大值

package whut;
import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
import org.apache.hadoop.io.IntWritable;
//UDAF是输入多个数据行,产生一个数据行
//用户自定义的UDAF必须是继承了UDAF,且内部包含多个实现了exec的静态类
public class MaxiNumber extends UDAF{
public static class MaxiNumberIntUDAFEvaluator implements UDAFEvaluator{
//最终结果
private IntWritable result;
//负责初始化计算函数并设置它的内部状态,result是存放最终结果的
@Override
public void init() {
result=null;
}
//每次对一个新值进行聚集计算都会调用iterate方法
public boolean iterate(IntWritable value)
{
if(value==null)
return false;
if(result==null)
result=new IntWritable(value.get());
else
result.set(Math.max(result.get(), value.get()));
return true;
}
//Hive需要部分聚集结果的时候会调用该方法
//会返回一个封装了聚集计算当前状态的对象
public IntWritable terminatePartial()
{
return result;
}
//合并两个部分聚集值会调用这个方法
public boolean merge(IntWritable other)
{
return iterate(other);
}
//Hive需要最终聚集结果时候会调用该方法
public IntWritable terminate()
{
return result;
}
}
}

注意事项:

1、用户的UDAF必须继承了org.apache.hadoop.hive.ql.exec.UDAF。

2、用户的UDAF必须包含至少一个实现了org.apache.hadoop.hive.ql.exec的静态类,诸如常见的实现了 UDAFEvaluator。

3、一个计算函数必须实现的5个方法的具体含义如下:

init():主要是负责初始化计算函数并且重设其内部状态,一般就是重设其内部字段。一般在静态类中定义一个内部字段来存放最终的结果。

iterate():每一次对一个新值进行聚集计算时候都会调用该方法,计算函数会根据聚集计算结果更新内部状态。当输入值合法或者正确计算了,则就返回true。

terminatePartial():Hive需要部分聚集结果的时候会调用该方法,必须要返回一个封装了聚集计算当前状态的对象。

merge():Hive进行合并一个部分聚集和另一个部分聚集的时候会调用该方法。

terminate():Hive最终聚集结果的时候就会调用该方法。计算函数需要把状态作为一个值返回给用户。

4、部分聚集结果的数据类型和最终结果的数据类型可以不同。

Hive 的权限控制
Hive从0.10可以通过元数据控制权限。但是Hive的权限控制并不是完全安全的。基本的授权方案的目的是防止用户不小心做了不合适的事情。
为了使用Hive的授权机制,有两个参数必须在hive-site.xml中设置:
< property>
< name>hive.security.authorization.enabled< /name>
< value>true< /value>
< description>enable or disable the hive client authorization< /description>
< /property>
< property>
< name>hive.security.authorization.createtable.owner.grants< /name>
< value>ALL< /value>
< description>the privileges automatically granted to the owner whenever a table gets created. An example like “select,drop” will grant select and drop privilege to the owner of the table< /description>< /property>
hive.security.authorization.enabled //参数是开启权限验证,默认为 false。
hive.security.authorization.createtable.owner.grants //参数是指表的创建者对表拥有所有权限。

角色的创建和删除
Hive 中的角色定义与关系型数据库中角色的定义类似,它是一种机制,给予那些没有适当权限的用户分配一定的权限。

角色的授权和撤销

Hive 支持的权限控制。

超级管理权限
HIVE本身有权限管理功能,需要通过配置开启。
< property>
< name>hive.metastore.authorization.storage.checks< /name>
< value>true< /value>< /property>
< property>
< name>hive.metastore.execute.setugi< /name>
< value>false< /value>< /property>
< property>
< name>hive.security.authorization.enabled< /name>
< value>true< /value>< /property>
< property>
< name>hive.security.authorization.createtable.owner.grants< /name>
< value>ALL< /value>< /property>
其中hive.security.authorization.createtable.owner.grants设置成ALL表示用户对自己创建的表是有所有权限的(这样是比较合理地)。
开启权限控制有Hive的权限功能还有一个需要完善的地方,那就是“超级管理员”。 Hive中没有超级管理员,任何用户都可以进行Grant/Revoke操作,为了完善“超级管理员”,必须添加hive.semantic.analyzer.hook配置,并实现自己的权限控制类。
编写权限控制类,代码如下所示。
package com.xxx.hive;
import org.apache.hadoop.hive.ql.parse.ASTNode;
import org.apache.hadoop.hive.ql.parse.AbstractSemanticAnalyzerHook;
import org.apache.hadoop.hive.ql.parse.HiveParser;
import org.apache.hadoop.hive.ql.parse.HiveSemanticAnalyzerHookContext;
import org.apache.hadoop.hive.ql.parse.SemanticException;
import org.apache.hadoop.hive.ql.session.SessionState;
/**
* 设置Hive超级管理员 *
* @author
* @version $Id: AuthHook.java,v 0.1 2013-6-13 下午3:32:12 yinxiu Exp $
*/
public class AuthHook extends AbstractSemanticAnalyzerHook {
private static String admin = “admin”;
@Override 27 public ASTNode preAnalyze(HiveSemanticAnalyzerHookContext context, 28 ASTNode ast) throws SemanticException {
switch (ast.getToken().getType()) {
case HiveParser.TOK_CREATEDATABASE:
case HiveParser.TOK_DROPDATABASE:
case HiveParser.TOK_CREATEROLE:
case HiveParser.TOK_DROPROLE:
case HiveParser.TOK_GRANT:
case HiveParser.TOK_REVOKE:
case HiveParser.TOK_GRANT_ROLE:
case HiveParser.TOK_REVOKE_ROLE:
String userName = null;
if (SessionState.get() != null && SessionState.get().getAuthenticator() != null) {
userName = SessionState.get().getAuthenticator().getUserName();
}
if (!admin.equalsIgnoreCase(userName)) {
throw new SemanticException(userName + " can’t use ADMIN options, except " + admin + “.”);
}
break;
default:
break;
}
return ast;
}
}
添加了控制类之后还必须添加下面的配置:
< property>
< name>hive.semantic.analyzer.hook< /name>
< value>com.xxx.AuthHook< /value> < /property>
若有使用hiveserver,hiveserver必须重启。
至此,只有admin用户可以进行Grant/Revoke操作。
权限操作示例:
grant select on database default to user xiaojiang;
revoke all on database default from user xiaojiang;
show grant user xiaojiang on database default;
Hive与JDBC示例
在使用 JDBC 开发 Hive 程序时, 必须首先开启 Hive 的远程服务接口。使用下面命令进行开启:
hive -service hiveserver & //Hive低版本提供的服务是:hiveserver
hive --service hiveserver2 & //Hive0.11.0以上版本提供了的服务是:hiveserver2
使用的hive1.0版本,故使用hiveserver2服务,下面我使用 Java 代码通过JDBC连接Hiveserver。

hive性能调优
(一)Hadoop 计算框架的特性
什么是数据倾斜
由于数据的不均衡原因,导致数据分布不均匀,造成数据大量的集中到一点,造成数据热点
Hadoop框架的特性
不怕数据大,怕数据倾斜
jobs数比较多的作业运行效率相对比较低,比如即使有几百行的表,如果多次关联多次汇总,产生十几个jobs,耗时很长。原因是map reduce作业初始化的时间是比较长的sum,count,max,min等UDAF,不怕数据倾斜问题,hadoop在map端的汇总合并优化,使数据倾斜不成问题,count(distinct ),在数据量大的情况下,效率较低,因为count(distinct)是按group by 字段分组,按distinct字段排序,一般这种分布方式是很倾斜的
(二)优化的常用手段
解决数据倾斜问题
减少job数
设置合理的map reduce的task数,能有效提升性能。
了解数据分布,自己动手解决数据倾斜问题是个不错的选择
数据量较大的情况下,慎用count(distinct)。
对小文件进行合并,是行至有效的提高调度效率的方法。
优化时把握整体,单个作业最优不如整体最优。
(三)Hive的数据类型方面的优化
优化原则
按照一定规则分区(例如根据日期)。通过分区,查询的时候指定分区,会大大减少在无用数据上的扫描, 同时也非常方便数据清理。
合理的设置Buckets。在一些大数据join的情况下,map join有时候会内存不够。如果使用Bucket Map Join的话,可以只把其中的一个bucket放到内存中,内存中原来放不下的内存表就变得可以放下。这需要使用buckets的键进行join的条件连结,并且需要如下设置
set hive.optimize.bucketmapjoin = true
(四)Hive的操作方面的优化
(1)全排序
Hive的排序关键字是SORT BY,它有意区别于传统数据库的ORDER BY也是为了强调两者的区别–SORT BY只能在单机范围内排序
(2)怎样做笛卡尔积
当Hive设定为严格模式(hive.mapred.mode=strict)时,不允许在HQL语句中出现笛卡尔积
MapJoin是的解决办法
MapJoin,顾名思义,会在Map端完成Join操作。这需要将Join操作的一个或多个表完全读入内存
MapJoin的用法是在查询/子查询的SELECT关键字后面添加/*+ MAPJOIN(tablelist) */

提示优化器转化为MapJoin(目前Hive的优化器不能自动优化MapJoin)
其中tablelist可以是一个表,或以逗号连接的表的列表。tablelist中的表将会读入内存,应该将小表写在这里
在大表和小表做笛卡尔积时,规避笛卡尔积的方法是,给Join添加一个Join key,原理很简单:将小表扩充一列join key,并将小表的条目复制数倍,join key各不相同;将大表扩充一列join key为随机数
(3)控制Hive的Map数
通常情况下,作业会通过input的目录产生一个或者多个map任务
主要的决定因素有: input的文件总个数,input的文件大小,集群设置的文件块大小(目前为128M, 可在hive中通过set dfs.block.size;命令查看到,该参数不能自定义修改)
是不是map数越多越好
答案是否定的。如果一个任务有很多小文件(远远小于块大小128m),则每个小文件也会被当做一个块,用一个map任务来完成,而一个map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。而且,同时可执行的map数是受限的。
是不是保证每个map处理接近128m的文件块,就高枕无忧了?
答案也是不一定。比如有一个127m的文件,正常会用一个map去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,如果map处理的逻辑比较复杂,用一个map任务去做,肯定也比较耗时。
针对上面的问题3和4,我们需要采取两种方式来解决:即减少map数和增加map数;
举例
a) 假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块(6个128m的块和1个12m的块),从而产生7个map数
b)假设input目录下有3个文件a,b,c,大小分别为10m,20m,130m,那么hadoop会分隔成4个块(10m,20m,128m,2m),从而产生4个map数
即如果文件大于块大小(128m),那么会拆分,如果小于块大小,则把该文件当成一个块
(4)怎样决定reducer个数
Hadoop MapReduce程序中,reducer个数的设定极大影响执行效率
不指定reducer个数的情况下,Hive会猜测确定一个reducer个数,基于以下两个设定:
参数1:hive.exec.reducers.bytes.per.reducer(默认为1G)
参数2 :hive.exec.reducers.max(默认为999)
计算reducer数的公式
N=min(参数2,总输入数据量/参数1)
依据Hadoop的经验,可以将参数2设定为0.95*(集群中TaskTracker个数)
reduce个数并不是越多越好
同map一样,启动和初始化reduce也会消耗时间和资源;
另外,有多少个reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题
什么情况下只有一个reduce
很多时候你会发现任务中不管数据量多大,不管你有没有设置调整reduce个数的参数,任务中一直都只有一个reduce任务;
其实只有一个reduce任务的情况,除了数据量小于
hive.exec.reducers.bytes.per.reducer参数值的情况外,还有以下原因:
a)没有group by的汇总
b)用了Order by
(5)合并 MapReduce 操作
Multi-group by
Multi-group by是Hive的一个非常好的特性,它使得Hive中利用中间结果变得非常方便
FROM log
insert overwrite table test1 select log.id group by log.id
insert overwrite table test2 select log.name group by log.name
上述查询语句使用了Multi-group by特性连续group by了2次数据,使用不同的group by key。这一特性可以减少一次MapReduce操作。
Bucket 与 Sampling
Bucket是指将数据以指定列的值为key进行hash,hash到指定数目的桶中。这样就可以支持高效采样了
Sampling可以在全体数据上进行采样,这样效率自然就低,它还是要去访问所有数据。而如果一个表已经对某一列制作了bucket,就可以采样所有桶中指定序号的某个桶,这就减少了访问量。
如下例所示就是采样了test中32个桶中的第三个桶。
SELECT * FROM test 、、、TABLESAMPLE(BUCKET 3 OUT OF 32);

(6)JOIN 原则
在使用写有 Join 操作的查询语句时有一条原则:应该将条目少的表/子查询放在 Join 操作符的左边
原因是在 Join 操作的 Reduce 阶段,位于 Join 操作符左边的表的内容会被加载进内存,将条目少的表放在左边,可以有效减少发生 OOM 错误的几率
Map Join
Join 操作在 Map 阶段完成,不再需要Reduce,前提条件是需要的数据在 Map 的过程中可以访问到
例如:
INSERT OVERWRITE TABLE phone_traffic
SELECT /*+ MAPJOIN(phone_location) */ l.phone,p.location,l.traffic from phone_location p join log l on (p.phone=l.phone)

相关的参数为:
hive.join.emit.interval = 1000 How many rows in the right-most join operand Hive should buffer before emitting the join result.
hive.mapjoin.size.key = 10000
hive.mapjoin.cache.numrows = 10000
(7)Group By
Map 端部分聚合
并不是所有的聚合操作都需要在 Reduce 端完成,很多聚合操作都可以先在 Map 端进行部分聚合,最后在 Reduce 端得出最终结果
基于 Hash
参数包括:
hive.map.aggr = true 是否在 Map 端进行聚合,默认为 True
hive.groupby.mapaggr.checkinterval = 100000 在 Map 端进行聚合操作的条目数目
有数据倾斜的时候进行负载均衡
hive.groupby.skewindata = false
当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。
(8)合并小文件
文件数目过多,会给 HDFS 带来压力,并且会影响处理效率,可以通过合并 Map 和 Reduce 的结果文件来消除这样的影响:
hive.merge.mapfiles = true 是否和并 Map 输出文件,默认为 True
hive.merge.mapredfiles = false 是否合并 Reduce 输出文件,默认为 False
hive.merge.size.per.task = 25610001000 合并文件的大小

Hive 案例分析
这里我们以机顶盒产生的用户收视数据为例,来具体分析如何使用Hive。
1、机顶盒产生的用户原始数据都有一定的格式,包含机顶盒号、收看的频道、收看的节目、收看的时间等信息。
2、用户的原始数据通常不直接交给hive处理,而是需要经过一个清洗和转化的过程。这个过程一般是通过Hadoop 作业来实现,转化成与hive表对应的格式。
这个案例的具体步骤如下:
步骤1:用户数据预处理
通过MapReduce作业将日志转化为固定的格式。
用户的原始数据如下所示。
< GHApp>< WIC cardNum=“1370695139” stbNum=“03111108020232488” date=“2012-09-21” pageWidgetVersion=“1.0”>< A e=“13:55:11” s=“13:50:10” n=“104” t=“1” pi=“789” p="%E5%86%8D%E5%9B%9E%E9%A6%96(21)" sn=“BTV影视” />< /WIC>< /GHApp>
转化之后的数据如下所示,每个字段我们使用"@"分割符号。
1370695139@03111108020232488@2012-09-21@BTV影视@再回首@13:50:10@13:55:11@301
上面的字段分别代表:机顶盒号、用户编号、收看日期、频道、栏目、起始时间、结束时间、收视时长。
步骤2:创建hive表
我们根据对应字段,使用hive创建表。
create table tvdata(cardnum string,stbnum string,date string,sn string,p string ,s string,e string,duration int) row format delimited fields terminated by ‘@’ stored as textfile;
步骤3:将hdfs中的数据导入表中
我们使用以下命令,将hdfs中的数据导入表中。
load data inpath ‘/media/tvdata/part-r-00000’ into table tvdata;
步骤4:编写HQL,分析数据
使用HQL语句,统计每个的频道的人均收视时长。
select sn,sum(duration)/count(*) from tvdata group by sn;
这里我们使用HQL只是从一个角度分析数据,大家可以尝试从多个角度来分析数据。

www.htsjk.Com true http://www.htsjk.com/hive/40864.html NewsArticle Hive 操作, (一)表操作 Hive 和 Mysql 的表操作语句类似,如果熟悉 Mysql,学习Hive 的表操作就非常容易了,下面对 Hive 的表操作进行深入讲解。 (1)先来创建一个表名为student1的内部表...
相关文章
    暂无相关文章
评论暂时关闭