Spring Boot+Spark 3.2.1调用Dataset.show()方法报错求助
问题描述
使用Spring Boot + Apache Spark 3.2.1通过JDBC读取Hive数据时,调用Dataset.show()方法抛出以下错误:
org.apache.spark.scheduler.DAGScheduler : ResultStage 7 (show at SampleHiveController.java:62) failed in 7,461 s due to Job aborted due to stage failure: Task 0 in stage 7.0 failed 1 times, most recent failure: Lost task 0.0 in stage 7.0 (TID 5) : java.sql.SQLException: Illegal conversion at org.apache.hive.jdbc.HiveBaseResultSet.getBigDecimal(HiveBaseResultSet.java:137)
调用count()和printSchema()方法均正常运行,相关代码如下:
@RequestMapping(value = "/spark", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<List<Map<String, Object>>> showSpark() { SparkSession spark = SparkSession .builder() .master("local") .appName("Java Spark Hive Example") .enableHiveSupport() .getOrCreate(); Dataset<Row> df = spark.read() .format("jdbc") .option("url", "jdbc:hive2://hdp31-dev-03.dmp.test.com:2181,hdp31-dev-01.dmp.test.com:2181,hdp31-dev-02.dmp.test.com:2181/;serviceDiscoveryMode=zooKeeper;zooKeeperNamespace=hiveserver2;principal=hive/_HOST@WE.TEST.COM") .option("dbtable", "dds_test.test") .option("user", "user") .option("password", "test") .option("driver", "org.apache.hive.jdbc.HiveDriver") .load(); System.out.println("*** Right after ingestion"); df.printSchema(); df.show(); }
原因分析
show()方法需要完整序列化并展示数据,而count()仅统计行数、printSchema()仅读取元数据,都不会触发全量数据类型转换。报错指向getBigDecimal的非法转换,说明Hive表中存在Spark JDBC驱动无法自动转换为BigDecimal的字段类型——比如Hive的decimal精度/标度超出驱动支持范围、字段存储了非数值内容,或是Spark与Hive的类型映射规则不兼容。
解决方案
方案1:指定自定义字段映射
在JDBC读取时,通过customSchema参数强制指定字段类型,绕过自动转换逻辑:
Dataset<Row> df = spark.read() .format("jdbc") .option("url", "...") .option("dbtable", "dds_test.test") .option("user", "user") .option("password", "test") .option("driver", "org.apache.hive.jdbc.HiveDriver") // 将问题字段转为String,后续按需处理 .option("customSchema", "id INT, problematic_col STRING, other_col DOUBLE") .load();
方案2:调整Spark类型转换配置
修改Spark的JDBC转换规则,允许宽松转换或精度损失:
spark.conf().set("spark.sql.decimalOperations.allowPrecisionLoss", "true"); spark.conf().set("spark.sql.jdbc.typeConversionMode", "relaxed");
添加上述配置后再读取数据,可避免严格类型校验导致的报错。
方案3:使用Hive原生读取
既然已启用enableHiveSupport(),直接通过Spark SQL读取Hive表,跳过JDBC层的类型转换问题:
Dataset<Row> df = spark.sql("SELECT * FROM dds_test.test");
需确保Spark配置了正确的Hive metastore地址,保证元数据同步。
方案4:检查并修复Hive表
查看Hive表结构和数据,定位异常字段:
-- 查看表结构 DESCRIBE dds_test.test; -- 检查问题字段数据 SELECT problematic_col FROM dds_test.test LIMIT 10;
若存在decimal类型精度超标或数据非法,可修改表结构或清洗数据。
内容的提问来源于stack exchange,提问作者Tim

