专栏首页伦少的博客hive查询报错:java.io.IOException:org.apache.parquet.io.ParquetDecodingException
原创

hive查询报错:java.io.IOException:org.apache.parquet.io.ParquetDecodingException

转载请务必注明原创地址为:https://dongkelun.com/2018/05/20/hiveQueryException/

前言

本文解决如标题所述的一个hive查询异常,详细异常信息为:

Failed with exception java.io.IOException:org.apache.parquet.io.ParquetDecodingException: Can not read value at 1 in block 0 in file hdfs://192.168.44.128:8888/user/hive/warehouse/test.db/test/part-00000-9596e4bd-f511-4f76-9030-33e426d0369c-c000.snappy.parquet

这个异常是用spark sql将oracle(不知道mysql中有没有该问题,大家可以自己测试一下)中表数据查询出来然后写入hive表中,之后在hive命令行执行查询语句时产生的,下面先具体看一下如何产生这个异常的。

1、建立相关的库和表

1.1 建立hive测试库

在hive里执行如下语句

create database test;

1.2 建立oracle测试表

CREATE TABLE TEST
(	"ID" VARCHAR2(100), 
	"NUM" NUMBER(10,2)
)

1.3 在oracle表里插入一条记录

INSERT INTO TEST (ID, NUM) VALUES('1', 1);

2、spark sql代码

执行如下代码,便可以将之前在oracle里建的test的表导入到hive里了,其中hive的表会自动创建,具体的spark连接hive,连接关系型数据库,可以参考我的其他两篇博客:spark连接hive(spark-shell和eclipse两种方式)Spark Sql 连接mysql

package com.dkl.leanring.spark.sql

import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.SaveMode

object Oracle2HiveTest {
  def main(args: Array[String]): Unit = {

    //初始化spark
    val spark = SparkSession
      .builder()
      .appName("Oracle2HiveTest")
      .master("local")
      //      .config("spark.sql.parquet.writeLegacyFormat", true)
      .enableHiveSupport()
      .getOrCreate()

    //表名为我们新建的测试表
    val tableName = "test"

    //spark连接oracle数据库
    val df = spark.read
      .format("jdbc")
      .option("url", "jdbc:oracle:thin:@192.168.44.128:1521:orcl")
      .option("dbtable", tableName)
      .option("user", "bigdata")
      .option("password", "bigdata")
      .option("driver", "oracle.jdbc.driver.OracleDriver")
      .load()
    //导入spark的sql函数,用起来较方便
    import spark.sql
    //切换到test数据库
    sql("use test")
    //将df中的数据保存到hive表中(自动建表)
    df.write.mode(SaveMode.Overwrite).saveAsTable(tableName)
    //停止spark
    spark.stop
  }
}

3、在hive里查询

hive
use test;
select * from test;

这时就可以出现如标题所述的异常了,附图:

4、解决办法

将2里面spark代码中的.config("spark.sql.parquet.writeLegacyFormat", true)注释去掉,再执行一次,即可解决该异常,该配置的默认值为false,如果设置为true,Spark将使用与Hive相同的约定来编写Parquet数据。

5、异常原因

出现该异常的根本原因是由于Hive和Spark中使用的不同的parquet约定引起的,参考https://stackoverflow.com/questions/37829334/parquet-io-parquetdecodingexception-can-not-read-value-at-0-in-block-1-in-file中的最后一个回答(加载可能比较慢),由于博主英文水平不是那么的好,所以附上英文吧~

Root Cause:
This issue is caused because of different parquet conventions used in Hive and Spark. In Hive, the decimal datatype is represented as fixed bytes (INT 32). In Spark 1.4 or later the default convention is to use the Standard Parquet representation for decimal data type. As per the Standard Parquet representation based on the precision of the column datatype, the underlying representation changes.
eg: DECIMAL can be used to annotate the following types: int32: for 1 <= precision <= 9 int64: for 1 <= precision <= 18; precision < 10 will produce a warning

Hence this issue happens only with the usage of datatypes which have different representations in the different Parquet conventions. If the datatype is DECIMAL (10,3), both the conventions represent it as INT32, hence we won't face an issue. If you are not aware of the internal representation of the datatypes it is safe to use the same convention used for writing while reading. With Hive, you do not have the flexibility to choose the Parquet convention. But with Spark, you do.

Solution: The convention used by Spark to write Parquet data is configurable. This is determined by the property spark.sql.parquet.writeLegacyFormat The default value is false. If set to "true", Spark will use the same convention as Hive for writing the Parquet data. This will help to solve the issue.

6、注意

1.2中的建表语句中NUMBER(10,2)的精度(10,2)必须要写,如果改为NUMBER就不会出现该异常,至于其他精度会不会出现该问题,大家可自行测试。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • spark连接hive(spark-shell和eclipse两种方式)

    转载请务必注明原创地址为:http://dongkelun.com/2018/03/25/sparkHive/

    董可伦
  • spark 将DataFrame所有的列类型改为double

    转载请务必注明原创地址为:http://dongkelun.com/2018/04/27/dfChangeAllColDatatypes/

    董可伦
  • Spark通过修改DataFrame的schema给表字段添加注释

    通过Spark将关系型数据库(以Oracle为例)的表同步的Hive表,要求用Spark建表,有字段注释的也要加上注释。Spark建表,有两种方法:

    董可伦
  • 使用sqlite3 模块操作sqlite3数据库

    Python内置了sqlite3模块,可以操作流行的嵌入式数据库sqlite3。如果看了我前面的使用 pymysql 操作MySQL数据库这篇文章就更简单了。因...

    乐百川
  • 解决使用innobackupex备份mysql产生returned OS error 124

    这个是指mysql进程超出了打开最多的文件数量,检查下mysql数据文件data目录下的文件总数。

    bboysoul
  • 解决使用innobackupex备份mysql产生returned OS error 124

    这个是指mysql进程超出了打开最多的文件数量,检查下mysql数据文件data目录下的文件总数。

    bboysoul
  • 送给前端的你:可视化快速生成模拟数据服务——Easy Mock

    ? 内容来源:2017年11月18日,大搜车前端工程师高攀在“2017中国开源年会”进行《Easy Mock 接口数据模拟服务》演讲分享。IT 大咖说(微信i...

    IT大咖说
  • dataframe行变换为列

    使用 import org.apache.spark.sql.functions 里面的函数,具体的方式可以看 functions :

    机器学习和大数据挖掘
  • Spark Sql 源码剖析(一):sql 执行的主要流程

    之前写过不少 Spark Core、Spark Streaming 相关的文章,但使用更广泛的 Spark Sql 倒是极少,恰好最近工作中使用到了,便开始研读...

    codingforfun
  • CodeForces 732C Sanatorium

    C. Sanatorium time limit per test 1 second memory limit per test 256 megab...

    ShenduCC

扫码关注云+社区

领取腾讯云代金券