一种处理Hive元数据与文件类型不同时SQL查询失败的方法

2023-05-16

文章目录

  • 一、背景
  • 二、分析过程
    • 2.1 环境及测试数据
      • 2.1.1 环境
      • 2.1.2 测试数据
    • 2.2 select语句异常分析
      • 2.2.1 异常分析
      • 2.2.2 捕获异常位置
    • 2.3 insert overwrite语句异常分析
      • 2.3.1 异常分析
      • 2.3.2 捕获异常位置
      • 2.3.2 读数据(readRow)异常
  • 三、代码示例及结论
  • 四、CDH集群中部署修改后的jar包
  • 五、可能的其他方案?

一、背景

    由于Hive的元数据与文件存储分离,且可单独修改表的类型,造成元数据与文件类型不同,这时使用SQL查询数据则会报错。不幸的是,我们就有这种需求,数采的数据同步了一份在Hive中,每天有大量的数据实时写入生成大量小文件;且对列的类型修改等没做限制,列类型可以被改成与之前不兼容的类型,以致于查询报错,通过insert overwrite来合并小文件的任务也一直失败,HDFS上小文件不断增多,严重影响查询效率。
    当前使用的Hive版本为2.1.1-cdh6.3.0(CDH6.3.0),搜索了一下也没有什么配置可以直接让Hive忽略这种类型不同的错误,当前Hive版本也没有高版本似乎有的类型兼容的功能;先简单调试了一下发现Hive Hook功能似乎也拦截不到数据这一步。不得已尝试一下修改源码的方式,却走通了。
    本文记录通过修改Hive(2.1.1-cdh6.3.0)源码的方式,处理Hive元数据与文件类型不同时,SQL查询失败的问题,将类型不兼容的字段查询结果设置为空值。

二、分析过程

2.1 环境及测试数据

2.1.1 环境

    CDH6.3.0,Hive版本为2.1.1-cdh6.3.0,还是调试hiveserver2,调试方法参考之前的《Hive源码调试》文章。顺带一提,github上cloudera/hive已经搜不到了,可能不打算开源了,还好gitee上这位朋友保存了一份https://gitee.com/gabry/cloudera-hive,有需要的可以自己保存一下这个仓库。

2.1.2 测试数据

创建一个表t1(我们默认用的parquet格式,本文也只测试过parquet格式数据;分区表也可以,但这里只举一个非分区表例子),插入两条数据;再创建一个列名相同,但id列类型不同的表error_type:

 create table t1(id float,content string) stored as parquet;
 insert into t1 vlaues(1.1,'content1'),(2.2,'content2');
 create table error_type(id int,content string) stored as parquet;

在HDFS上直接将t1的数据文件拷到error_type表的目录下:

hdfs dfs -cp /user/hive/warehouse/testdb.db/t1/000000_0 /user/hive/warehouse/testdb.db/error_type/

这时使用sql查询error_type表则会报错:

0: jdbc:hive2://localhost:10000> select * from error_type;
INFO  : Compiling command(queryId=hive_20220306113526_62d5507c-8df1-478b-8f9f-4ea1b8601df9): select * from error_type
INFO  : Semantic Analysis Completed
INFO  : Returning Hive schema: Schema(fieldSchemas:[FieldSchema(name:error_type.id, type:int, comment:null), FieldSchema(name:error_type.content, type:string, comment:null)], properties:null)
INFO  : Completed compiling command(queryId=hive_20220306113526_62d5507c-8df1-478b-8f9f-4ea1b8601df9); Time taken: 0.13 seconds
INFO  : Executing command(queryId=hive_20220306113526_62d5507c-8df1-478b-8f9f-4ea1b8601df9): select * from error_type
INFO  : Completed executing command(queryId=hive_20220306113526_62d5507c-8df1-478b-8f9f-4ea1b8601df9); Time taken: 0.001 seconds
INFO  : OK
Error: java.io.IOException: org.apache.hadoop.hive.ql.metadata.HiveException: java.lang.ClassCastException: org.apache.hadoop.io.FloatWritable cannot be cast to org.apache.hadoop.io.IntWritable (state=,code=0)

2.2 select语句异常分析

2.2.1 异常分析

开始调试,上面的ClassCastException发生处的函数调用栈(从IDEA中复制)为:

