栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

【软件工程实践】Hive研究-Blog1

【软件工程实践】Hive研究-Blog1

【软件工程实践】Hive研究-Blog1

2021SC@SDUSC

研究方向


我负责的是将查询块QB转换成逻辑查询计划(OP Tree)

源码总体介绍

如图所示,这是从Apache官网上下载的3.1.2版本的Hive源码大致结构。

下面我们来大致了解以下各种组件的作用。

hive三个最重要的组件:

1.serde: 这个组件是 hive内置的一些序列化解析类,此组件允许用户自己开发自定义序列化、反序列化文件解析器

2.metaStore: hive的元数据服务器,用来存放数据仓库中所有表和分区的信息,hive元数据建表sql、升级sql脚本都存放在此目录下

3.ql: 此组件用于解析sql生成执行计划(hive核心包,熟读此包,可了解hive执行流程核心)

也就是说,我的研究方向因该着重从ql组件中下手。

其他组件

cli: hive命令的入口,用于处理命令行提交作业

service: 此组件所有对外api接口的服务端(通过thrift实现),可用于其他客户端与hive交互,比如jdbc。

common: hive基础代码库,hive各个组件信息的传递也是有此包HiveConf类来管理。

ant: 此组件包含一些ant任务需要的基础代码

bin: 此组件包涵hive里的所有脚本,包括hivecli的脚本

beeline: HiveServer2提供的一个新的命令行工具Beeline

hcatalog: 是apache开源的对于表和底层数据管理统一服务平台,HCatalog底层依赖于Hive metastore

findbugs: Findbugs是一个在java程序中查找bug的程序,它查找bug模式的实例,也就是可能出错的代码实例,注意Findbugs是检查java字节码,也就是*.class文件。

hwi: hive web页面的接口

shims: shims相关类是用来兼容不同的hadoop和hive版本

llap: 是基于tez的一种近实时查询方案

hive辅助组件
conf: 此目录包涵hive配置文件hive-default.xml、hive-site.xml

data: hive测试所用数据

lib: hive运行期间依赖的jar

更多的组件详细介绍可以阅读Apache Hive官网上的文档。

目标代码


功夫不负有心人,经过大约20分钟的寻找,我最终在代码路径ql/src/java/org/apache/hadoop/hive/ql中找到了我的目标分析代码集合——plan文件夹。顾名思义,该文件夹的作用就是将语句转换为计划,也就是我负责研究的方向。在plan文件夹中,第一个文件夹为mapper文件夹,我们从当中的文件进行一个个的解析。

CachingStatsSource.java文件代码解析

我们首先附上整个java文件的源码。


package org.apache.hadoop.hive.ql.plan.mapper;

import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;

import org.apache.hadoop.hive.ql.exec.Operator;
import org.apache.hadoop.hive.ql.optimizer.signature.OpTreeSignature;
import org.apache.hadoop.hive.ql.stats.OperatorStats;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

public class CachingStatsSource implements StatsSource {


  private final Cache cache;

  public CachingStatsSource(int cacheSize) {
    cache = CacheBuilder.newBuilder().maximumSize(cacheSize).build();
  }

  public void put(OpTreeSignature sig, OperatorStats opStat) {
    cache.put(sig, opStat);
  }

  @Override
  public Optional lookup(OpTreeSignature treeSig) {
    return Optional.ofNullable(cache.getIfPresent(treeSig));
  }

  @Override
  public boolean canProvideStatsFor(Class clazz) {
    if (cache.size() > 0 && Operator.class.isAssignableFrom(clazz)) {
      return true;
    }
    return false;
  }

  @Override
  public void putAll(Map map) {
    for (Entry entry : map.entrySet()) {
      put(entry.getKey(), entry.getValue());
    }
  }

}

开始解析。

方法CachingStatsSource

我们首先来看一下名为CachingStatsSource的方法。

  public CachingStatsSource(int cacheSize) {
    cache = CacheBuilder.newBuilder().maximumSize(cacheSize).build();
  }

这里面包含了一句语法:CacheBuilder.newBuilder().maximunSize(cacheSize).build();
它的作用是什么?经过查阅,我得知cache是用来比如对于同样一次输入不止一次的取值操作时,所使用的缓存。那么这个参数cacheSize就非常显而易见了,它表示的是缓存的容量,当超出maximumSize时就会被回收。相关的,这个maximumSize()方法就是设置最大缓存容量的方法了,也就是说,这整个方法的作用就是设置一个新的缓存块,由传入的参数cacheSize决定该缓存块的大小,之后的所有操作都是基于该缓存块基础上的。

方法put
  public void put(OpTreeSignature sig, OperatorStats opStat) {
    cache.put(sig, opStat);
  }

cache.put();
这是一个什么方法?我们继续查阅相关资料。经过查阅,我们得到如下信息:

