Spark SQL:map操作连环报错记录(too many elements for tuple,ClassNotFoundException: scala.Any,<refinement>

摘要:Spark SQLScala

由于Scala限制Tuple最大元素为22个导致的血案

问题复现

实际的业务场景是使用Spark SQL加工数仓的表,由于逻辑比较复杂如果直接Spark SQL自带的算子实现需要多好几次groupBy和join,因此直接使用DataFrame.map算子,转为RDD操作再转为Dataframe一次搞定。固定格式如下

    DataFrame
      .map {
        row => {
          // TODO业务逻辑
          // 列字段输出
          (element1, element2, element3...)
        }
      }.toDF(columnName1, columnName2, columnName3...)

最后输出在一个Tuple中使用toDF即可完成要求,但是Scala的Tuple要求元素最大22个

scala> (1, 2, 3, 4, 5, 6, 7, 8, 9, 10,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)
<console>:1: error: too many elements for tuple: 25, allowed: 22

Spark SQL要加工的业务字段为25个,显然得想其他办法去实现


初步解决方案

百度使用Array的方式解决,将所有字段包装在一个Array中,在获得Dataframe之后使用select($array字段名(索引))来完成,这个方法是正确,直接绕过了Tuple,以一个例子代码试一下

val a = Seq(("a", 1), ("b", 2)).toDF("a", "b")
    .map {
      row => {
        val one: String = row.getAs[String]("a")
        val two: Int = 1
        (one, Array(one, two))
      }
    }.toDF("a", "b").select($"a", $"b"(0).as("two"), $"b"(1).as("three"))

以上例子假设one和tow分别是业务要求加工的两个字段,执行报错

java.lang.ClassNotFoundException: scala.Any

直接报错在map那一行,第二个bug出现了,这个问题的原因是Array中元素类型不一致,Scala直接推断为Any,而Array[Any]不能toDF

scala> Seq(("a", Array(1, "a")), ("b", Array(2, "b"))).toDF("a", "b")
java.lang.ClassNotFoundException: scala.Any

继续修改将所有Array中元素改为String类型,在最后select的时候再将各别字段使用cast转回来,新代码如下

val a = Seq(("a", 1), ("b", 2)).toDF("a", "b")
    .map {
      row => {
        val one: String = row.getAs[String]("a")
        val two: Int = 1
        (one, Array(one, two.toString))
      }
    }.toDF("a", "b").select($"a", $"b"(0).as("two"), $"b"(1).as("three").cast("int"))

问题似乎解决了,但是实际业务代码继续报错,第三个bug

java.lang.ClassNotFoundException: <refinement>

深入检查时候发现Array中有Option[String]对象,Array中存在String和Option[String]两种类型。因为某些业务指标有空值,所有使用了Some和None类型,因此改成了最终方案如下


最终解决方案

解决方案是引入多个Array,将同一数据类型的字段放在一个Array中,代码如下

val a = Seq(("a", 1), ("b", 2)).toDF("a", "b")
      .map {
        row => {
          val one = row.getAs[String]("a")
          (one, Array(1, 2), Array(Some(one), None))
        }
      }.toDF("a", "b", "c").select($"a", $"b"(0).as("two"), $"c"(0).as("three"))

这样直接避免了数据类型不一致的问题,并且在最后也不需要在转化类型了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,277评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,689评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,624评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,356评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,402评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,292评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,135评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,992评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,429评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,636评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,785评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,492评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,092评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,723评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,858评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,891评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,713评论 2 354

推荐阅读更多精彩内容