【问题标题】:How to use Column.isin with list?如何将 Column.isin 与列表一起使用?
【发布时间】:2015-12-09 16:39:55
【问题描述】:
val items = List("a", "b", "c")

sqlContext.sql("select c1 from table")
          .filter($"c1".isin(items))
          .collect
          .foreach(println)

上面的代码抛出以下异常。

Exception in thread "main" java.lang.RuntimeException: Unsupported literal type class scala.collection.immutable.$colon$colon List(a, b, c) 
at org.apache.spark.sql.catalyst.expressions.Literal$.apply(literals.scala:49)
at org.apache.spark.sql.functions$.lit(functions.scala:89)
at org.apache.spark.sql.Column$$anonfun$isin$1.apply(Column.scala:642)
at org.apache.spark.sql.Column$$anonfun$isin$1.apply(Column.scala:642)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
at scala.collection.mutable.WrappedArray.foreach(WrappedArray.scala:35)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:245)
at scala.collection.AbstractTraversable.map(Traversable.scala:104)
at org.apache.spark.sql.Column.isin(Column.scala:642)

以下是我修复它的尝试。它编译并运行,但不返回任何匹配项。不知道为什么。

val items = List("a", "b", "c").mkString("\"","\",\"","\"")

sqlContext.sql("select c1 from table")
          .filter($"c1".isin(items))
          .collect
          .foreach(println)

【问题讨论】:

    标签: scala apache-spark apache-spark-sql


    【解决方案1】:

    正如托马拉克所说:

    isin(java.lang.Object... list)
    A boolean expression that is evaluated to true if the value 
    of this expression is contained by the evaluated values of the arguments.
    

    因此,您只需进行以下更改即可解决此问题:

    val items = List("a", "b", "c").map(c => s""""$c"""")
    

    【讨论】:

    • 为什么是地图?我的是 .filter($"c1".isin(List("a", "b", "c"))) 会工作。
    • 考虑到您的代码List("a", "b", "c").mkString("\"","\",\"","\""),我假设您想用双引号将每个项目括起来。地图做同样的事情。
    【解决方案2】:

    根据文档,isin 采用可变参数,而不是列表。列表在这里实际上是一个令人困惑的名称。您可以尝试将您的列表转换为可变参数,如下所示:

    val items = List("a", "b", "c")
    
    sqlContext.sql("select c1 from table")
              .filter($"c1".isin(items:_*))
              .collect
              .foreach(println)
    

    您的带有 mkString 的变体可以编译,因为单个 String 也是一个 vararg(参数数量等于 1),但它可能不是您想要实现的。

    【讨论】:

      【解决方案3】:

      它在 Java Api (Java 8) 中是这样工作的

      .isin(sampleListName.stream().toArray(String[]::new))));
      

      sampleListName 是一个列表

      【讨论】:

        【解决方案4】:

        更简单:

        sqlContext.sql("select c1 from table")
                  .filter($"c1".isin("a", "b", "c"))
                  .collect
                  .foreach(println)
        

        除非您有很多列表值,通常情况并非如此。

        【讨论】:

          【解决方案5】:

          Spark 现在(从 2.4.0 开始)有一个名为 isInCollection 的方法,这正是您正在寻找的,而不是 isIn

          (他们不应该统一方法吗?)

          【讨论】:

          • 请注意,此方法是通过:def isInCollection(values: scala.collection.Iterable[_]): Column = isin(values.toSeq: _*) 实现的(参见:definition)。我真的不知道为什么 API 有两个不同的名称来表示类似的行为。
          • 这让我更加困惑。我真的不明白。我希望有一个重载方法来处理这两种类型的输入,就像 API 中的许多其他方法一样。谢谢你的信息!
          • 这个PR介绍方法不用解释:/
          • @BlueSheepToken 讨论在this PR。它没有重载的原因是 isin 被定义为采用 Any*,而 Iterable[_] 可以是 Any* 导致冲突。
          • 我不知道你们是怎么找到这种东西的,但是我的随机切线问题在我将其发布 20 个月后得到了完全回答。谢谢!
          猜你喜欢
          • 2020-09-11
          • 1970-01-01
          • 2020-11-07
          • 1970-01-01
          • 2021-12-17
          • 2020-05-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多