hive变量传递

来源:互联网 发布:数据中心网络拓扑图 编辑:程序博客网 时间:2024/05/24 04:01

源:http://caiguangguang.blog.51cto.com/1652935/1541758

hive 可以通过在cli向hive传递参数,变量等,其实是通过下面两个类实现

1、org.apache.hadoop.hive.ql.processors.SetProcessor类

2、org.apache.hadoop.hive.ql.parse.VariableSubstitution类

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

VaruableSublititution用来实现在解析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的调用是在CliDriver类的processLocalCmd方法中发生的

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方法。



VariableSubtitution的具体实现:

VariableSutitution类有两个控制参数

1
2
hive.variable.substitute  控制是否打开Substitution功能,默认是true
hive.variable.substitute.depth ,控制可以匹配到几层,默认是40
主要有getSubtitute和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'

完成了变量的替换。



0 0