getPrimitiveJavaObject:46, WritableIntObjectInspector (org.apache.hadoop.hive.serde2.objectinspector.primitive)
copyToStandardObject:412, ObjectInspectorUtils (org.apache.hadoop.hive.serde2.objectinspector)
toThriftPayload:170, SerDeUtils (org.apache.hadoop.hive.serde2)
convert:49, ThriftFormatter (org.apache.hadoop.hive.serde2.thrift)
process:94, ListSinkOperator (org.apache.hadoop.hive.ql.exec)
forward:882, Operator (org.apache.hadoop.hive.ql.exec)
process:95, SelectOperator (org.apache.hadoop.hive.ql.exec)
forward:882, Operator (org.apache.hadoop.hive.ql.exec)
process:130, TableScanOperator (org.apache.hadoop.hive.ql.exec)
pushRow:438, FetchOperator (org.apache.hadoop.hive.ql.exec)
pushRow:430, FetchOperator (org.apache.hadoop.hive.ql.exec)
fetch:146, FetchTask (org.apache.hadoop.hive.ql.exec)
getResults:2227, Driver (org.apache.hadoop.hive.ql)
getNextRowSet:491, SQLOperation (org.apache.hive.service.cli.operation)
getOperationNextRowSet:297, OperationManager (org.apache.hive.service.cli.operation)
fetchResults:869, HiveSessionImpl (org.apache.hive.service.cli.session)
invoke:-1, GeneratedMethodAccessor5 (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:78, HiveSessionProxy (org.apache.hive.service.cli.session)
access$000:36, HiveSessionProxy (org.apache.hive.service.cli.session)
run:63, HiveSessionProxy$1 (org.apache.hive.service.cli.session)
doPrivileged:-1, AccessController (java.security)
doAs:422, Subject (javax.security.auth)
doAs:1962, UserGroupInformation (org.apache.hadoop.security)
invoke:59, HiveSessionProxy (org.apache.hive.service.cli.session)
fetchResults:-1, $Proxy39 (com.sun.proxy)
fetchResults:507, CLIService (org.apache.hive.service.cli)
FetchResults:708, ThriftCLIService (org.apache.hive.service.cli.thrift)
getResult:1717, TCLIService$Processor$FetchResults (org.apache.hive.service.rpc.thrift)
getResult:1702, TCLIService$Processor$FetchResults (org.apache.hive.service.rpc.thrift)
process:39, ProcessFunction (org.apache.thrift)
process:39, TBaseProcessor (org.apache.thrift)
process:56, TSetIpAddressProcessor (org.apache.hive.service.auth)
run:286, TThreadPoolServer$WorkerProcess (org.apache.thrift.server)
runWorker:1149, ThreadPoolExecutor (java.util.concurrent)
run:624, ThreadPoolExecutor$Worker (java.util.concurrent)
run:748, Thread (java.lang)

WritableIntObjectInspector.getPrimitiveJavaObject:46这个方法为:

@Override
  public Object getPrimitiveJavaObject(Object o) {
    return o == null ? null : Integer.valueOf(((IntWritable) o).get());
  }

此时参数为:

this = {WritableIntObjectInspector@10276} 
 typeInfo = {PrimitiveTypeInfo@10277} "int"
o = {FloatWritable@10262} "1.1"

这里将从文件中读取的FloatWritable类型的对象,转换为根据表元数据int类型对应的IntWritable类型,出现ClassCastException。

对日志中看到的HiveException类的构造函数下断点,可知道抛出HiveException的位置为函数调用栈process:94, ListSinkOperator (org.apache.hadoop.hive.ql.exec)这一行对应的这个函数:

@Override
  @SuppressWarnings("unchecked")
  public void process(Object row, int tag) throws HiveException {
    try {
      res.add(fetcher.convert(row, inputObjInspectors[0]));
      numRows++;
    } catch (Exception e) {
      throw new HiveException(e);
    }
  }

2.2.2 捕获异常位置

异常抛出后,被捕获并抛出HiveException之前的几个栈中函数:

getPrimitiveJavaObject:46, WritableIntObjectInspector (org.apache.hadoop.hive.serde2.objectinspector.primitive)
copyToStandardObject:412, ObjectInspectorUtils (org.apache.hadoop.hive.serde2.objectinspector)
toThriftPayload:170, SerDeUtils (org.apache.hadoop.hive.serde2)
convert:49, ThriftFormatter (org.apache.hadoop.hive.serde2.thrift)

getPrimitiveJavaObject:46, WritableIntObjectInspector显然是特定类型的实现,不适合在这里捕获异常;copyToStandardObject:412, ObjectInspectorUtils函数本身逻辑比较复杂;toThriftPayload:170, SerDeUtilsconvert:49, ThriftFormatter都可以,convert:49, ThriftFormatter刚好有个循环处理一行数据的每个字段,在这里处理看起来比较清晰,

  @Override
  public Object convert(Object row, ObjectInspector rowOI) throws Exception {
    StructObjectInspector structOI = (StructObjectInspector) rowOI;
    List<? extends StructField> fields = structOI.getAllStructFieldRefs();
    Object[] converted = new Object[fields.size()];
    for (int i = 0 ; i < converted.length; i++) {
      StructField fieldRef = fields.get(i);
      Object field = structOI.getStructFieldData(row, fieldRef);
      converted[i] = field == null ? null :
          SerDeUtils.toThriftPayload(field, fieldRef.getFieldObjectInspector(), protocol);
    }
    return converted;
  }

将生成converted[i]的那行改为:

      try {
        converted[i] = field == null ? null :
                SerDeUtils.toThriftPayload(field, fieldRef.getFieldObjectInspector(), protocol);
      } catch (ClassCastException e) {
          converted[i] = null;
      }

这样修改后(部署见后面章节)执行select * from error_type不会抛异常了,查询的2条数据id字段都为null。

2.3 insert overwrite语句异常分析

2.3.1 异常分析

    本以为就这样修改一下就可以了,尝试执行合并小文件的SQL:insert overwrite table error_type select * from error_type还会报错,日志里打印的函数调用栈如下:

Caused by: java.lang.ClassCastException: org.apache.hadoop.io.FloatWritable cannot be cast to org.apache.hadoop.io.IntWritable
	at org.apache.hadoop.hive.serde2.objectinspector.primitive.WritableIntObjectInspector.get(WritableIntObjectInspector.java:36)
	at org.apache.hadoop.hive.ql.io.parquet.write.DataWritableWriter$IntDataWriter.write(DataWritableWriter.java:385)
	at org.apache.hadoop.hive.ql.io.parquet.write.DataWritableWriter$GroupDataWriter.write(DataWritableWriter.java:199)
	at org.apache.hadoop.hive.ql.io.parquet.write.DataWritableWriter$MessageDataWriter.write(DataWritableWriter.java:215)
	at org.apache.hadoop.hive.ql.io.parquet.write.DataWritableWriter.write(DataWritableWriter.java:88)
	at org.apache.hadoop.hive.ql.io.parquet.write.DataWritableWriteSupport.write(DataWritableWriteSupport.java:60)
	at org.apache.hadoop.hive.ql.io.parquet.write.DataWritableWriteSupport.write(DataWritableWriteSupport.java:32)
	at org.apache.parquet.hadoop.InternalParquetRecordWriter.write(InternalParquetRecordWriter.java:123)
	at org.apache.parquet.hadoop.ParquetRecordWriter.write(ParquetRecordWriter.java:179)
	at org.apache.parquet.hadoop.ParquetRecordWriter.write(ParquetRecordWriter.java:46)
	at org.apache.hadoop.hive.ql.io.parquet.write.ParquetRecordWriterWrapper.write(ParquetRecordWriterWrapper.java:136)
	at org.apache.hadoop.hive.ql.io.parquet.write.ParquetRecordWriterWrapper.write(ParquetRecordWriterWrapper.java:149)
	at org.apache.hadoop.hive.ql.exec.FileSinkOperator.process(FileSinkOperator.java:769)
	at org.apache.hadoop.hive.ql.exec.Operator.forward(Operator.java:882)
	at org.apache.hadoop.hive.ql.exec.SelectOperator.process(SelectOperator.java:95)
	at org.apache.hadoop.hive.ql.exec.Operator.forward(Operator.java:882)
	at org.apache.hadoop.hive.ql.exec.TableScanOperator.process(TableScanOperator.java:130)
	at org.apache.hadoop.hive.ql.exec.MapOperator$MapOpCtx.forward(MapOperator.java:146)
	at org.apache.hadoop.hive.ql.exec.MapOperator.process(MapOperator.java:484)

2.3.2 捕获异常位置

经过亿点调试分析(这些SQL有MR任务,任务会提交到Yarn,先设置参数set hive.exec.mode.local.auto=true;让Hive以本地模式运行该SQL,否则断点不会触发),接近抛异常位置(是否可以作为规律)的这个方法org.apache.hadoop.hive.ql.io.parquet.write.DataWritableWriter.GroupDataWriter#write也有与前面ThriftFormatter.convert:49方法类似的通过循环写每一个字段的功能:

    @Override
    public void write(Object value) {
      for (int i = 0; i < structFields.size(); i++) {
        StructField field = structFields.get(i);
        Object fieldValue = inspector.getStructFieldData(value, field);

        if (fieldValue != null) {
          String fieldName = field.getFieldName();
          DataWriter writer = structWriters[i];

          recordConsumer.startField(fieldName, i);
          writer.write(fieldValue);
          recordConsumer.endField(fieldName, i);
        }
      }
    }

其中writer.write(fieldValue)就是异常信息打印的调用栈中的org.apache.hadoop.hive.ql.io.parquet.write.DataWritableWriter$GroupDataWriter.write(DataWritableWriter.java:199)位置。

这里有一行Object fieldValue = inspector.getStructFieldData(value, field);,经过调试可以发现,这行代码和前面捕获异常的方法convert:49, ThriftFormatter中的Object field = structOI.getStructFieldData(row, fieldRef);调用的都是org.apache.hadoop.hive.serde2.objectinspector.StandardStructObjectInspector#getStructFieldData

  @Override
  @SuppressWarnings("unchecked")
  public Object getStructFieldData(Object data, StructField fieldRef) {
    if (data == null) {
      return null;
    }
    // We support both List<Object> and Object[]
    // so we have to do differently.
    boolean isArray = data.getClass().isArray();
    if (!isArray && !(data instanceof List)) {
      if (!warned) {
        LOG.warn("Invalid type for struct " + data.getClass());
        LOG.warn("ignoring similar errors.");
        warned = true;
      }
      return data;
    }
    int listSize = (isArray ? ((Object[]) data).length : ((List<Object>) data)
        .size());
    MyField f = (MyField) fieldRef;
    if (fields.size() != listSize && !warned) {
      // TODO: remove this
      warned = true;
      LOG.warn("Trying to access " + fields.size()
          + " fields inside a list of " + listSize + " elements: "
          + (isArray ? Arrays.asList((Object[]) data) : (List<Object>) data));
      LOG.warn("ignoring similar errors.");
    }
    int fieldID = f.getFieldID();

    if (fieldID >= listSize) {
      return null;
    } else if (isArray) {
      return ((Object[]) data)[fieldID];
    } else {
      return ((List<Object>) data).get(fieldID);
    }
  }

StandardStructObjectInspector#getStructFieldData方法一个参数为从文件从读取的一行数据,第二个参数为org.apache.hadoop.hive.serde2.objectinspector.StandardStructObjectInspector.MyField的实例,其中有要取的字段的下标,这个方法大概功能就是根据下标从一行数据中取数,但是没做类型判断。MyField中也有与表的元数据中字段类型对应的ObjectInspector,可以使用ObjectInspector来读取一下本次获取的字段数据,如果类型冲突则捕获ClassCastException,并让本方法返回空值,后续的读写流程本字段都是null,这样无论对于之前的select语句还是insert overwrite语句,都可以达到本文想要的效果。

由于我们定义的Hive表都是用的原始类型,所以调用objectInspector实现的org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector接口中的方法getPrimitiveJavaObject,通过多态来实现各种类型数据的读取,StandardStructObjectInspector#getStructFieldData函数最后一个if else部分改为:

    Object objValue;
    if (fieldID >= listSize) {
      return null;
    } else if (isArray) {
      objValue = ((Object[]) data)[fieldID];
    } else {
      objValue = ((List<Object>) data).get(fieldID);
    }
    ObjectInspector objectInspector = f.getFieldObjectInspector();
    if (Category.PRIMITIVE.equals(objectInspector.getCategory())) {
      try {
        ((PrimitiveObjectInspector) objectInspector).getPrimitiveJavaObject(objValue);
      } catch (ClassCastException | UnsupportedOperationException e) {
        /*
        UnsupportedOperationException:
          如Hive列类型为String,这里获取到的objectInspector为ParquetStringInspector的实例,
          但org.apache.hadoop.hive.ql.io.parquet.serde.primitive.ParquetStringInspector.getPrimitiveJavaObject中,
          参数不是那个方法中做了判断的那几种类型时就会抛UnsupportedOperationException
         */
        objValue = null;
      }
    }
    return objValue;

(修改了这部分后,对于原始类型,其实前面2.2.2节中的捕获异常可以删除)

2.3.2 读数据(readRow)异常

在有的表执行insert overwrite时,遇到了下面两个错误(其实是同一种):

Caused by: java.lang.UnsupportedOperationException: Cannot inspect org.apache.hadoop.io.LongWritable
	at org.apache.hadoop.hive.ql.io.parquet.serde.primitive.ParquetStringInspector.getPrimitiveJavaObject(ParquetStringInspector.java:77)
	at org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils.getLong(PrimitiveObjectInspectorUtils.java:709)
	at org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorConverter$LongConverter.convert(PrimitiveObjectInspectorConverter.java:182)
	at org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorConverters$StructConverter.convert(ObjectInspectorConverters.java:416)
	at org.apache.hadoop.hive.ql.exec.MapOperator$MapOpCtx.readRow(MapOperator.java:126)
	at org.apache.hadoop.hive.ql.exec.MapOperator$MapOpCtx.access$200(MapOperator.java:89)
	at org.apache.hadoop.hive.ql.exec.MapOperator.process(MapOperator.java:483)
Caused by: java.lang.ClassCastException: org.apache.hadoop.io.FloatWritable cannot be cast to org.apache.hadoop.io.IntWritable
	at org.apache.hadoop.hive.serde2.objectinspector.primitive.WritableIntObjectInspector.get(WritableIntObjectInspector.java:36)
	at org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils.getDouble(PrimitiveObjectInspectorUtils.java:755)
	at org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils.getFloat(PrimitiveObjectInspectorUtils.java:796)
	at org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorConverter$FloatConverter.convert(PrimitiveObjectInspectorConverter.java:211)
	at org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorConverters$StructConverter.convert(ObjectInspectorConverters.java:416)
	at org.apache.hadoop.hive.ql.exec.MapOperator$MapOpCtx.readRow(MapOperator.java:126)
	at org.apache.hadoop.hive.ql.exec.MapOperator$MapOpCtx.access$200(MapOperator.java:89)
	at org.apache.hadoop.hive.ql.exec.MapOperator.process(MapOperator.java:483)

都是在MapOperator 483行调用MapOperator M a p O p C t x . r e a d R o w 中 的 错 误 ( 2.3.1 节 中 日 志 显 示 M a p O p e r a t o r 484 调 用 M a p O p e r a t o r MapOpCtx.readRow中的错误(2.3.1节中日志显示MapOperator 484调用MapOperator MapOpCtx.readRow2.3.1MapOperator484MapOperatorMapOpCtx.forward中抛出的异常),只是两个日志中最后出错的数据类型不同。没分析代码,还是用与之前类似的方法,在org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorConverters.StructConverter#convert方法中也有个循环处理每个字段的功能,将异常日志中ObjectInspectorConverters.java:416指出的这一行代码:

outputFieldValue = fieldConverters.get(f).convert(inputFieldValue);

改成:

        try {
          outputFieldValue = fieldConverters.get(f).convert(inputFieldValue);
        } catch (ClassCastException | UnsupportedOperationException e) {
          outputFieldValue = null;
        }

修改到这一步后,我们遇到的那些元数据与与文件不兼容类型的表都能正常查询了,也可以通过insert overwrite合并小文件了。

三、代码示例及结论

修改的代码都提交到了fork的这个仓库中,可查看这个提交记录 https://gitee.com/Ox3E6/cloudera-hive/commit/1e31127162b3bb29716580692c2d1fe30543f057

目前还不熟悉Hive代码迷宫中的细节和一些整体流程,仅仅根据报错位置尝试添加一些处理功能,如2.3.1节和2.3.3节都是在实际数据处理过程中抛出的异常。还是需要多做测试,遇到一个问题处理一个,只要转换成null后Hive的读写及其他逻辑不报错就行。

四、CDH集群中部署修改后的jar包

    修改的代码都位于hive-serde模块中,但是由于其他hive模块也引入了hive-serde依赖(没意识到这点之前,只替换了hive-serde jar包,每次还是抛出HiveException异常,重新编译调试了几次,甚至以为出现了灵异事件或是又要发现什么至今未知的Java异常捕获优先级技巧…),所以最简单的方法就是把编译打包后lib目录下hive开头的jar包全部拷过去。

CDH机器上,搜索hive jar包位置以hive-serde jar包为例:

[root@dev-master2 ~]# find / -name hive-serde-2.1.1-cdh6.3.0.jar

/opt/cloudera/cm/cloudera-navigator-server/libs/cdh6/hive-serde-2.1.1-cdh6.3.0.jar
/opt/cloudera/cm/cloudera-scm-telepub/libs/cdh6/hive-serde-2.1.1-cdh6.3.0.jar
/opt/cloudera/parcels/CDH-6.3.0-1.cdh6.3.0.p0.1279813/jars/hive-serde-2.1.1-cdh6.3.0.jar
/opt/cloudera/parcels/CDH-6.3.0-1.cdh6.3.0.p0.1279813/lib/hive/lib/hive-serde-2.1.1-cdh6.3.0.jar
/opt/cloudera/parcels/CDH-6.3.0-1.cdh6.3.0.p0.1279813/lib/oozie/embedded-oozie-server/webapp/WEB-INF/lib/hive-serde-2.1.1-cdh6.3.0.jar

有的是符号链接,只需要放入这3个目录:

/opt/cloudera/cm/common_jars/
/opt/cloudera/parcels/CDH-6.3.0-1.cdh6.3.0.p0.1279813/jars/
/opt/cloudera/parcels/CDH-6.3.0-1.cdh6.3.0.p0.1279813/lib/oozie/embedded-oozie-server/webapp/WEB-INF/lib/

后两个目录下jar包文件名直接就是打包出来的jar包名,但是common_jars目录下的jar包文件名中有一串不知道什么算法生成的hash,形如:

[root@dev-master2 scripts]# ls -lh /opt/cloudera/cm/common_jars/hive* 
-rw-r--r--. 1 root root  46K Jul 19  2019 /opt/cloudera/cm/common_jars/hive-ant-2.1.1-cdh6.3.0.f857dabb5222c1969c9f4087c8bfaac3.jar
-rw-r--r--. 1 root root  12K Jul 19  2019 /opt/cloudera/cm/common_jars/hive-classification-2.1.1-cdh6.3.0.c2ac9c5cf1fbb22aeda542f287ecbaa4.jar
-rw-r--r--. 1 root root  46K Jul 19  2019 /opt/cloudera/cm/common_jars/hive-cli-2.1.1-cdh6.3.0.f8741782bcbf8b4b58f537da6346e0ff.jar
-rw-r--r--. 1 root root 324K Jul 19  2019 /opt/cloudera/cm/common_jars/hive-common-1.1.0-cdh5.12.0.10beb989e3d6a390afce045b1e865bde.jar
-rw-r--r--. 1 root root 429K Jul 19  2019 /opt/cloudera/cm/common_jars/hive-common-2.1.1-cdh6.3.0.87dadce3138dc2c5c2e696cc6f6f7927.jar
......

以前替换yarn一个有并发修改问题的jar包也遇到这种情况,但是jar包替换后使用原来一样的带hash的文件名,也没有报校验失败的错误。

所以可将以下脚本与所有打包后lib目录下的hive*.jar放在一个目录下,将目录拷到CDH上每一台(通过一些脚本)机器上,并在每一台(通过一些脚本)机器上运行该脚本,替换hive的jar包,然后重启Hive即可。

copy_jars.sh(带hash的那部分可从机器上拷出来,再通过正则替换生成)

#!/usr/bin/env bash

# 参考/user/bin/hive脚本:Reference: http://stackoverflow.com/questions/59895/can-a-bash-script-tell-what-directory-its-stored-in
current_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
echo "current_dir: $current_dir"
cp $current_dir/hive*.jar /opt/cloudera/parcels/CDH-6.3.0-1.cdh6.3.0.p0.1279813/jars/
cp $current_dir/hive*.jar /opt/cloudera/parcels/CDH-6.3.0-1.cdh6.3.0.p0.1279813/lib/oozie/embedded-oozie-server/webapp/WEB-INF/lib/

cp $current_dir/hive-ant-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-ant-2.1.1-cdh6.3.0.f857dabb5222c1969c9f4087c8bfaac3.jar
cp $current_dir/hive-classification-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-classification-2.1.1-cdh6.3.0.c2ac9c5cf1fbb22aeda542f287ecbaa4.jar
cp $current_dir/hive-cli-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-cli-2.1.1-cdh6.3.0.f8741782bcbf8b4b58f537da6346e0ff.jar
cp $current_dir/hive-common-1.1.0-cdh5.12.0.jar /opt/cloudera/cm/common_jars/hive-common-1.1.0-cdh5.12.0.10beb989e3d6a390afce045b1e865bde.jar
cp $current_dir/hive-common-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-common-2.1.1-cdh6.3.0.87dadce3138dc2c5c2e696cc6f6f7927.jar
cp $current_dir/hive-exec-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-exec-2.1.1-cdh6.3.0.15d37ff81bca70d35b904a6946abea49.jar
cp $current_dir/hive-jdbc-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-jdbc-2.1.1-cdh6.3.0.a9016068a26246ac47c4b2637db33adb.jar
cp $current_dir/hive-llap-client-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-llap-client-2.1.1-cdh6.3.0.701f1dfc66958f0d8feab78d602b9cb6.jar
cp $current_dir/hive-llap-common-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-llap-common-2.1.1-cdh6.3.0.6c733dcdfa1e52ce79dc1b0066220a00.jar
cp $current_dir/hive-llap-server-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-llap-server-2.1.1-cdh6.3.0.105d9633082dfb213b9d390dc3df8087.jar
cp $current_dir/hive-llap-tez-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-llap-tez-2.1.1-cdh6.3.0.47ac2463acf7de1929b57c4da5ac7f41.jar
cp $current_dir/hive-metastore-1.1.0-cdh5.12.0.jar /opt/cloudera/cm/common_jars/hive-metastore-1.1.0-cdh5.12.0.f439e1b26177542bfc57e428717a265a.jar
cp $current_dir/hive-metastore-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-metastore-2.1.1-cdh6.3.0.4a407e44f9168f014f41edd4a56d5028.jar
cp $current_dir/hive-orc-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-orc-2.1.1-cdh6.3.0.0d1f0cf02d1bdad572cca211654c64af.jar
cp $current_dir/hive-serde-1.1.0-cdh5.12.0.jar /opt/cloudera/cm/common_jars/hive-serde-1.1.0-cdh5.12.0.62c4570f4681c0698b9f5f5ab6baab4a.jar
cp $current_dir/hive-serde-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-serde-2.1.1-cdh6.3.0.bde9116deea651dbf085034565504351.jar
cp $current_dir/hive-service-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-service-2.1.1-cdh6.3.0.0c28a52a856414cb45d0b827bd7884e9.jar
cp $current_dir/hive-service-rpc-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-service-rpc-2.1.1-cdh6.3.0.fde12a48a558128e4d15bfb47f90cfb4.jar
cp $current_dir/hive-shims-1.1.0-cdh5.12.0.jar /opt/cloudera/cm/common_jars/hive-shims-1.1.0-cdh5.12.0.2698b9ffda7580409fc299d986f41ded.jar
cp $current_dir/hive-shims-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-shims-2.1.1-cdh6.3.0.a151f9e3d14dfeb5bb2b34e0b2ef8a28.jar
cp $current_dir/hive-storage-api-2.1.1-cdh6.3.0.jar /opt/cloudera/cm/common_jars/hive-storage-api-2.1.1-cdh6.3.0.fb98d759511d27287bcd20e48b40f961.jar

五、可能的其他方案?

  • 如从Hive表的INPUTFORMAT切入
  • 更加熟悉Hive流程后,看其他地方是否能更方便地处理或全局处理
  • 有空看看Hive3的兼容怎么做的,“学习学习”
    在这里插入图片描述
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一种处理Hive元数据与文件类型不同时SQL查询失败的方法 的相关文章

随机推荐

  • GitHub上README.md编写教程(基本语法)

    今天在编写github中的readme md文档时 xff0c 发现自己写的和别人写的样式完全不一样 xff0c 自己的好难看 xff0c 于是百度了一番 xff0c 很多都是转载的别人13年的博客 xff0c 其中还发现一片17年写的原创
  • android 平板适配

    首次进行平板开发 xff0c 从一开始就在琢磨适配是怎么弄的 xff0c 百度 google 群一大圈 xff0c 还是没人告诉具体是怎么做的 xff0c 都是基本的概念性的讲述怎么适配 xff0c 写了一个界面发现存在很大适配问题 xff
  • Linux下常用的优秀软件

    Linux下优秀软件介绍 常用软件工具软件美化图像视频相关音频播放器下载工具科研利器终端Windows下常用软件运行 常用软件 下面的软件均是本人使用过的 xff0c 如果大家有自己觉得很好的软件 xff0c 欢迎留言 xff0c 好的软件
  • Charles抓包遇到的坑,看这一篇就够了

    Android 7 0 xff08 API 24 xff09 以下 xff0c 你可以直接使用 Charles 安装相关证书配置好代理后实现抓包功能 xff0c 本文主要讲android7 0以后如何实现抓包功能 xff1a 首先下载安装C
  • Bad notification posted from: Couldn't expand RemoteViews for: StatusBarNotification

    自定义通知栏有些机型报下面的错 xff1a android app RemoteServiceException Bad notification posted from package xxx Couldn 39 t expand Rem
  • SCP不用密码传输文件

    SCP不用密码传输文件 方法一 xff1a 使用sshpass yum install sshpass sshpass p password scp data scripts data log root 64 X X X X data da
  • 新版Unity里面怎么使用Post Process

  • 在Unity中使用.NET 4.x和在Unity项目添加外部程序集

    2019版本已经没有4 x等效运行选项了 xff1a 应该是只能选择4 x等效Api 然后API等级选择有两种选择 xff1a NET Standard 2 0 此配置文件与 NET Foundation发布的 NET Standard 2
  • Unity使用.NET4.x新的语法和语言功能

  • UE4设置 只修改蓝图节点的语言为英文

    原因 因为在查找需要的节点时 xff0c 输入英文更符合命名法 xff0c 为了更好的查找节点 xff0c 把节点的名字改成英文当然更好 xff01 操作步骤 取消下面的勾选即可 结果
  • Unity的InputSystem使用实践

    如何使用 首先得有一个PlayerInput在场景中 xff0c 每一个PlayerInput表示一个玩家 在Actions里面选择自己的Actions xff0c 可以新建 xff1a 比如在PlayerMaps中的MoveActions
  • 虚幻4C++编程入门(搬运1)

    首先我们将使用虚幻编辑器中的类向导生成基础 C 43 43 类 xff0c 以便蓝图稍后进行延展 下图展示了向导的第一步 新建一个 Actor 这里根据对character pawn和actor的描述 xff0c 知道了pawn是actor
  • 虚幻4C++编程入门深入了解

    这部分我们将讨论基础构建块以及它们之间相互关联的方式 在此我们将了解虚幻引擎如何使用 继承和合成构建自定义游戏性功能 游戏性类 xff1a 对象 Actor 和组件 多数游戏性类派生自 4 个主要类型 它们是 UObject AActor
  • 窗口焦点丢失问题分析

    从slog中的systemlog可以看出如下信息 xff1a 01 01 08 29 03 732 633 936 I WindowManager Relayout invis Window 42244420 u0 Keyguard mEx
  • ubuntu不能挂载U盘问题

    插上U盘一个弹窗显示不能挂载系统 就不附图了 自己也是在到处找了问题 xff0c 试了很多教程 xff0c 要么看不懂要么没用要么瞎写的 最后实测一个有用的 因为ubuntu默认不能识别U盘 解决方法 xff1a 安装exfat磁盘格式工具
  • unity3d个人版怎么改变主题=>黑色

    是有很多文章都有介绍如何使用操作 xff0c 我就不再多说 xff0c 主要是那个软件的问题 xff08 在下面我会附上winhex的下载地址和详细教程 xff09 一般会出问题的地方是试用版会出很多问题 xff0c 比如什么200k以上不
  • 【正则表达式】基础应用(匹配matches(regex))(转)

    正则表达式基础应用 匹配 字符 x 字符 x 反斜线字符 字符类 abc a b 或 c xff08 简单类 xff09 abc 任何字符 xff0c 除了 a b 或 c xff08 否定 xff09 a zA Z a 到 z 或 A 到
  • 一种动态更新flink任务配置的方法

    文章目录 1 原理2 例 xff0c 整数过滤2 1 并行度为12 2 并行度大于12 3 完整代码 参考链接 1 原理 参考Flink Spark 如何实现动态更新作业配置 xff0c 讲得比较详细 xff0c 这篇的文章的参考参考文献也
  • 一种Hudi on Flink动态同步元数据变化的方法

    文章目录 一 背景二 官方Schema Evolution例子三 Flink 43 Hudi实现Schema Evolution四 96 HoodieFlinkStreamer 96 流程浅析及扩展方法4 1 FlinkKafkaConsu
  • 一种处理Hive元数据与文件类型不同时SQL查询失败的方法

    文章目录 一 背景二 分析过程2 1 环境及测试数据2 1 1 环境2 1 2 测试数据 2 2 select语句异常分析2 2 1 异常分析2 2 2 捕获异常位置 2 3 insert overwrite语句异常分析2 3 1 异常分析