You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spark连接BigQuery触发java.lang.NoSuchMethodError异常求助

解决Spark连接BigQuery时的Guava版本冲突问题

这个NoSuchMethodError确实是Guava版本不兼容导致的——com.google.common.base.Optional.toJavaUtil()方法是在Guava 21.0版本才新增的,而你本地Spark 2.3.x默认自带的Guava版本(一般是14.0.1)根本没有这个方法。

虽然你已经在sbt里排除了依赖并指定了新版本Guava,但问题出在Spark启动时的类加载顺序:本地Spark的classpath里自带的旧Guava会优先于你的fat jar里的新版本被加载,导致运行时调用了旧类的方法。

下面是几个可行的解决方法:

1. 强制Spark优先加载你的fat jar中的类

修改spark-submit命令,通过--driver-class-path参数把你的jar放在类路径最前面,确保驱动端优先加载你打包的新版本Guava:

spark-submit --deploy-mode client --driver-class-path BigQueryConnector.jar --class com.bigquery.OwnDataSetReader BigQueryConnector.jar

这个方法不需要修改Spark的安装文件,对其他任务无影响,是最推荐的临时解决方案。

2. 替换Spark自带的Guava jar

如果你希望所有本地Spark任务都使用新版本Guava,可以直接替换Spark安装目录下的旧Guava包:

  • 找到Spark安装路径下的jars文件夹,删除其中的guava-*.jar(比如guava-14.0.1.jar)
  • 把你使用的guava-30.0-jre.jar复制到这个jars文件夹中

注意:这个操作会影响所有本地Spark任务,如果其他任务依赖旧版本Guava的特性,可能会引发新的问题,需要谨慎测试。

3. 强化sbt依赖管理,确保编译期完全统一Guava版本

在你的build.sbt中添加dependencyOverrides,强制所有依赖库都使用指定的Guava版本,避免编译期出现潜在的版本不一致:

name := "bigquer-connector"
version := "0.1"
scalaVersion := "2.11.8"
test in assembly := {}
assemblyJarName in assembly := "BigQueryConnector.jar"
assemblyMergeStrategy in assembly := {
  case x if x.startsWith("META-INF") => MergeStrategy.discard
  case x =>
    val oldStrategy = (assemblyMergeStrategy in assembly).value
    oldStrategy(x)
}

// 强制所有依赖使用统一的Guava版本
dependencyOverrides += "com.google.guava" % "guava" % "30.0-jre"

libraryDependencies += ("com.google.cloud.spark" %% "spark-bigquery" % "0.18.0")
  .exclude("com.google.guava", "guava")
  .exclude("org.glassfish.jersey.bundles.repackaged", "jersey-guava")
libraryDependencies += "com.google.guava" % "guava" % "30.0-jre"
libraryDependencies += ("org.apache.spark" % "spark-core_2.11" % "2.3.1")
  .exclude("com.google.guava", "guava")
  .exclude("org.glassfish.jersey.bundles.repackaged", "jersey-guava")
libraryDependencies += ("org.apache.spark" % "spark-sql_2.11" % "2.3.1")
  .exclude("com.google.guava", "guava")
  .exclude("org.glassfish.jersey.bundles.repackaged", "jersey-guava")

调试验证

可以在你的主类中添加一行代码,打印运行时实际加载的Guava版本,确认问题是否解决:

object OwnDataSetReader extends App {
  // 打印Guava版本,验证是否加载了正确的版本
  println("Loaded Guava version: " + com.google.common.base.Optional.class.getPackage().getImplementationVersion())

  val session = SparkSession.builder()
    .appName("big-query-connector")
    .config(getConf)
    .getOrCreate()

  // ... 剩余代码不变
}

如果输出是30.0-jre,说明版本加载正确,问题应该就能解决了。

内容的提问来源于stack exchange,提问作者Anoop Deshpande

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:07:18