关于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包起作用。这次记录先到这里,具体原因有时间再想想,或者有没有大佬分析一波。

posted @ 2021-04-10 16:27  这代码烫手  阅读(316)  评论(1)    收藏  举报