2016-03-08 10 views
18

Chcę filtrować Pyspark DataFrame z SQL-like IN klauzuli, jak wFiltrowanie Pyspark DataFrame z SQL-jak w punkcie

sc = SparkContext() 
sqlc = SQLContext(sc) 
df = sqlc.sql('SELECT * from my_df WHERE field1 IN a') 

gdzie a jest krotka (1, 2, 3). Dostaję taki błąd:

java.lang.RuntimeException: [1.67] failure: ``('' expected but identifier a found

który jest w zasadzie mówiąc to spodziewałem się czegoś podobnego '(1, 2, 3)' zamiast. Problem polega na tym, że nie mogę ręcznie zapisać wartości w wyciągu z innego zadania.

Jak filtrować w tym przypadku?

Odpowiedz

34

Łańcuch przechodzi do SQLContext jest oceniany w zakresie środowiska SQL. Nie przechwytuje zamknięcia. Jeśli chcesz przekazać zmienną musisz zrobić to jawnie przy użyciu formatowania ciąg:

df = sc.parallelize([(1, "foo"), (2, "x"), (3, "bar")]).toDF(("k", "v")) 
df.registerTempTable("df") 
sqlContext.sql("SELECT * FROM df WHERE v IN {0}".format(("foo", "bar"))).count() 
## 2 

Oczywiście nie jest to coś, czego można użyć w „prawdziwym” środowisku SQL ze względów bezpieczeństwa, ale to nie powinno tutaj sprawa.

W praktyce DataFrame DSL jest wiele możliwości wyboru, jeśli chcesz tworzyć dynamiczne zapytania:

from pyspark.sql.functions import col 

df.where(col("v").isin({"foo", "bar"})).count() 
## 2 

Jest łatwy do budowania i komponowania i obsługuje wszystkie szczegóły HiveQL/Spark SQL dla Ciebie.

+0

Na drugim sposobie, można osiągnąć to samo, wykonując df.where (df.v.isin ({"foo", "bar"})). count() –

+3

Możesz, ale osobiście nie podoba mi się to podejście. Za pomocą 'col' mogę łatwo oddzielić wyrażenie SQL i konkretny obiekt' DataFrame'. Możesz na przykład przechowywać słownik użytecznych wyrażeń i wybierać je w razie potrzeby. Z wyraźnym obiektem DF będziesz musiał umieścić go w funkcji i nie komponuje się tak dobrze. – zero323

12

powtarzając co @ zero323 wspomniał powyżej: co możemy zrobić to samo na podstawie listy jak również (nie tylko set) jak poniżej

from pyspark.sql.functions import col 

df.where(col("v").isin(["foo", "bar"])).count()