2015-09-13 7 views
30
val items = List("a", "b", "c") 

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

Powyższy kod zgłasza następujący wyjątek.Filtr iskrzenia isin nie działa zgodnie z oczekiwaniami.

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) 

Poniżej znajduje się moja próba naprawienia tego. Kompiluje się i działa, ale nie zwraca żadnego dopasowania. Nie pewny dlaczego.

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

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

Według [dokumentacja] (https://spark.apache.org/docs/latest/ api/java/org/apache/spark/sql/Column.html # isin (java.lang.Object ...)) 'isin' pobiera listę, a nie ciąg znaków. – Tomalak

Odpowiedz

57

Według dokumentacji, isin zajmuje vararg, a nie lista. Lista jest w rzeczywistości mylącą nazwą. Można spróbować konwersji Listy do vararg tak:

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

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

Twój wariant z mkString kompiluje, ponieważ jeden String jest również vararg (z liczbą argumentów równa 1), ale nie jest to proably co chcesz osiągnąć.

+0

wow, to mylące bummer. Zauważyłem to w kilku miejscach w Spark. varargs wydaje się raczej niebezpieczne dla typu, ponieważ jest określone jako Any. Jak możemy to naprawić ?! – nont

+0

Wreszcie mam to działa! Właśnie potrzebowałem tego: _ * rzecz haha ​​dzięki! –

+0

@Nie w końcu odkryłeś dlaczego Spark jest do bani. Gratulacje! – piggybox

-1

Jak Tomalak wspomniał go:

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. 

Dlatego właśnie mógł rozwiązać ten czyni następujące zmiany:

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

Dlaczego mapa? Mój jest to, że '.filter ($" c1 ".isin (List (" a "," b "," c "))) będzie działać. – Tomalak

+0

Biorąc pod uwagę twój kod 'List (" a "," b "," c "). MkString (" \ "", "\", \ "", "\" ")', założyłem, że chciałeś otoczyć każdy przedmiot podwójnymi cudzysłowami. Mapa robi to samo. –

+0

Nie mój kod. ;) – Tomalak

3

To działało jak to w Java API (Java 8)

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

sampleListName jest lista

Powiązane problemy