那么我们知道了,这个方法就是一个设置键值对的作用,那么整个方法的作用也是如此。

方法lookup
  @Override
  public Optional lookup(OpTreeSignature treeSig) {
    return Optional.ofNullable(cache.getIfPresent(treeSig));
  }

那么,这个Optional.ofNullable()是什么方法呢?
我们查阅资料,发现了该源码:

    
    public static  Optional ofNullable(T value) {
        return value == null ? empty() : of(value);
    }
 
    
    public static Optional empty() {
        @SuppressWarnings("unchecked")
        Optional t = (Optional) EMPTY;
        return t;
    }
 
    
    private static final Optional EMPTY = new Optional<>();
 
    
    private Optional() {
        this.value = null;
    }
 
    
    public T orElse(T other) {
        return value != null ? value : other;
    }

这个方法的意思如下:

1.首先执行ofNullable()方法,如果T对象为空,执行empty()方法;不为空,执行of(value)方法;

2.empty()方法,初始化一个空对象Optional(空对象和null不是一回事哈);

3.of(value)方法,将泛型对象T用于Optional构造方法的参数上,返回一个有值的对象

4.经过上面两步,从而保证了Optional不为null,避免了空指针;

那么,在方法里面的另外一个方法getIfPresent(treeSig)是什么呢?
又经过查阅资料,我知道了他的用法。
getIfPresent(key):从现有的缓存中获取,如果缓存中有key,则返回value,如果没有则返回null。那么整个方法的意思就明了了:先从缓存中看有没有目标"treeSig"对应的值,如果有就返回没有就返回Null,然后再调用Optional.ofNullable()方法返回一个不为空的指针,防止抛出空指针异常的错误导致整个进程奔溃,或许加上try-catch语句可以解决。

canProvideStatsFor方法
  @Override
  public boolean canProvideStatsFor(Class clazz) {
    if (cache.size() > 0 && Operator.class.isAssignableFrom(clazz)) {
      return true;
    }
    return false;
  }

其中,对于cache.size()方法,我们很容易得知该方法时返回cache也就是我们该开始预设的缓冲块的大小。而后面的这个Operator.class.isAssignableFrom()方法就需要查阅资料。查阅资料得知:当前Class对象如果是参数Class对象的父类,父接口,或者是相同,都会返回true。也就是说,如果当传入的Class对象符合要求,才会返回true,也就是相当于提供了一层保险机制,相当于变相的说明了这个方法是部分private的,十分聪明的写法。那么整个方法的意思就清楚了:只有当传入的Class对象为当前Class对象的弗雷,父接口或者相同时,和设置的代码块大小大于0的情况下,才能返回true,否则全部返回false。

putAll方法
  @Override
  public void putAll(Map map) {
    for (Entry entry : map.entrySet()) {
      put(entry.getKey(), entry.getValue());
    }
  }

这里后面的put方法我们在前面已经解释说明过了,这里就不再赘述。我们先来看看整个map.entrySet()方法是一个什么方法。经过查阅资料我们可以得知:该方法返回的是此映射中包含的映射的 Set 视图,我们用一个实例来简单说明它的作用:

import java.util.HashMap;

class Main {
    public static void main(String[] args) {
        // 创建一个 HashMap
        HashMap sites = new HashMap<>();

        // 往 HashMap 添加一些元素
        sites.put(1, "Google");
        sites.put(2, "Runoob");
        sites.put(3, "Taobao");
        System.out.println("sites HashMap: " + sites);

        // 返回映射关系中 set view
        System.out.println("Set View: " + sites.entrySet());
    }
}

该实例的运行结果为:

sites HashMap: {1=Google, 2=Runoob, 3=Taobao}
Set View: [1=Google, 2=Runoob, 3=Taobao]

简单来说,就是把所有的映射关系都呈现出来。
而看起来十分奇怪的语句”Entry entry : map.entrySet()“是什么意思呢?我们再次经过查阅之后,发现这是一个遍历Map的方式。

我们使用实例来说明:

for(Map.Entry me : m.entrySet()) {
    t.append(me.getKey() +  ": " + me.getValue() + "/n");

}

这里的t是一个textarea,m是一个HashMap。

这种遍历Map的方法可以让我们在从Map中取得关键字之后,我们不用每次重复返回到Map中取得相对的值。

如下面是以前的写法:每次都要再从m中读出s所对应的值。

Set keys = m.keySet( );
if(keys != null) 
    for(String s : keys)
        t.append(s + ": " + m.get(s) + "/n");

那么整个方法的作用我们也清楚了:遍历整个map里面的键值对,把键值对放到entry里面。

小结

本周初次开始了对Hive源码的研究,学习到了许多新奇的知识,也感叹到代码设计的巧妙之处。整个类的方法都是围绕cache进行的,对cache的操作非常集中,我们后续转换为查询任务时也会使用到cache,这是非常基础的。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/311202.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号