java.sql.SQLException: 将 DataFrame 加载到 Spark 时未找到合适的驱动程序 SQL
java.sql.SQLException: No suitable driver found when loading DataFrame into Spark SQL
我在尝试将 JDBC DataFrame 加载到 Spark SQL 中时遇到了一个非常奇怪的问题。
我在我的笔记本电脑上尝试了几种 Spark 集群——YARN、独立集群和伪分布式模式。它在 Spark 1.3.0 和 1.3.1 上都是可重现的。 spark-shell
和使用 spark-submit
执行代码时都会出现问题。我试过 MySQL & MS SQL JDBC 驱动程序但没有成功。
考虑以下示例:
val driver = "com.mysql.jdbc.Driver"
val url = "jdbc:mysql://localhost:3306/test"
val t1 = {
sqlContext.load("jdbc", Map(
"url" -> url,
"driver" -> driver,
"dbtable" -> "t1",
"partitionColumn" -> "id",
"lowerBound" -> "0",
"upperBound" -> "100",
"numPartitions" -> "50"
))
}
到目前为止一切顺利,架构得到正确解析:
t1: org.apache.spark.sql.DataFrame = [id: int, name: string]
但是当我评估 DataFrame 时:
t1.take(1)
发生以下异常:
15/04/29 01:56:44 WARN TaskSetManager: Lost task 0.0 in stage 0.0 (TID 0, 192.168.1.42): java.sql.SQLException: No suitable driver found for jdbc:mysql://<hostname>:3306/test
at java.sql.DriverManager.getConnection(DriverManager.java:689)
at java.sql.DriverManager.getConnection(DriverManager.java:270)
at org.apache.spark.sql.jdbc.JDBCRDD$$anonfun$getConnector.apply(JDBCRDD.scala:158)
at org.apache.spark.sql.jdbc.JDBCRDD$$anonfun$getConnector.apply(JDBCRDD.scala:150)
at org.apache.spark.sql.jdbc.JDBCRDD$$anon.<init>(JDBCRDD.scala:317)
at org.apache.spark.sql.jdbc.JDBCRDD.compute(JDBCRDD.scala:309)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:277)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:244)
at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:35)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:277)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:244)
at org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:61)
at org.apache.spark.scheduler.Task.run(Task.scala:64)
at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:203)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
当我尝试在执行器上打开 JDBC 连接时:
import java.sql.DriverManager
sc.parallelize(0 until 2, 2).map { i =>
Class.forName(driver)
val conn = DriverManager.getConnection(url)
conn.close()
i
}.collect()
完美运行:
res1: Array[Int] = Array(0, 1)
当我在本地 Spark 上 运行 相同的代码时,它也能完美运行:
scala> t1.take(1)
...
res0: Array[org.apache.spark.sql.Row] = Array([1,one])
我正在使用预构建的 Spark,支持 Hadoop 2.4。
重现该问题的最简单方法是使用 start-all.sh
脚本和 运行 以下命令以伪分布式模式启动 Spark:
/path/to/spark-shell --master spark://<hostname>:7077 --jars /path/to/mysql-connector-java-5.1.35.jar --driver-class-path /path/to/mysql-connector-java-5.1.35.jar
有办法解决这个问题吗?这看起来是一个严重的问题,所以奇怪的是谷歌搜索在这里没有帮助。
显然最近有人报告了这个问题:
https://issues.apache.org/jira/browse/SPARK-6913
问题出在 java.sql.DriverManager 中,除了 bootstrap ClassLoader 之外,没有看到由 ClassLoader 加载的驱动程序。
作为临时解决方法,可以将所需的驱动程序添加到执行程序的引导类路径中。
更新:此拉取请求修复了问题:https://github.com/apache/spark/pull/5782
更新 2:修复合并到 Spark 1.4
我们卡在 Spark 1.3 (Cloudera 5.4) 上,所以我发现这个问题和 Wildfire 的回答很有帮助,因为它让我不再用头撞墙。
想我会分享我们如何将驱动程序放入引导类路径:我们只是将它复制到 /opt/cloudera/parcels/CDH-5.4.0-1.cdh5.4.0.p0.27/lib/hive/lib节点。
用于将数据写入MySQL
在 spark 1.4.0 中,您必须在写入之前加载 MySQL,因为它加载驱动程序是加载函数而不是写入函数。
我们必须将 jar 放在每个工作节点上,并在每个节点上的 spark-defaults.conf 文件中设置路径。
此问题已在 spark 1.5.0
中修复
我在 SQL 服务器上使用 spark-1.6.1,仍然面临同样的问题。我必须将库(sqljdbc-4。0.jar)添加到实例中的库和 conf/spark-dfault.conf
文件中的行下方。
spark.driver.extraClassPath lib/sqljdbc-4.0.jar
我在尝试将 JDBC DataFrame 加载到 Spark SQL 中时遇到了一个非常奇怪的问题。
我在我的笔记本电脑上尝试了几种 Spark 集群——YARN、独立集群和伪分布式模式。它在 Spark 1.3.0 和 1.3.1 上都是可重现的。 spark-shell
和使用 spark-submit
执行代码时都会出现问题。我试过 MySQL & MS SQL JDBC 驱动程序但没有成功。
考虑以下示例:
val driver = "com.mysql.jdbc.Driver"
val url = "jdbc:mysql://localhost:3306/test"
val t1 = {
sqlContext.load("jdbc", Map(
"url" -> url,
"driver" -> driver,
"dbtable" -> "t1",
"partitionColumn" -> "id",
"lowerBound" -> "0",
"upperBound" -> "100",
"numPartitions" -> "50"
))
}
到目前为止一切顺利,架构得到正确解析:
t1: org.apache.spark.sql.DataFrame = [id: int, name: string]
但是当我评估 DataFrame 时:
t1.take(1)
发生以下异常:
15/04/29 01:56:44 WARN TaskSetManager: Lost task 0.0 in stage 0.0 (TID 0, 192.168.1.42): java.sql.SQLException: No suitable driver found for jdbc:mysql://<hostname>:3306/test
at java.sql.DriverManager.getConnection(DriverManager.java:689)
at java.sql.DriverManager.getConnection(DriverManager.java:270)
at org.apache.spark.sql.jdbc.JDBCRDD$$anonfun$getConnector.apply(JDBCRDD.scala:158)
at org.apache.spark.sql.jdbc.JDBCRDD$$anonfun$getConnector.apply(JDBCRDD.scala:150)
at org.apache.spark.sql.jdbc.JDBCRDD$$anon.<init>(JDBCRDD.scala:317)
at org.apache.spark.sql.jdbc.JDBCRDD.compute(JDBCRDD.scala:309)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:277)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:244)
at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:35)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:277)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:244)
at org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:61)
at org.apache.spark.scheduler.Task.run(Task.scala:64)
at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:203)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
当我尝试在执行器上打开 JDBC 连接时:
import java.sql.DriverManager
sc.parallelize(0 until 2, 2).map { i =>
Class.forName(driver)
val conn = DriverManager.getConnection(url)
conn.close()
i
}.collect()
完美运行:
res1: Array[Int] = Array(0, 1)
当我在本地 Spark 上 运行 相同的代码时,它也能完美运行:
scala> t1.take(1)
...
res0: Array[org.apache.spark.sql.Row] = Array([1,one])
我正在使用预构建的 Spark,支持 Hadoop 2.4。
重现该问题的最简单方法是使用 start-all.sh
脚本和 运行 以下命令以伪分布式模式启动 Spark:
/path/to/spark-shell --master spark://<hostname>:7077 --jars /path/to/mysql-connector-java-5.1.35.jar --driver-class-path /path/to/mysql-connector-java-5.1.35.jar
有办法解决这个问题吗?这看起来是一个严重的问题,所以奇怪的是谷歌搜索在这里没有帮助。
显然最近有人报告了这个问题:
https://issues.apache.org/jira/browse/SPARK-6913
问题出在 java.sql.DriverManager 中,除了 bootstrap ClassLoader 之外,没有看到由 ClassLoader 加载的驱动程序。
作为临时解决方法,可以将所需的驱动程序添加到执行程序的引导类路径中。
更新:此拉取请求修复了问题:https://github.com/apache/spark/pull/5782
更新 2:修复合并到 Spark 1.4
我们卡在 Spark 1.3 (Cloudera 5.4) 上,所以我发现这个问题和 Wildfire 的回答很有帮助,因为它让我不再用头撞墙。
想我会分享我们如何将驱动程序放入引导类路径:我们只是将它复制到 /opt/cloudera/parcels/CDH-5.4.0-1.cdh5.4.0.p0.27/lib/hive/lib节点。
用于将数据写入MySQL
在 spark 1.4.0 中,您必须在写入之前加载 MySQL,因为它加载驱动程序是加载函数而不是写入函数。 我们必须将 jar 放在每个工作节点上,并在每个节点上的 spark-defaults.conf 文件中设置路径。 此问题已在 spark 1.5.0
中修复我在 SQL 服务器上使用 spark-1.6.1,仍然面临同样的问题。我必须将库(sqljdbc-4。0.jar)添加到实例中的库和 conf/spark-dfault.conf
文件中的行下方。
spark.driver.extraClassPath lib/sqljdbc-4.0.jar