web-dev-qa-db-ja.com

SQLのようなIN句でPyspark DataFrameをフィルタリングする

次のように、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)'のようなものを期待していると言っています。問題は、別のジョブから抽出された値を手動で書き込むことができないことです。

この場合、どのようにフィルタリングしますか?

37
mar tin

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のすべての詳細を構築して、簡単に構築および処理できます。

53
zero323

上記で@ zero323が言及したことを繰り返します:list(setだけでなく以下を使用して同じことを行うことができます

from pyspark.sql.functions import col

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

ちょっとした追加/更新:

choice_list = ["foo", "bar", "jack", "joan"]

データフレーム「df」をフィルタリングして、choice_listの値のみを取得する列「v」に基づいて行を保持する場合は、

df_filtered = df.where( ( col("v").isin (choice_list) ) )
3
shwetabharti

整数列に対してもこれを行うことができます。

df_filtered = df.filter("field1 in (1,2,3)")

または、文字列列の場合:

df_filtered = df.filter("field1 in ('a','b','c')")
0
BICube

私のために働いたわずかに異なるアプローチは、カスタムフィルター機能でフィルタリングすることです。

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'))) \
0
Alex_Gidiotis