`
db3
  • 浏览: 12477 次
  • 性别: Icon_minigender_1
  • 来自: 美国
社区版块
存档分类
最新评论

Hive中的ObjectInspector设计

阅读更多
ObjectInspector是Hive中一个咋一看比较令人困惑的概念,当初读Hive源代码时,花了很长时间才理解。 当读懂之后,发现ObjectInspector作用相当大,它解耦了数据使用和数据格式,从而提高了代码的复用程度。 简单的说,ObjectInspector接口使得Hive可以不拘泥于一种特定数据格式,使得数据流 1)在输入端和输出端切换不同的输入/输出格式 2)在不同的Operator上使用不同的数据格式。

这是ObjectInspector interface
public interface ObjectInspector extends Cloneable {
  public static enum Category {
    PRIMITIVE, LIST, MAP, STRUCT, UNION
  };

  String getTypeName();

  Category getCategory();
}


这个interface提供了最一般的方法 getTypeName 和 getCategory。 我们再来看它的子抽象类和interface:
StructObjectInspector
MapObjectInspector
ListObjectInspector
PrimitiveObjectInspector
UnionObjectInspector

其中,PrimitiveObjectInspector用来完成对基本数据类型的解析,而StructObjectInspector用了完成对一行数据的解析,它本身有一组ObjectInspector组成。 由于Hive支持Nested Data Structure,所以,在StructObjectInspector中又可以(一层或多层的)嵌套任意的ObjectInspector。 Struct, Map, List, Union是Hive支持的4种集合数据类型,比如某一列的数据可以被声明为Struct类型,这样解析这一列的StructObjectInspector中就会嵌套了另一个StructObjectInspector。

现在我们可以从一个小例子看看ObjectInspector是如何工作的,这是一个Hive SerDe的测试用例代码:

/**
   * Test the LazySimpleSerDe class.
   */
  public void testLazySimpleSerDe() throws Throwable {
    try {
      // Create the SerDe
      LazySimpleSerDe serDe = new LazySimpleSerDe();
      Configuration conf = new Configuration();
      Properties tbl = createProperties();
      //用Properties初始化serDe
      serDe.initialize(conf, tbl);

      // Data
      Text t = new Text("123\t456\t789\t1000\t5.3\thive and hadoop\t1.\tNULL");
      String s = "123\t456\t789\t1000\t5.3\thive and hadoop\tNULL\tNULL";
      Object[] expectedFieldsData = {new ByteWritable((byte) 123),
          new ShortWritable((short) 456), new IntWritable(789),
          new LongWritable(1000), new DoubleWritable(5.3),
          new Text("hive and hadoop"), null, null};

      // Test
      deserializeAndSerialize(serDe, t, s, expectedFieldsData);
    } catch (Throwable e) {
      e.printStackTrace();
      throw e;
    }
  }

   private void deserializeAndSerialize(LazySimpleSerDe serDe, Text t, String s,
      Object[] expectedFieldsData) throws SerDeException {
    // Get the row ObjectInspector
    StructObjectInspector oi = (StructObjectInspector) serDe
        .getObjectInspector();
    // 获取列信息
    List<? extends StructField> fieldRefs = oi.getAllStructFieldRefs();
    assertEquals(8, fieldRefs.size());

    // Deserialize
    Object row = serDe.deserialize(t);
    for (int i = 0; i < fieldRefs.size(); i++) {
      Object fieldData = oi.getStructFieldData(row, fieldRefs.get(i));
      if (fieldData != null) {
        fieldData = ((LazyPrimitive) fieldData).getWritableObject();
      }
      assertEquals("Field " + i, expectedFieldsData[i], fieldData);
    }
    // Serialize
    assertEquals(Text.class, serDe.getSerializedClass());
    Text serializedText = (Text) serDe.serialize(row, oi);
    assertEquals("Serialized data", s, serializedText.toString());
  }

  //创建schema,保存在Properties中
  private Properties createProperties() {
    Properties tbl = new Properties();

    // Set the configuration parameters
    tbl.setProperty(Constants.SERIALIZATION_FORMAT, "9");
    tbl.setProperty("columns",
        "abyte,ashort,aint,along,adouble,astring,anullint,anullstring");
    tbl.setProperty("columns.types",
        "tinyint:smallint:int:bigint:double:string:int:string");
    tbl.setProperty(Constants.SERIALIZATION_NULL_FORMAT, "NULL");
    return tbl;
  }


从这个例子中,不难出,Hive将对行中列的读取和行的存储方式解耦和了,只有ObjectInspector清楚行和行中的列是怎样存取的,但使用者并不知道存储的细节。 对于数据的使用者来说,只需要行的Object和相应的ObjectInspector,就能读取出每一列的对象。

这段代码再清晰不过了,ObjectInspector oi控制了对列的Access
for (int i = 0; i < fieldRefs.size(); i++) {
      Object fieldData = oi.getStructFieldData(row, fieldRefs.get(i));
      if (fieldData != null) {
        fieldData = ((LazyPrimitive) fieldData).getWritableObject();
      }
      assertEquals("Field " + i, expectedFieldsData[i], fieldData);
  }


这段代码的作用是把一行deserialize,然后再serialize
    Object row = serDe.deserialize(t);
    Text serializedText = (Text) serDe.serialize(row, oi);
由此不难看出,只要有了不同的SerDe对象,可以很容易的将一条数据deserialize,然后再serialize成不同的格式,从而非常方便的实现数据格式的切换。

理解了上面的例子,就不难理解为什么所有的Hive ExprNodeEvaluator 和 UDF,UDAF, UDTF 都需要 (Object, ObjectInspector) pair了。 数据存储细节和使用的分离,使得Hive不需要针对不同的数据格式对同一个UDF, UDAF 或UDTF实现不同的版本,这些函数看到的只是WritableObject!


下面是表达式evaluator的interface:
/**
* ExprNodeEvaluator.
*
*/
public abstract class ExprNodeEvaluator {

  /**
   * Initialize should be called once and only once. Return the ObjectInspector
   * for the return value, given the rowInspector.
   */
  public abstract ObjectInspector initialize(ObjectInspector rowInspector) throws HiveException;

  /**
   * Evaluate the expression given the row. This method should use the
   * rowInspector passed in from initialize to inspect the row object. The
   * return value will be inspected by the return value of initialize.
   */
  public abstract Object evaluate(Object row) throws HiveException;

}

initialize中需要初始化ObjectInspector,返回输出数据的ObjectInspector(它负责解析evaluate method返回的对象);而每次evaluate call传进来一条Object数据,它的解析由ObjectInspector负责。

接下来是GenericUDF抽象类:
public abstract class GenericUDF {

  /**
   * A Defered Object allows us to do lazy-evaluation and short-circuiting.
   * GenericUDF use DeferedObject to pass arguments.
   */
  public static interface DeferredObject {
    Object get() throws HiveException;
  };

  /**
   * The constructor.
   */
  public GenericUDF() {
  }

  /**
   * Initialize this GenericUDF. This will be called once and only once per
   * GenericUDF instance.
   *
   * @param arguments
   *          The ObjectInspector for the arguments
   * @throws UDFArgumentException
   *           Thrown when arguments have wrong types, wrong length, etc.
   * @return The ObjectInspector for the return value
   */
  public abstract ObjectInspector initialize(ObjectInspector[] arguments)
      throws UDFArgumentException;

  /**
   * Evaluate the GenericUDF with the arguments.
   *
   * @param arguments
   *          The arguments as DeferedObject, use DeferedObject.get() to get the
   *          actual argument Object. The Objects can be inspected by the
   *          ObjectInspectors passed in the initialize call.
   * @return The
   */
  public abstract Object evaluate(DeferredObject[] arguments)
      throws HiveException;

  /**
   * Get the String to be displayed in explain.
   */
  public abstract String getDisplayString(String[] children);

}

它的机制与evaluator非常类似,初始化中敲定ObjectInspector数组,它们负责解析输入,返回output数据(即evaluator method返回的Object)的ObjectInspector;每次evaluate call传进一个Object数组,返回一条数据。

Hive支持LazySimple, LazyBinary,Thrift等不同的数据格式,同一个查询计划中,可以在operator上切换数据流的格式。比较常见的是在Mapper端使用LazySimpleSerDe,Mapper输出的数据使用LazyBinarySerDe,因为binary格式比较节省空间,从而减少repartition时的网络传输。 如果你想看查询计划的每一步到底使用了哪一种SerDe格式,只要用"Explain Extended"就可以查清楚了。

(本文原创,转载请注明出处)
分享到:
评论

相关推荐

    部分普通sql查询在hive中的实现方式

    部分普通sql查询在hive中的实现方式详细说明;

    hive修改过的jdbc包,用于显示hive中的中文内容

    如果系统语言不是utf-8的话,通过jdbc调用hive的数据时,中文会是乱码,通过修改jdbc包加上utf8标识后就好了,这个是改好了的包

    Apache Hive 中文手册_hive_

    Apache Hive 是基于Hadoop的一个数据仓库工具,用来进行数据提取、转化、加载,这是一种可以存储、查询和分析存储在Hadoop中的大规模数据的机制。hive数据仓库工具能将结构化的数据文件映射为一张数据库表,并提供...

    利用Hive进行复杂用户行为大数据分析及优化案例

    04_HIve中的case when、cast及unix_timestamp的使用 05_复杂日志分析-需求分析 06_复杂日志分析-需求字段讲解及过滤 07_复杂日志分析-字段提取及临时表的创建 08_复杂日志分析-指标结果的分析实现 09_Hive中数据文件...

    Hive中SQL详解

    Hive中SQL详解

    Hive数据仓库之垃圾分类数据分析系统

    (2)hive数据仓库分层设计,包含ODS、DWD、ADS层 (3)sqoop数据迁移,完成HIve与MySQL数据库中的数据交互 (4)Echarts搭建动态可视化大屏 (5)SpringBoot搭建可视化后台系统,完成前端与后台的数据传递与交互。 ...

    大数据之Hive官方文档简要翻译(中文文档)

    将官方文档做了简要翻译 ...元数据使用JPOX ORM解决方案(Data Nucleus)持久化,因此它支持的任何数据库都可以被Hive使用。大多数商业关 系数据库和许多开源数据库都受到支持。请参阅下面一节中支持的数据库列表。

    hive旅游-hive旅游系统-hive旅游系统源码-hive旅游管理系统-基于Web的hive旅游系统设计与实现-java代码

    hive旅游-hive旅游系统-hive旅游系统源码-hive旅游管理系统-hive旅游管理系统java代码-hive旅游系统设计与实现-基于springboot的hive旅游系统-基于Web的hive旅游系统设计与实现-hive旅游网站-hive旅游网站代码-hive...

    设计开发 Hive 编程指南 完整版

    设计开发 Hive 编程指南 完整版 设计开发 Hive 编程指南 完整版

    hive

    hive hive hive hive hive hive hive hive hive hive hive hive

    第6章:Hive性能优化及Hive3新特性1

    第6章:Hive性能优化及Hive3新特性课程学习目标掌握Hive中分区表及分桶表的设计及优化实现了解Hive中索引的设计及应用场景掌握Hive中文件格式与数据

    Hive3.1.2编译源码

    使用hive3.1.2和spark3.0.0配置hive on spark的时候,发现官方下载的hive3.1.2和spark3.0.0不兼容,hive3.1.2对应的版本是spark2.3.0,而spark3.0.0对应的hadoop版本是hadoop2.6或hadoop2.7。 所以,如果想要使用高...

    hive编程指南中文

    《Hive编程指南》是一本Apache Hive的编程指南 旨在介绍如何使用Hive的SQL方法 HiveQL来汇总 查询和分析存储在Hadoop分布式文件系统上的大数据集合 全书通过大量的实例 首先介绍如何在用户环境下安装和配置Hive 并对...

    Hive用户指南(Hive_user_guide)_中文版.pdf

    由于 SQL 被广泛的应用在数据仓库中,因此,专门针对 Hive 的特性设计 了类 SQL 的查询语言 HQL。熟悉 SQL 开发的开发者可以很方便的使用 Hive 进行开 发。 2. 数据存储位置。 Hive 是建立在 Hadoop 之上的,所有...

    hive-jdbc hive jdbc驱动

    hive-jdbc

    Hive表生成工具,Hive表生成工具Hive表生成工具

    Hive表生成工具,Hive表生成工具Hive表生成工具

    Hive使用手册Hive使用手册

    1 Hive 概念与连接使用: 2 2 Hive支持的数据类型: 2 2.1原子数据类型: 2 2.2复杂数据类型: 2 2.3 Hive类型转换: 3 3 Hive创建/删除数据库 3 3.1创建数据库: 3 3.2 删除数据库: 3 4 Hive 表相关语句 3 4.1 Hive ...

    hive学习总结 思维导图.xmind

    由于 Hive 采用了类似SQL 的查询语言 HQL(Hive Query Language),因此很容易将 Hive ...数据库可以用在 Online 的应用中,但是Hive 是为数据仓库而设计的,清楚这一点,有助于从应用角度理解 Hive 的特性。

    【63课时完整版】大数据实践HIVE详解及实战

    7.Hive中基本命令的使用 8.Hive中常用的属性配置 9.Hive中常用的交互式命令 10Hive中数据库的管理与使用 11.Hive中表的管理与使用 12.Hive中外部表的使用 第2章:Hive 常用DML、UDF及连接方式 13.Hive中分区表的...

    《Hive数据仓库案例教程》教学课件 第5章 Hive数据操作.pdf

    《Hive数据仓库案例教程》教学课件 第5章 Hive数据操作.pdf《Hive数据仓库案例教程》教学课件 第5章 Hive数据操作.pdf《Hive数据仓库案例教程》教学课件 第5章 Hive数据操作.pdf《Hive数据仓库案例教程》教学课件 第...

Global site tag (gtag.js) - Google Analytics