Wie verwende ich Column.isin mit Liste?

71
val items = List("a", "b", "c")

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

Der obige Code löst die folgende Ausnahme aus.

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)

Unten ist mein Versuch, es zu beheben. Es wird kompiliert und ausgeführt, gibt jedoch keine Übereinstimmung zurück. Nicht sicher warum.

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

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

Antworten:

131

Laut Dokumentation isinnimmt ein Vararg, keine Liste. Liste ist hier eigentlich ein verwirrender Name. Sie können versuchen, Ihre Liste wie folgt in vararg zu konvertieren:

val items = List("a", "b", "c")

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

Ihre Variante mit mkString wird kompiliert, da ein einzelner String ebenfalls ein vararg ist (mit einer Anzahl von Argumenten gleich 1), aber wahrscheinlich nicht das, was Sie erreichen möchten.

TheMP
quelle
17

So funktionierte es in Java Api (Java 8)

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

sampleListName ist eine Liste

Anandkumar
quelle
5

Spark hat jetzt (seit 2.4.0) eine Methode namens aufgerufen isInCollection, die genau das ist, wonach Sie suchen, anstatt isIn.

(Sollten sie die Methoden nicht vereinheitlichen?)

Lucas Lima
quelle
2

Wie Tomalak es erwähnt hat:

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.

Daher können Sie dieses Problem beheben und die folgende Änderung vornehmen:

val items = List("a", "b", "c").map(c => s""""$c"""")
Francis Toth
quelle
1
Warum die Karte? Mein ist, dass .filter($"c1".isin(List("a", "b", "c")))das funktionieren würde.
Tomalak
In Anbetracht Ihres Codes List("a", "b", "c").mkString("\"","\",\"","\"")ging ich davon aus, dass Sie jedes Element in doppelte Anführungszeichen setzen möchten. Die Karte macht das Gleiche.
Francis Toth
0

Sogar einfacher:

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

Es sei denn, Sie haben viele Listenwerte, was normalerweise nicht der Fall ist.

Pedro H.
quelle