MongoDB With Spark遇到的2个错误,不能初始化和sample重复的key
1.$sample stage could not find a non-duplicate document while using a random cursor
这个问题比较难解决,因为我用mongodb spark connector没用到sample,但是在生成RDD的过程中会进行sample操作,所以没法避免,出现这个问题的原因也不可控,在jira上有这个问题,但并没有一个合理的解决方案,stackoverflow上也没有解决办法,就我个人而言,出现这个问题有几个特征:
a) 出现在sharding 集群中,因为我单机不用spark,也不会出现这种问题,而在搜索过程中发现遇到这问题的人非常少,而且很多都不可再现,而spark连sharding集群会一直出这个问题。
b) 似乎和shardsvr有直接联系,出现这问题的机器一直是其中一台shardsvr,而之前同样的程序在集群中是跑通过的,所以怀疑是上次异常断电导致这台shardsvr有什么设置出现了问题。
解决方案目前可以使用sparkSession.config设置这项参数,也可以直接在readConfig里设置这项参数,如sparkSession进行如下设置:
- lazy val spark = SparkSession.builder()
- .master("spark://192.168.12.161:7077")
- .config(new SparkConf().setJars(Array("hdfs://192.168.12.161:9000/mongolib/mongo-spark-connector_2.11-2.0.0.jar",
- "hdfs://192.168.12.161:9000/mongolib/bson-3.4.2.jar",
- "hdfs://192.168.12.161:9000/mongolib/mongo-java-driver-3.4.2.jar",
- "hdfs://192.168.12.161:9000/mongolib/mongodb-driver-3.4.2.jar",
- "hdfs://192.168.12.161:9000/mongolib/mongodb-driver-core-3.4.2.jar",
- "hdfs://192.168.12.161:9000/mongolib/commons-io-2.5.jar",
- "hdfs://192.168.12.161:9000/mongolib/config-1.2.1.jar",
- "hdfs://192.168.12.161:9000/ScheduleImport.jar")))
- .config("spark.cores.max", 80)
- .config("spark.executor.cores", 16)
- .config("spark.executor.memory", "32g")
- .config("spark.mongodb.input.uri", s"mongodb://${user}:${passwd}@192.168.12.161:27017/wenshu.origin2?authSource=${authDB}")
- .config("spark.mongodb.output.uri", s"mongodb://${user}:${passwd}@192.168.12.160:27017/wenshu.backup?authSource=${authDB}")
- .config("spark.mongodb.input.partitionerOptions.samplesPerPartition", 1)
- .getOrCreate()
这个参数在Connector中的作用如下:
- override def partitions(connector: MongoConnector, readConfig: ReadConfig, pipeline: Array[BsonDocument]): Array[MongoPartition] = {
- Try(PartitionerHelper.collStats(connector, readConfig)) match {
- case Success(results) =>
- val matchQuery = PartitionerHelper.matchQuery(pipeline)
- val partitionerOptions = readConfig.partitionerOptions.map(kv => (kv._1.toLowerCase, kv._2))
- val partitionKey = partitionerOptions.getOrElse(partitionKeyProperty, DefaultPartitionKey)
- val partitionSizeInBytes = partitionerOptions.getOrElse(partitionSizeMBProperty, DefaultPartitionSizeMB).toInt * 1024 * 1024
- val samplesPerPartition = partitionerOptions.getOrElse(samplesPerPartitionProperty, DefaultSamplesPerPartition).toInt
- val count = if (matchQuery.isEmpty) {
- results.getNumber("count").longValue()
- } else {
- connector.withCollectionDo(readConfig, { coll: MongoCollection[BsonDocument] => coll.count(matchQuery) })
- }
- val avgObjSizeInBytes = results.get("avgObjSize", new BsonInt64(0)).asNumber().longValue()
- val numDocumentsPerPartition: Int = math.floor(partitionSizeInBytes.toFloat / avgObjSizeInBytes).toInt
- val numberOfSamples = math.floor(samplesPerPartition * count / numDocumentsPerPartition.toFloat).toInt
- if (numDocumentsPerPartition >= count) {
- MongoSinglePartitioner.partitions(connector, readConfig, pipeline)
- } else {
- val samples = connector.withCollectionDo(readConfig, {
- coll: MongoCollection[BsonDocument] =>
- coll.aggregate(List(
- Aggregates.`match`(matchQuery),
- Aggregates.sample(numberOfSamples),
- Aggregates.project(Projections.include(partitionKey)),
- Aggregates.sort(Sorts.ascending(partitionKey))
- ).asJava).allowDiskUse(true).into(new util.ArrayList[BsonDocument]()).asScala
- })
- def collectSplit(i: Int): Boolean = (i % samplesPerPartition == 0) || !matchQuery.isEmpty && i == count - 1
- val rightHandBoundaries = samples.zipWithIndex.collect {
- case (field, i) if collectSplit(i) => field.get(partitionKey)
- }
- val addMinMax = matchQuery.isEmpty
- val partitions = PartitionerHelper.createPartitions(partitionKey, rightHandBoundaries, PartitionerHelper.locations(connector), addMinMax)
- if (!addMinMax) PartitionerHelper.setLastBoundaryToLessThanOrEqualTo(partitionKey, partitions)
- partitions
- }
- case Failure(ex: MongoCommandException) if ex.getErrorMessage.endsWith("not found.") || ex.getErrorCode == 26 =>
- logInfo(s"Could not find collection (${readConfig.collectionName}), using a single partition")
- MongoSinglePartitioner.partitions(connector, readConfig, pipeline)
- case Failure(e) =>
- logWarning(s"Could not get collection statistics. Server errmsg: ${e.getMessage}")
- throw e
- }
- }
- // scalastyle:on cyclomatic.complexity
- }
上面这段是connector中的代码,作用是划分partition,sample的大小不会影响数据准确性,只会影响性能。改成1可以避免这个错误。
2、带验证的数据读写,不能初始化类。
有些时候我会将部分数据读出来,修改后更新回原collection,但是MongoSpark.write操作只能写入到一张不存在的表中,不能进行upsert,所以需要在分发任务的时候序列化一个(val dbColl: MongoCollection[Document] = db.getCollection("")),把它传到每个task中,这样我就可以处理完一部分数据之后直接用这个MongoCollection写回到表里,rdd.foreach(x => {???? dbColl.replaceOne(eqq("_id", y.get("_id")), y, new UpdateOptions().upsert(true))})。这个在没有认证的时候是可以的,但是在有认证的情况下会报不能初始化类的错误,仔细看错误路径发现报错部分在dbColl.replaceOne这句。经过若干次尝试,发现:
a) 如果在rdd.foreach之前使用val mongoURI = new MongoClientURI(uri)会报MongoClientURI不能被序列化的错。
b) 如果这个写在main()之前,会出现不能初始化类的错误。
c) 如果这个写在里面,但是rdd.foreach中用到了外面声明的一个Calendar,也会报不能初始化类的错误。
d) 把Calendar转化为字符串,val mongoURI = new MongoClientURI(uri)都写在foreach里面,可以正确执行。
得出结论如下:
好多乱七八糟的类不能被序列化,不能被序列化的东西需要分发的话就会报这个错误。但是知道了原理还得想个解决方案,毕竟每条数据都创建一个mongoclient实在有点怪怪的,所以最后决定使用foreachPartition,具体如下:
- val rdd = MongoSpark.builder().sparkSession(spark).build().toRDD()
- // val df = MongoSpark.builder().sparkSession(spark).build.toDF
- // MongoSpark.save(df.write)
- rdd.cache()
- println(rdd.count())
- val uri = s"mongodb://${user}:${passwd}@192.168.12.161:27017/?authSource=${authDB}"
- val uri2 = s"mongodb://${config.getString("mongo.backup.user")}:${config.getString("mongo.backup.passwd")}@192.168.12.160:27017/?authSource=${config.getString("mongo.backup.authDB")}"
- rdd.foreachPartition { x => {
- val mongoURI = new MongoClientURI(uri)
- val mongo = new MongoClient(mongoURI)
- val db = mongo.getDatabase("wenshu")
- val dbColl = db.getCollection("origin")
- //val mongoURI2 = new MongoClientURI(s"mongodb://${config.getString("mongo.backup.user")}:${config.getString("mongo.backup.user")}@192.168.12.160:27017/?authSource=${config.getString("mongo.backup.user")}")
- val mongoURI2 = new MongoClientURI(uri2)
- val mongo2 = new MongoClient(mongoURI2)
- val db2 = mongo2.getDatabase("wenshu")
- val dbColl2 = db2.getCollection(backName)
- x.foreach { y =>
- dbColl.replaceOne(eqq("_id", y.get("_id")), y, new UpdateOptions().upsert(true))
- dbColl2.insertOne(y)
- }
- mongo.close
- mongo2.close
- } }
MongoDB With Spark遇到的2个错误,不能初始化和sample重复的key的更多相关文章
- c++中深层复制(浅层复制运行错误)成功运行-----sample
下面随笔给出c++中深层复制(浅层复制运行错误)成功运行------sample. 浅层复制与深层复制 浅层复制 实现对象间数据元素的一一对应复制. 深层复制 当被复制的对象数据成员是指针类型时,不是 ...
- Mongodb集群搭建过程及常见错误
Replica Sets MongoDB 支持在多个机器中通过异步复制达到故障转移和实现冗余.多机器中同一时刻只 有一台是用于写操作.正是由于这个情况,为 MongoDB 提供了数据一致性的保障.担当 ...
- spark mllib配置pom.xml错误 Multiple markers at this line Could not transfer artifact net.sf.opencsv:opencsv:jar:2.3 from/to central (https://repo.maven.apache.org/maven2): repo.maven.apache.org
刚刚spark mllib,在maven repository网站http://mvnrepository.com/中查询mllib后得到相关库的最新dependence为: <dependen ...
- Spark随机深林扩展—OOB错误评估和变量权重
本文目的 当前spark(1.3版)随机森林实现,没有包括OOB错误评估和变量权重计算.而这两个功能在实际工作中比较常用.OOB错误评估可以代替交叉检验,评估模型整体结果,避免交叉检验带来的计算开销. ...
- Mongodb解决不能连接到服务器的错误
注:这次解决的这个问题的前提是之前打开MongoDB之后,再次使用的时候无法连接了(使用mongod和mongo都不对) 闲话:遇到这种问题真是让人恼火,所以说句sun of beach,好了~爽 正 ...
- MongoDB,HDFS, Spark to 电影推荐
http://www.infoq.com/cn/news/2014/12/mongdb-spark-movie-recommend MovieWeb是一个电影相关的网站,它提供的功能包括搜索电影信息. ...
- MongoDB的“not master and slaveok=false”错误解决
在客户端操作MongoDB时经常会如下错误: SECONDARY> show collections; Fri Jul :: uncaught exception: error: { } 原因是 ...
- MongoDB:数据导入CSV文件之错误记录
测试主机1:Windows 10,MongoDB 3.6.3,WPS 10.1,Notepad++ 7.5.3, 测试主机2:Ubuntu 16.04,MongoDB 4, 今天测试了将数据从文件—— ...
- spark出现task不能序列化错误的解决方法 org.apache.spark.SparkException: Task not serializable
import org.elasticsearch.cluster.routing.Murmur3HashFunction; import org.elasticsearch.common.math.M ...
随机推荐
- 催希凡javaweb 学习28天
看到这样的博客,自己也在看传智播客的视频,收藏一下 催希凡javaweb 学习28天 http://www.cnblogs.com/Prozhu/category/824899.html
- pycharm快捷键帮助文档Keymap Reference
前面我们已经安装了pycharm,为了提升效率,我们一般会用到快捷键操作,pycharm有哪些快捷键呢?Pycharm中打开Help->Keymap Reference可查看默认快捷键帮助文档, ...
- 小程序升级实时音视频录制及播放能力,开放 Wi-Fi、NFC(HCE) 等硬件连接功能
“ 小程序升级实时音视频录制及播放能力,开放 Wi-Fi.NFC(HCE) 等硬件连接功能.同时提供按需加载.自定义组件和更多访问层级等新特性,增强了第三方平台的能力,以满足日趋丰富的业务需求.” 0 ...
- MySQL复制异常大扫盲:快速溯源与排查错误全解
MySQL复制异常大扫盲:快速溯源与排查错误全解https://mp.weixin.qq.com/s/0Ic8BnUokyOj7m1YOrk1tA 作者介绍王松磊,现任职于UCloud,从事MySQL ...
- jvm - 类的初始化过程
我们知道,我们写的java代码称为源码,想要能够被jvm执行首先需要编译成.class文件,那么编译完到使用又都经理的哪些阶段呢?主要分为以下三个阶段: 加载:查找并加载类的二进制数据(.class文 ...
- C语言数据类型运算法则
整形与整形运算得到的还是整形 printf("%d\n",1/3); //0 printf("%d\n",1+2); //3 整形与浮点型运算得到浮点型数据 p ...
- js中的offsetLeft和style.left
(1)style.left是带单位"px"的,而offsetLeft没有单位,另外,style.left必须是内联样式,或者在JS中通过style.left赋值,否则取得的将为空字 ...
- iot-hub物管理bug
物管理中,物绑定证书,如果证书被删除,将会出错 初始化用到 证书编码,证书为null时,null.code报错
- 对k8s service的一些理解
服务service service是一个抽象概念,定义了一个服务的多个pod逻辑合集和访问pod的策略,一般把service称为微服务 举个例子一个a服务运行3个pod,b服务怎么访问a服务的pod, ...
- 如何打印一棵树(Java)
1.有一棵多叉树,将它打印出来. import java.util.LinkedList; /** * 需求:按层打印一棵树 * 说明:树是保存在一个链表中 * created by wangjunf ...