这几天遇到了需要从hdfs加载json字符串,然后转化成json对象的场景。刚开始的实现方式见如下代码:
val loginLogRDD = sc.objectFile[String](loginFile, loadLoginFilePartitionNum)
.filter(jsonString => {
//val loginItem = line.toString().split("\t")
//LoginRecord(loginItem(0).toInt, loginItem(1), loginItem(2), loginItem(3).toInt, loginItem(4), loginItem(5), loginItem(6), loginItem(7).toInt, loginItem(8), loginItem(9), loginItem(10), loginItem(11), loginItem(12))
val json = JSON.parseFull(jsonString)
val resultJson = json match {
case Some(map: Map[String, Any]) => if (map.get("ip").getOrElse("").equals("")) false else true
case None => false
}
resultJson
}).
从以上代码可知,每条Json记录,都会创建Json解析器来进行解析。
这种方式加载速度特别慢,1s大概才1M左右,并且CPU也特别忙。因此推测是Spark程序有问题导致的。
为了提高记载速度,决定采用mapPartitions方式加载Json串,也就是每个分区只创建一个Json解析器,代码如下:
val loginLogRDD = sc.objectFile[String](loginFile, loadLoginFilePartitionNum)
.mapPartitions(jsonStringIter=>{
val mapper = new ObjectMapper()
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
mapper.registerModule(DefaultScalaModule)
jsonStringIter.map(record => {
try {
Some(mapper.readValue(record, classOf[JsonLoginRecord]))
} catch {
case e: Exception => None
}
})
})
修改之后,每秒加载速度达到了100多兆,速度提高了100多倍,效果截图如下: