使用Spark.read.jdbc通过JDBC协议读取Hive数据时出现NumberFormatException异常
解决方案:Spark JDBC读取Hive表报NumberFormatException
这个问题我之前排查过,核心原因是Spark通过JDBC访问Hive时的元数据处理逻辑,和直接通过Hive元存储(spark.read.table依赖的是这个)的逻辑不一致——错误里把列名c1当成数据行来尝试转整数,说明JDBC驱动要么误把表头当成了数据,要么自动推断Schema时读错了数据源。下面是几个经过验证的可行方案:
方案1:改用SQL查询替代table参数
直接用query参数指定查询语句,绕开JDBC驱动对table参数的解析问题,同时明确指定要读取的列:
df = spark.read.jdbc( url="jdbc:hive2://ip:port", query="SELECT c1, col2, col3 FROM db.table", # 明确列出所有需要的列 properties={"user": "your_username", "password": "your_password"} # 补充你的JDBC认证信息 )
这种方式更直接,能避免驱动对表名解析的潜在bug。
方案2:手动指定Schema,关闭自动推断
Spark自动推断Schema时,可能因为JDBC返回的数据流格式问题,误把列名当成了第一行数据。手动定义Schema可以强制指定列类型:
from pyspark.sql.types import StructType, StructField, IntegerType, StringType # 根据实际列类型调整 # 按照表的实际结构定义Schema custom_schema = StructType([ StructField("c1", IntegerType(), nullable=True), StructField("col2", StringType(), nullable=True), # 其他列依次添加 ]) df = spark.read.jdbc( url="jdbc:hive2://ip:port/db", # 这里可以直接指定数据库,后面table只用表名 table="table", properties={...}, schema=custom_schema # 指定手动定义的Schema )
方案3:检查JDBC URL和驱动版本
- 修正JDBC URL格式:确保URL包含数据库名,比如
jdbc:hive2://ip:port/db,而不是只到端口,这样table参数只用表名即可,避免db.table的解析问题。 - 匹配驱动版本:确保你的Hive JDBC驱动版本和Spark、Hive集群版本兼容。比如Spark 3.x建议搭配Hive 3.x的驱动,版本不匹配会导致各种元数据读取异常。
方案4:调整JDBC连接属性
添加fetchsize或者hive.resultset.use.unique.column.names这类属性,修正驱动的行为:
properties = { "user": "your_user", "password": "your_pass", "fetchsize": "1000", "hive.resultset.use.unique.column.names": "false" } df = spark.read.jdbc( url="jdbc:hive2://ip:port/db", table="table", properties=properties )
hive.resultset.use.unique.column.names这个参数会影响驱动返回的列名格式,关闭它可以避免列名被修改,进而避免Schema推断错误。
内容的提问来源于stack exchange,提问作者Syehunter
相关产品推荐
相关产品推荐

