spark-sql 时间戳类型比较源码修改

上次说到时间戳和字符串比较时会把时间戳cast成string 再做比较关于spark -sql 时间戳类型比较的一个小坑,这个过程中对精度做了处理。项目组的大哥最近频繁使用毫秒值为0的数据进行查询比较。他觉得这是一个bug,让我去修改一下。

首先我分析了一下生成的物理计划,发现>=,<= 时会发生cast as string的强转。

<=>和的情况并没有显示调用cast进行强转,但是依旧无法进行比较。因此在面对毫秒值为0的情况,最直接的方法就是在比较时对值进行处理。

我们找到比较函数所在的scala文件,它名为predicates.scala。以<=为例打上断点调试一下:

它包含左右两个表达式:

我们在这种情况下对左右表达式进行一下判断:

为保证在 =,>= ,<=>代码可以复用,我在里面添加了一个object,写了一个方法,这里对毫秒是0的字符串进行了截断,用于匹配cast后的时间戳字符串:

object TransString {
  /**
    * trans timestamp string to a right form so that it can be compare with timestamp while its milliseconds are 0
    *
    * @param left
    * @param right
    * @return
    */
  def trans(left: Expression, right: Expression): Expression = {
    var ret = right
    if (left.isInstanceOf[AttributeReference]) {
      if (left.asInstanceOf[AttributeReference].dataType == TimestampType && right.dataType == StringType) {
        if (right.isInstanceOf[Literal]) {
          var value = (right.asInstanceOf[Literal]).value.toString
          if (value.length > 19 && value.substring(19) == ".0") {
            value = value.substring(0, 19)
          }
          ret = Literal(UTF8String.fromString(value), StringType)
        }
      }
    }
    ret
  }

}

 

然后我们将构造的入参改成var,在执行比较每个的地方构造方法中调用该方法判断一下:

right = TransString.trans(left ,right),覆盖掉原来的right表达式。

本来一开始想直接把cast类中时间戳转字符串截断的代码注释掉,考虑到原生代码这么做应该有其原因,所以最后放弃了。此外,尝试在生成物理计划时让cast不要调用,调试了大半天,发现这个方式不是很靠谱,也可能是学艺不精的原因,没有能够实现。我觉得这么改代码不是很优雅,后续会尝试更优雅的解决办法。目前暂时提供这个解决方案。已提交代码给测试小姐姐,看下会不会对其他的功能产生影响。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值