关于spark.sql.dataframe.saveToMongoDB报错
问题出现的环境
这个问题卡了好久,心态都崩了,虽然我可以选择换其他数据库,但是就是感觉很不爽(主要是看的教学视频用的mongo,不一致就很难受)。
关于dataframe是什么的问题在这篇博客中有详细提及。以及如何生成dataframe。
然后mongodb的资料可以参见官网
先说一下我遇见的问题吧,环境:spark3.1.1,scala2.12,mongodb-spark-connector3.0.1
<properties>
<mongodb-spark.version>3.0.1</mongodb-spark.version>
<casbah.version>3.1.1</casbah.version>
<spark.version>3.1.1</spark.version>
<scala.version>2.12.13</scala.version>
<jblas.version>1.2.1</jblas.version>
<encoding>UTF-8</encoding>
</properties>
<!-- https://mvnrepository.com/artifact/org.mongodb/mongo-java-driver -->
<!-- <dependency>-->
<!-- <groupId>org.mongodb</groupId>-->
<!-- <artifactId>mongo-java-driver</artifactId>-->
<!-- <version>3.12.7</version>-->
<!-- </dependency>-->
<!-- 引入Spark相关的Jar包 -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.12</artifactId>
<version>${spark.version}</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.12</artifactId>
<version>${spark.version}</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>${scala.version}</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>casbah-core_2.12</artifactId>
<version>${casbah.version}</version>
</dependency>
<dependency>
<groupId>org.mongodb.spark</groupId>
<artifactId>mongo-spark-connector_2.12</artifactId>
<version>${mongodb-spark.version}</version>
</dependency>
</dependencies>
//打开一个sparkSession
val spark=SparkSession.builder()
.appName("writeToMongo")
.master("local[*]")
.getOrCreate()
//加载数据
val rdd1=spark.sparkContext.textFile("cust.txt")
//声明spark隐式函数
import spark.implicits._
//处理数据并转为DataFrame格式
val df1=rdd1.map(line=>{
val arr=line.split(",")
(arr(0).toInt,arr(1),arr(2).toInt)
}).toDF("id","name","age")
//打印数据是否生成我们的DataFrame
df1.show(1000,false)
// 新建一个mongodb的连接,客户端
val mongoClient = MongoClient( MongoClientURI(mongoConfig.uri) )
// 定义要操作的mongodb表,可以理解为 db.Product
val test= mongoClient("local")("test")
test.dropCollection()
//用dataFrame.write方法来写入数据库
df1
.write
.format("com.mongodb.spark.sql.DefaultSource")
.option("spark.mongodb.output.uri", "mongodb://localhost:27017/local.test")
.mode("overwrite")
.save()
// 对表创建索引
test.createIndex( MongoDBObject( "productId" -> 1 ) )
mongoClient.close()
//关闭sparkSession
spark.stop()
在以上操作下得到如下报错

分析问题出现的原因
首先分析这个错误,大部分说法是jar包的问题,而后我仔细对应了版本,发现版本没有错,错的是我,别人的视频中可以用,但是我不配。
而后提出几个可能出现问题的原因:
1.jar包版本问题;
2.dataframe写入配置问题;
3.数据库版本的兼容性;
4.驱动问题;
针对是否是jar包问题
我反复去查看自己硬件配置和依赖版本,通过不断更换版本发现徒劳无功
dataframe写入配置问题
我尝试了插入一条数据,用相同的配置,发现是可以连接并成功插入
import com.mongodb.DBObject
import com.mongodb.casbah.{MongoClient, MongoCollection}
import com.mongodb.util.JSON
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.sql.SQLContext
val conf: SparkConf = new SparkConf().setMaster("local").setAppName("CreateDFFromJsonFile")
val sqlContext = SparkSession.builder().config(conf).getOrCreate()
// 构造一个Json字符串
val json = s"""{
| "school_code" : "1910434024",
| "school_name" : "szu",
| "teacher_idcard" : "250",
| "teacher_name" : "hjj"
|}
|""".stripMargin
println(json.toString)
val mongoClient = MongoClient( MongoClientURI("mongodb://localhost:27017/local") )
val collection: MongoCollection = mongoClient("local")("test")
val bson: DBObject = JSON.parse(json).asInstanceOf[DBObject]
collection.insert(bson) // mongodb casbah的写法
}
猜测是否是真的是dataframe问题,但是我对dataframe对象进行各种操作发现并没有什么问题。那么真相只有一个,dataframe写入mongodb中间操作问题。查看了许久源码,也没发现问题在哪。
对于MongoDB版本兼容性问题
我尝试更换MongoDB的版本,来回试,结果一无所获。看来不是版本兼容性问题。
驱动问题
一般来说驱动是官方给的,不会出现什么问题,我只是抱着尝试的心态,试一哈,将MongoDB-java-driver放了进去,真是,突如其来的惊喜,竟然不报错了。
总结
虽然这个问题看似解决了,但是我知道,根本问题的原因并没有找到。而后通过不断尝试将错误定位到casbah-core_2.12和mongo-spark-connector_2.12两个jar包冲突的问题上,具体原因有待分析,先记录一下。若不用mongoClient连接引入connector就可以将dataframe数据成功写入,要对单个集合操作把casbah引入就可以了,值得一提的是,在jar包引入时,出现冲突时,先引入的jar包起作用。这次记录先到这里,具体原因有时间再想想,或者有没有大佬分析一波。

浙公网安备 33010602011771号