次のように、SQLのようなIN
句でPyspark DataFrameをフィルタリングしたい
sc = SparkContext()
sqlc = SQLContext(sc)
df = sqlc.sql('SELECT * from my_df WHERE field1 IN a')
ここで、a
はTuple (1, 2, 3)
です。このエラーが発生しています:
Java.lang.RuntimeException:[1.67] failure: ``( ''が必要ですが、識別子が見つかりました
これは基本的に、aの代わりに'(1、2、3)'のようなものを期待していると言っています。問題は、別のジョブから抽出された値を手動で書き込むことができないことです。
この場合、どのようにフィルタリングしますか?
SQLContext
に渡す文字列は、SQL環境のスコープで評価されます。閉鎖をキャプチャしません。変数を渡したい場合は、文字列フォーマットを使用して明示的に行う必要があります。
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
セキュリティ上の理由から、これは明らかに「実際の」SQL環境で使用するものではありませんが、ここでは重要ではありません。
実際には、動的クエリを作成する場合、DataFrame
DSLは多くの選択肢です。
from pyspark.sql.functions import col
df.where(col("v").isin({"foo", "bar"})).count()
## 2
HiveQL/Spark SQLのすべての詳細を構築して、簡単に構築および処理できます。
上記で@ zero323が言及したことを繰り返します:list(set
だけでなく以下を使用して同じことを行うことができます
from pyspark.sql.functions import col
df.where(col("v").isin(["foo", "bar"])).count()
ちょっとした追加/更新:
choice_list = ["foo", "bar", "jack", "joan"]
データフレーム「df」をフィルタリングして、choice_listの値のみを取得する列「v」に基づいて行を保持する場合は、
df_filtered = df.where( ( col("v").isin (choice_list) ) )
整数列に対してもこれを行うことができます。
df_filtered = df.filter("field1 in (1,2,3)")
または、文字列列の場合:
df_filtered = df.filter("field1 in ('a','b','c')")
私のために働いたわずかに異なるアプローチは、カスタムフィルター機能でフィルタリングすることです。
def filter_func(a):
"""wrapper function to pass a in udf"""
def filter_func_(col):
"""filtering function"""
if col in a.value:
return True
return False
return udf(filter_func_, BooleanType())
# Broadcasting allows to pass large variables efficiently
a = sc.broadcast((1, 2, 3))
df = my_df.filter(filter_func(a)(col('field1'))) \