hive变量传递的源码实现

简介:

  用过hive的人都知道,可以通过在cli向hive传递参数,变量等,这里其实是通过下面两个类实现的。

1
2
org.apache.hadoop.hive.ql.processors.SetProcessor类
org.apache.hadoop.hive.ql.parse.VariableSubstitution类

其中SetProcessor类定义了对set 命令的处理,VariableSubstitution类负责把变量值进行转换。

VariableSubstitution用来实现在解析hive命令时把特殊字符进行转换,如果是以!开头的shell命令的话,直接在 CliDriver类的 processCmd方法中做转换

1
2
3
else  if  (cmd_trimmed.startsWith( "!" )) {
       String shell_cmd = cmd_trimmed.substring( 1 );
       shell_cmd =  new  VariableSubstitution().substitute(ss.getConf(), shell_cmd);

其他的命令会在具体的CommandProcessor 实现类中做转换。关于CommandProcessor 类这里简单说下,后面会相信分析:

CommandProcessor 的调用是在在CliDriver类的processLocalCmd 方法中发生的。

1
int  processLocalCmd (String cmd, CommandProcessor proc, CliSessionState ss)

这里传入一个CommandProcessor 的实例,函数中会判断具体的实现类。如果实现类是Driver类(即执行的命令是sql),会调用Driver的run方法。

1
2
3
4
            if  (proc  instanceof  Driver) {
             Driver qp = (Driver) proc;
.....
             ret = qp.run(cmd).getResponseCode();

如果是其他实现类(即执行的命令是set/add/compile等),会调用对应实现类(commandprocessor相关类)的run方法。

下面分析下VariableSubstitution的具体实现:

VariableSubstitution类有两个控制参数

1
2
hive.variable.substitute  控制是否打开Substitution功能,默认是 true
hive.variable.substitute.depth ,控制可以匹配到几层,默认是 40

主要有getSubstitute和substitute方法。

方法的调用顺序是

1
substitute----->getSubstitute

其中substitute 方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public  String substitute ( HiveConf conf, String expr) {    
if  (conf.getBoolVar( ConfVars.HIVEVARIABLESUBSTITUTE)){  //判断hive.variable.substitute是否设置true
       l4j.debug(  "Substitution is on: " +expr);
     else  {
       return  expr;
     }
     if  (expr ==  null ) {
       return  null ;
     }
     Matcher match = varPat.matcher(  "" );
     String eval = expr;
     for ( int  s= 0 ;s<conf.getIntVar( ConfVars.HIVEVARIABLESUBSTITUTEDEPTH); s++) {
       match.reset(eval);
       if  (!match.find()) {     //判断输入的命令是否匹配"\\$\\{[^\\}\\$\u0020]+\\}",如果不匹配直接返回
         return  eval;
       }
       String var = match.group();
       var = var.substring( 2 , var.length()- 1 );  // remove ${ .. }
       String val = getSubstitute(conf, var);
 
       if  (val ==  null ) {
         l4j.debug( "Interpolation result: "  +eval);
         return  eval;  // return literal, no substitution found
       }
       // substitute
       eval = eval.substring( 0 , match.start())+val+eval.substring(match.end());  //完成替换
     }
     throw  new  IllegalStateException( "Variable substitution depth too large: "
                                     + conf.getIntVar(ConfVars.HIVEVARIABLESUBSTITUTEDEPTH) +  " "  + expr);
   }

其中getSubstitute会调用SetProcessor类,来解析命令。

比如,以hiveconf:开头的命令会经过如下的处理:

1
2
3
       if  (var.startsWith( SetProcessor.HIVECONF_PREFIX)){
         val = conf.get(var.substring( SetProcessor.HIVECONF_PREFIX.length()));
       }

但是对于使用命名空间如hiveconf,system,env的,前缀则不可少,hivevar可以不需要前缀。

1
2
3
4
5
6
7
     if  (val ==  null ){
       if (var.startsWith( SetProcessor.HIVEVAR_PREFIX)){   //这里HIVEVAR_PREFIX的值是hivevar:
         val =  SessionState.get().getHiveVariables().get(var.substring( SetProcessor.HIVEVAR_PREFIX.length()));
       else  {
         val = SessionState.get().getHiveVariables().get(var);
       }
     }

这里有个例子:

1
2
set system:testdate= 20140816
select * from chinacache_log where dt >=  '${system:testdate}'   limit  5 ;

1)第一个set命令在经过processLocalCmd 方法处理之后,传入substitute的expr是20140816 (取=号之后的数据)

因为不能匹配到正则,直接回返回。

1
2
3
4
5
String eval = expr;
.....
       if  (!match.find()) { 
         return  eval;
       }

2)第2条sql

1
  select * from xxxx where f1>= '${system:testdate}'

由Driver处理后,传入的expr是

1
select * from peter001 where f1>= '${system:testdate}'

由match.group()匹配到${system:testdate},然后通过

1
var.substring( 2 , var.length()- 1 )

去除掉${},并调用getSubstitute获取设置的变量值,并最终生成一个有效的sql。

最终由

1
eval.substring( 0 , match.start())+val+eval.substring(match.end())

返回的值是

1
select * from peter001 where f1>= '20140816'

完成了变量的替换。


本文转自菜菜光 51CTO博客,原文链接:http://blog.51cto.com/caiguangguang/1541758,如需转载请自行联系原作者

相关文章
|
5月前
|
SQL 分布式计算 数据库
【大数据技术Spark】Spark SQL操作Dataframe、读写MySQL、Hive数据库实战(附源码)
【大数据技术Spark】Spark SQL操作Dataframe、读写MySQL、Hive数据库实战(附源码)
115 0
|
7月前
|
SQL 分布式计算 Java
浅析 hive udaf 的正确编写方式- 论姿势的重要性-系列四-如何直接访问metastore service(附源码)
浅析 hive udaf 的正确编写方式- 论姿势的重要性-系列四-如何直接访问metastore service(附源码)
|
SQL 存储 分布式计算
Hive简介及源码编译
Hive是一个基于Hadoop的数据仓库,可以将结构化数据映射成一张表,并提供类SQL的功能,最初由Facebook提供,使用HQL作为查询接口、HDFS作为存储底层、MapReduce作为执行层,设计目的是让SQL技能良好,但Java技能较弱的分析师可以查询海量数据,2008年facebook把Hive项目贡献给Apache。Hive提供了比较完整的SQL功能(本质是将SQL转换为MapReduce),自身最大的缺点就是执行速度慢。Hive有自身的元数据结构描述,可以使用MySql\ProstgreSql\oracle 等关系型数据库来进行存储,但请注意Hive中的所有数据都存储在HDFS中
363 0
Hive简介及源码编译
|
SQL HIVE
Hive metastore源码阅读(三)
  上次写了hive metastore的partition的生命周期,但是简略概括了下alter_partition的操作,这里补一下alter_partition,因为随着项目的深入,发现它涉及的地方较多,比如insert into 时如果路径存在情况下会调用alter_partition,调用insert overwrite语句时,也会调用该方法,   入口依旧是Hive.
1222 0
|
SQL HIVE
Hive metastore源码阅读(二)
  最近随着项目的深入,发现hive meta有些弊端,就是你会发现它的元数据操作与操作物理集群的代码耦合在一起,非常不利于扩展。比如:在create_table的时候同时进行路径校验及创建,如下代码: 1 if (!TableType.
1437 0
|
SQL Apache 数据库
Hive metastore源码阅读(一)
  不要问我为什么,因为爱,哈哈哈哈。。。进入正题,最近做项目顺带学习了下hive metastore的源码,进行下知识总结。   hive metastore的整体架构如图:      一、组成结构:   如图我们可以看到,hive metastore的组成结构分为 客户端 服务端 ,那么下来我们逐一进行分析:   1、客户端       从代码的角度来看:尼玛太多了。
1526 0
|
5月前
|
SQL 数据采集 数据挖掘
大数据行业应用之Hive数据分析航班线路相关的各项指标
大数据行业应用之Hive数据分析航班线路相关的各项指标
108 1
|
5月前
|
SQL 存储 大数据
【大数据技术Hadoop+Spark】Hive基础SQL语法DDL、DML、DQL讲解及演示(附SQL语句)
【大数据技术Hadoop+Spark】Hive基础SQL语法DDL、DML、DQL讲解及演示(附SQL语句)
88 0