如何计算火花中的某个字符



我想计算火花壳中的字符"a"。我有一个有点麻烦的方法,用"a"和"长度 - 1"分开是我想要的。这是代码:

val sqlContext = new org.apache.spark.sql.SQLContext(sc)
val test_data = sqlContext.read.json("music.json")
test_data.registerTempTable("test_data")
val temp1 = sqlContext.sql("select user.id_str as userid, text from test_data")
val temp2 = temp1.map(t => (t.getAs[String]("userid"),t.getAs[String]("text").split('a').length-1))

但是,有人告诉我,这并不安全。我不知道为什么,你能给我一个更好的方法来做到这一点吗?

这是不安全的,因为如果值NULL

val df = Seq((1, None), (2, Some("abcda"))).toDF("id", "text")

getAs[String]将返回null

scala> df.first.getAs[String]("text") == null
res1: Boolean = true

split将给出 NPE:

scala> df.first.getAs[String]("text").split("a")
java.lang.NullPointerException
...

这很可能是您在上一个问题中遇到的情况。

一个简单的解决方案:

import org.apache.spark.sql.functions._
val aCnt = coalesce(length(regexp_replace($"text", "[^a]", "")), lit(0))
df.withColumn("a_cnt", aCnt).show
// +---+-----+-----+
// | id| text|a_cnt|
// +---+-----+-----+
// |  1| null|    0|
// |  2|abcda|    2|
// +---+-----+-----+

如果你想让你的代码相对安全,你应该检查是否存在null

def countAs1(s: String) = s match {
  case null => 0
  case chars => s.count(_ == 'a')
}
countAs1(df.where($"id" === 1).first.getAs[String]("text"))
// Int = 0
countAs1(df.where($"id" === 2).first.getAs[String]("text"))
// Int = 2

或捕获可能的异常:

import scala.util.Try
def countAs2(s: String) = Try(s.count(_ == 'a')).toOption.getOrElse(0)
countAs2(df.where($"id" === 1).first.getAs[String]("text"))
// Int = 0
countAs2(df.where($"id" === 2).first.getAs[String]("text"))
// Int = 2

最新更新