【问题标题】:How to filter out rows with NaN values in Hive?如何在 Hive 中过滤掉具有 NaN 值的行?
【发布时间】:2017-09-17 11:35:55
【问题描述】:

我在 Hue 中运行一个 hive 表的求和函数,并得到一个 NaN 的返回值。

这是我的代码:

select sum(v1) from hivedb.tb1;

我不知道为什么它给了我一个 NaN 结果。我检查了我的任何 v1 值是否为空:

select * from hivedb.tb1 where v1 is null;

,原来没有记录有空值。该表有1亿行,因此我无法对每条记录进行手动检查。

  1. 有人知道我为什么会得到 NaN 结果吗?
  2. 如果是因为我在某些行中有一些异常值,我该如何找到它们?

感谢任何帮助。提前谢谢!

更新 1 我手动筛选了前 1000 行,幸运的是在 tb1 中发现了一些 NaN 异常值。这是由于前面步骤中的一些舍入误差造成的。所以我的问题1可能已经回答了。如果您认为可能有其他原因,请随时发表评论。

我仍然不知道如何使用有效的方法来发现具有 NaN 值的行。所以我仍然期待我的问题2的任何答案。请随时分享。感谢您的帮助。

更新 2 在下面的讨论部分中接受的答案的帮助下解决了这个问题。有多种处理方法。

  1. 使用条件选择 v1+1 >v1。它将选择具有非 NaN 值的行。
  2. 使用 cast(v1 as String) ='NaN' 的条件选择。它将选择具有 NaN 值的行。

【问题讨论】:

  • 哦,来吧,在计算 SQL 聚合时会忽略 Null 值。另一方面,1 亿个值的总和可能会溢出 Integer、Float 或 Decimal(p,s) 的容量。顺便问一下v1 的数据类型是什么?你试过sum(cast(v1 as Double))吗?
  • @Samson Scharfrichter 你是对的。我只是不知道如何选择异常行。不过,谢谢你的其余部分。回到你的问题,v1 是双倍的。
  • @SamsonScharfrichter 谢谢。我有点想通了。一次偶然的机会,我手动筛选了数千行,幸运的是我在 tb1 中发现了一些 NaN 值。它是由一些舍入误差问题产生的。所以我的第一个问题有点回答了,即 tb1 中存在的 NaN 值。但我仍然不知道如何处理我的问题 #2。如果您有任何见解,请随时分享。

标签: sql hadoop hive nan hue


【解决方案1】:

不确定这是否适用于许多情况,但在 Hive 3 中我得到:

select float('NaN') = float('NaN')

返回真

理论上来说:

select * from hivedb.tb1 where v1 <> float('NaN');

应该做到这一点

【讨论】:

    【解决方案2】:

    Hive 依赖于 Java(加上 Null 和朋友的特定于 SQL 的语义),Java 遵循 IEEE 数字语义标准。这意味着...... NaN 很棘手。

    引用that post...

    (Float.NaN == Float.NaN) 总是返回 false。
    事实上,如果你 看Float.isNaN()的JDK实现,一个数是 如果它不等于自身 则不是数字(这是有道理的,因为 一个数字应该等于它自己)
    同样适用于 Double.NaN

    因此,没有必要向您展示如何使用名为 reflect2 的(未记录的)Hive 函数,它允许您在 Hive 列上调用原始 Java 方法,即

    where v1 is not null and not reflect2(v1, "isNaN")
    

    ...因为——理论上——你可以简单地说:

    where v1 is not null and v1=v1
    

    免责声明 -- 我见过 Hive 优化器进行激进的“优化”并产生错误结果的情况。
    换句话说,如果简单的 @987654331 @ 子句没有按预期过滤掉 NaN 值,然后查看 reflect2...

    编辑——事实上,优化器似乎忽略了 Hive 某些版本中的 v1=v1 子句(参见 cmets),因此需要更迂回的公式:

    • v1 +1.0 > v1 应该可以工作...除非舍入错误导致 abs(v1) abs(v1) >> 1
    • 其他“数字”技巧在极端情况下也会同样失败,尤其是当v1 =0.0

    最后,最稳健的方法似乎是尝试 cast(v1 as String) <>'NaN' (因为所有可能的 NaN 值都显示为“NaN”,即使它们在算术意义).


    关于reflect2 的旁注——您可以看到the official Hive doc 中确实没有提到它,而提到了reflect(甚至还有specific Wiki entry)。但它早在 Hive V0.11 cf 就已经实施。 Hive-4025

    编辑 -- Java“反射”现在对 ODBC / JDBC / Hue 连接默认禁用(参见 cmets) ,并且在使用 ranger 或 Sentry 等安全插件时无法重新启用。所以它的使用仅限于(已弃用的)hive CLI。

    【讨论】:

    • 嗨,@Samson Scharfrichter:谢谢你的好意。不幸的是,两者都不起作用。我尝试了 v1=v1 和反射 2。对于 v1=v1 测试,没有错误,但它产生了错误的结果。这是反射 2 的错误消息:Error while compiling statement: FAILED: SemanticException UDF reflect2 is not allowed
    • 参见。 community.hortonworks.com/questions/25828/… 关于 reflectreflect2 通过 JDBC 被“列入黑名单”。您可以在边缘节点上试用旧版 hive 胖客户端吗?
    • 您是否尝试过比v1=v1 更复杂的方法,例如(v1 +1.0 > v1 or abs(v1) *1.1 > abs(v1))(如果 v1 不在 10^-38、10^+38 范围内,+1 技巧将无法始终如一地工作;并且 *1.1 技巧不会在零处工作,但它们一起可能会完成这项工作 - 在一种非常低效的方式)
    • 或者一些简单的东西:cast(v1 as String) <>'NaN' (或者你在浏览 Hue 中的 NaN 值时看到的任何内容)
    • 嗨,@Samson Scharfrichter:聪明的想法。我尝试了 v1 + 1 的东西,它可以工作。我最初的目标是选择具有 NaN 值的行。因此,除了您提供的内容之外,我还添加了另一个步骤,即加入和条件选择以实现我的目标。
    【解决方案3】:

    您可以将 NaN 处理为

    SELECT SUM(CAST(IF(v1 ='NaN', 0, v1)) as Double) FROM hivedb.tb1 
    

    【讨论】:

    • 我尝试了你的建议,得到了这个AnalysisException: operands of type DOUBLE and STRING are not comparable: x = 'NaN'
    • 不错的尝试,但您的 cast( ) 方向错误,并且 NaN 应该被视为 Null 而不是零,因为一些概念上的原因。所以你应该对sum(case when cast(v1 as String) ='NaN' then Null else v1 end)之类的东西做一些跟进
    猜你喜欢
    • 1970-01-01
    • 2018-09-02
    • 1970-01-01
    • 2012-11-09
    • 2017-10-04
    • 1970-01-01
    • 1970-01-01
    • 2021-02-12
    • 2014-06-05
    相关资源
    最近更新 更多