记一次scala的隐含问题

现象

在运行[spark][1]程序期间,在针对 [dataFrame][2] 的map操作中,产生了类似[HashMap][3] key重复的现象,如图所示

有两个重复健

这个问题导致了后续统计上的一系列问题

分析

起初我们是实际跟踪代码进行分析的,但是发现scala代码中没有任何问题,各种处理也非常合理

代码罗列如下,想看就看看,不看也能理解

    // 目标是针对businessid进行聚合,然后输出各个业务id下,销售天数
    // 获取数据的代码
    val dataframe = spark.sql("select businessid,date,money from table1")

    case class Stat() {
      // 针对每一个businessid的统计
      var moneyByDay: HashMap[String, Double] = HashMap[String, Double]()


      // 针对每一条记录的id进行相加
      def moneyByDayOp(data: (String, Double)) = {
        if (this.moneyByDay.contains(data._1)) {
          val tmpMoney = this.moneyByDay.get(data._1)
          val finalMoney = tmpMoney.getOrElse[Double](0) + data._2
          this.moneyByDay.remove(data._1)
          this.moneyByDay.put(data._1, finalMoney)
        } else {
          if (data._2 > 0)
            this.moneyByDay.put(data._1, data._2)
        }
      }
    }
    /**
      * 归并多条记录的结果
      **/
    def reduceStatModel(one: Stat, another: Stat): Stat = {
      one.moneyByDay ++= another.moneyByDay
      one
    }

    /**
      * 针对每条记录生成一个统计值
      **/
    import org.apache.spark.sql.Row
    def parseProductDay(data: Row): (Long, Stat) = {
      val result: Stat = new Stat
      val a: String = data.getAs[String]("date")
      result.moneyByDayOp(a, data.getAs[Long]("money"))
      (data.getAs[Long]("product_id"), result)
    }

    // 核心流程
    val finalRs = dataframe.rdd
      .map(line => parseProductDay(line))
      .reduceByKey(reduceStatModel(_, _))

    val hashMp = finalRs.collect()(0)._2.moneyByDay
    hashMp.put("20170727",1)
    

针对的存储,其实就是Stat类中的 moneyByDay对象,本质上是一个HashMap,并且通过泛型控制,key类型为String,value的类型为Double

放到集群上执行,是可以通过的,并且得到类似上图的结论

hashMap中包含重复的key,只能是两个可能

  1. key类型相同,但是可能原始字符串中有空格,或者不可见字符
  2. key类型不同,一个是字符串,另一个是其他数据类型

经过检查,1的可能性排除

问题原因是2,居然是2,排除了所有不可能之后,最后的真相即使再不可能,也是真的

原因

其实这种结论是意料之外,情理之中

众所周知,java的泛型检查是编译时的检查,实际运行时,容器类存储和运算都是将对象看做object进行处理的

对于基于jvm的scala,泛型本质上也是一个静态编译检查

上述代码,如果table1表中的字段date,其类型是string,那么万事ok,运算和结论都会正常

但是如果date是其他类型,比如int,那么就会产生问题

问题出现在上述代码的37行

 val a: String = data.getAs[String]("date")
// 这行代码是org.apache.spark.sql.Row对象的一个调用,目的是获取指定类型的字段,并且转化为指定类型

// 源码如下:


  /**
   * Returns the value at position i.
   * For primitive types if value is null it returns 'zero value' specific for primitive
   * ie. 0 for Int - use isNullAt to ensure that value is not null
   *
   * @throws ClassCastException when data type does not match.
   */
  def getAs[T](i: Int): T = get(i).asInstanceOf[T] // 此处是进行强制转化

  /**
   * Returns the value of a given fieldName.
   * For primitive types if value is null it returns 'zero value' specific for primitive
   * ie. 0 for Int - use isNullAt to ensure that value is not null
   *
   * @throws UnsupportedOperationException when schema is not defined.
   * @throws IllegalArgumentException when fieldName do not exist.
   * @throws ClassCastException when data type does not match.
   */
  def getAs[T](fieldName: String): T = getAs[T](fieldIndex(fieldName))

解决方案

  1. 将table1表的字段设计成string,代码可以运行通过

  2. 37行代码改为如下,转化string即可

     val a: String = String.valueOf(data.getAs[String]("date"))
    

疑问

在spark-shell中调用这段代码,其实是会报错的

val a = data.getAs[String]("date")
异常截图

但是为什么集群执行会通过?

并且返回了一个HashMap[String,Double],其中的key都是Int。。。每次调用foreach方法都会报错

普通的foreach操作,抛出了强转异常

  1. https://spark.apache.org/ "apache基于内存的分布式计算框架"

  2. https://spark.apache.org/docs/latest/sql-programming-guide.html "spark-dataframe, 与pandas的Dataframe相似,是针对分布式计算的抽象和实现"

  3. http://www.scala-lang.org/api/current/scala/collection/mutable/HashMap.html " "scala.mutable.hashmap scala中的map分为可变和不可变的"

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

推荐阅读更多精彩内容