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 ...
随机推荐
- FPGA设计中的异步复位、同步释放思想
1.一个简单的异步复位例子: module test( input clk, input rst_n, input data_in, output reg out ); always@(posedge ...
- vscode 使用iView时标签报错 Parsing error: x-invalid-end-tag
错误展示: 问题原因: iView将标签渲染为原生html标签时,由于这些标签是自闭合的,所以有end标签会报错. 解决方案: 修改配置文件,忽略该项检查: 根目录下 - .eslintrc.js - ...
- UNDERSTANDING ITWEEN CALLBACKS
One of the most frequent problems I see people have with iTween is with callbacks that don't fire. A ...
- SQL 流水账余额查询
创建表 CREATE TABLE [dbo].[test]( ,) NOT NULL, [RQ] [date] NULL, [SR] [int] NULL, [ZC] [int] NULL ) ON ...
- Linux命令实例功能笔记
ls命令 ls对文件mtime时间进行排序 降序: ls -lt | grep '^-' 升序: ls -ltr | grep '^-' seq命令 求1000以内所有偶数的和 ech ...
- C++中关于new和delete的使用
1.创建动态数组 数组类型的变量有三个重要的限制:数组长度固定不变,在编译时必须知道它的长度,数组只在定义它的块语句中存在.对于动态分配的数组,虽然长度是固定的,但是动态分配的数组不必在编译时知道其长 ...
- drf解析器
1.简介 作用:将传过来的数据,解析成字典 2.使用 分为局部使用和全局使用 局部使用,什么都不写,默认就是 parser_classes = [JSONParser,FormParser] from ...
- Django 框架 django的请求生命周期
概述 首先我们知道HTTP请求及服务端响应中传输的所有数据都是字符串,同时http请求是无状态的,可以通过session和cookie来辅助. 浏览器通过ip和端口及路由方式访问服务端. 在Djang ...
- 对k8s service的一些理解
服务service service是一个抽象概念,定义了一个服务的多个pod逻辑合集和访问pod的策略,一般把service称为微服务 举个例子一个a服务运行3个pod,b服务怎么访问a服务的pod, ...
- 别再说找不到Python练手项目了,这80个拿去过冬
开头真的很重要!!!一个吻,一部小说,一篇文章......好的开头就像一个漂亮女孩的问候,问完了,你还期待着她接下来会对你说些什么甜蜜的话呢. 真可惜!我不是漂亮女孩,我的这个开头也不好.但开头不好, ...