Spark Structured Streaming使用from_json函数运行Jar时报错求助
解决Spark打包Jar后
from_json抛出NoSuchMethodError的问题 太懂这种本地跑正常、一打包就报错的糟心情况了,先还原下你的问题场景:
从Kafka读取数据的Spark代码:
val hiveDf = parsedDf .select(from_json(col("value"), schema).as("value")) .selectExpr("value.*")在IntelliJ里运行一切顺畅,但打包成Jar提交到集群后直接抛出错误:
Exception in thread "main" java.lang.NoSuchMethodError: org.apache.spark.sql.functions$.from_json(Lorg/apache/spark/sql/Column;Lorg/apache/spark/sql/types/StructType;)Lorg/apache/spark/sql/Column;
问题根源
这个错误本质是依赖版本不兼容导致的:
- 本地IntelliJ运行时,用的是你项目配置的Spark依赖版本;但集群运行时,用的是集群自身的Spark版本,两个版本对不上——
from_json的方法签名在Spark 2.x和3.x版本中有明显差异,比如参数类型、返回值定义的变化,导致找不到匹配的方法。 - 另一种常见情况是打包时把Spark核心依赖也打进了Jar,和集群环境的Spark依赖冲突,最终加载了错误版本的方法。
一步步解决
1. 对齐Spark版本
先确认你的项目依赖的Spark版本,和运行代码的集群Spark版本完全一致。比如集群用的是Spark 3.3.0,那你的pom.xml(Maven)或build.sbt(SBT)里必须指定同一个版本。
举个配置例子:
- Maven配置:
<dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-sql_2.12</artifactId> <version>3.3.0</version> <scope>provided</scope> <!-- 重点:标记为provided,避免打包进Jar --> </dependency> - SBT配置:
libraryDependencies += "org.apache.spark" %% "spark-sql" % "3.3.0" % Provided
2. 正确设置依赖范围
把所有Spark相关的依赖(spark-core、spark-sql、spark-streaming-kafka-0-10等)的scope都设为provided(Maven)或Provided(SBT)。这样打包时这些依赖不会被包含到最终Jar里,运行时直接复用集群环境的Spark依赖,从根源避免版本冲突。
3. 排查隐藏的依赖冲突
有时候第三方依赖会偷偷引入不同版本的Spark组件,这时候需要检查依赖树:
- Maven用户执行命令:
mvn dependency:tree - SBT用户执行命令:
sbt dependencyTree
如果发现某个依赖带了不兼容的Spark版本,就把它排除掉。比如Maven里的排除配置:
<dependency> <groupId>com.example</groupId> <artifactId>some-third-lib</artifactId> <version>1.0.0</version> <exclusions> <exclusion> <groupId>org.apache.spark</groupId> <artifactId>spark-sql_2.12</artifactId> </exclusion> </exclusions> </dependency>
4. 用专业插件打包
别用IntelliJ自带的"Build Artifacts"打包,这种方式容易把所有依赖都塞进Jar。推荐用Maven的assembly插件或者SBT的assembly插件来打包,并且配置排除Spark相关依赖。
比如Maven的assembly插件配置:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>3.3.0</version> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <excludeGroupIds>org.apache.spark</excludeGroupIds> <!-- 排除Spark所有依赖 --> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin>
按照这些步骤排查,基本就能解决这个问题了。
内容的提问来源于stack exchange,提问作者Naman Agarwal
相关产品推荐
相关产品推荐

