web-dev-qa-db-ja.com

Pyspark:PicklingError:オブジェクトをシリアル化できませんでした:

次の2つのデータフレームがあります:df_whitelistとdf_text

+-------+--------------------+
|keyword|    whitelist_terms |
+-------+--------------------+
|     LA|             LA city|
|     LA|        US LA in da |
| client|this client has i...|
| client|our client has do...|
+-------+--------------------+
+--------------------+----------+
|                Text|  Keywords|
+--------------------+----------+
|the client as ada...|client;ada|
|this client has l...| client;LA|
+--------------------+----------+

Df_whitelistでは、各キーワードは一連の用語に対応します。キーワードLAは、「LAシティ」と「US LA in da」に対応しています。 df_textには、テキストとこのテキストで見つかったいくつかのキーワードがあります。私がやりたいのは、「クライアントはadaを持っている」などの各テキストについて、キーワード「client」と「ada」のそれぞれについて、そのキーワードのすべてのホワイトリスト用語を調べて、多くの場合、この用語はテキストで使用されていました。私が試したことは次のようなものです:

import pyspark.sql.functions as F
import pyspark.sql.types as T
import re
def whitelisting(text,listOfKeyword,df_whitelist):
    keywords = listOfKeyword.split(";")
    found_whiteterms_count = 0
    for k in keywords:
        if df_whitelist.filter(df_whitelist.keyword == k).count() == 0:
            found_whiteterms_count = found_whiteterms_count + 0
        else:
            df = df_whitelist.filter(df_whitelist.keyword == k).select("whitelist_terms")
            n = df.rdd.map(lambda x:len(re.findall(x["whitelist_terms"],text))).reduce(lambda x, y: x+y)
            found_whiteterms_count = found_whiteterms_count + n    
    return found_whiteterms_count     
whitelisting_udf = F.udf(lambda text,listOfKeyword: whitelisting(text,listOfKeyword,df_whitelist),T.IntegerType())
text.withColumn("whitelist_counts", whitelisting_udf(text.Text,text.Keywords))

そして私はエラーを得ました:

PicklingError: Could not serialize object: Py4JError: An error occurred while calling o1153.__getstate__. Trace:
py4j.Py4JException: Method __getstate__([]) does not exist
    at py4j.reflection.ReflectionEngine.getMethod(ReflectionEngine.Java:318)
    at py4j.reflection.ReflectionEngine.getMethod(ReflectionEngine.Java:326)
    at py4j.Gateway.invoke(Gateway.Java:272)
    at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.Java:132)
    at py4j.commands.CallCommand.execute(CallCommand.Java:79)
    at py4j.GatewayConnection.run(GatewayConnection.Java:214)
    at Java.base/Java.lang.Thread.run(Thread.Java:844)

しばらく試してみてもわかりません。誰かが問題とそれを修正する方法を指摘するのを手伝ってくれるでしょうか?ありがとう。

7
user1740987

Pysparkデータフレーム、_df_whitelist_をUDFに渡しています。pysparkデータフレームはピクルできません。また、UDF内のデータフレームで計算を行っていますが、これは受け入れられません(不可能)。関数はデータフレームの行数と同じ回数だけ呼び出されるため、計算は単純にしておく必要があることに注意してください。 pyspark sql関数で実行できなかった場合にのみ実行してください。

代わりに、keywordで2つのデータフレームを結合する必要があります。あなたが提供した2つのサンプルデータフレームから始めましょう:

_df_whitelist = spark.createDataFrame(
    [["LA", "LA city"], ["LA", "US LA in da"], ["client", "this client has i"], ["client", "our client"]], 
    ["keyword", "whitelist_terms"])
df_text = spark.createDataFrame(
    [["the client as ada", "client;ada"], ["this client has l", "client;LA"]], 
    ["Text", "Keywords"])
_

_df_text_の列Keywordsにはいくつかの処理が必要です。文字列を配列に変換してから分解し、1行に1つの項目のみを含める必要があります。

_import pyspark.sql.functions as F
df_text = df_text.select("Text", F.explode(F.split("Keywords", ";")).alias("keyword"))

    +-----------------+-------+
    |             Text|keyword|
    +-----------------+-------+
    |the client as ada| client|
    |the client as ada|    ada|
    |this client has l| client|
    |this client has l|     LA|
    +-----------------+-------+
_

これで、2つのデータフレームをkeywordで結合できます。

_df = df_text.join(df_whitelist, "keyword", "leftouter")

    +-------+-----------------+-----------------+
    |keyword|             Text|  whitelist_terms|
    +-------+-----------------+-----------------+
    |     LA|this client has l|          LA city|
    |     LA|this client has l|      US LA in da|
    |    ada|the client as ada|             null|
    | client|the client as ada|this client has i|
    | client|the client as ada|       our client|
    | client|this client has l|this client has i|
    | client|this client has l|       our client|
    +-------+-----------------+-----------------+
_
  • UDFで呼び出す最初の条件は、次のように変換できます。_df_text_のkeywordが_df_whitelist_にない場合、0です。これは、 _df_whitelist_列の値は、左側のデータフレームにのみ表示されるため、_left join_ではNULLになります。

  • 2番目の条件:_whitelist_terms_がTextに出現する回数を数える:Text.count(whitelist_terms)

これを行うためにUDFを書きます:

_from pyspark.sql.types import IntegerType
count_terms = F.udf(lambda Text, term: Text.count(term) if term is not None else 0, IntegerType())
df = df.select(
    "Text", 
    "keyword", 
    F.when(F.isnull("whitelist_terms"), 0).otherwise(count_terms("Text", "whitelist_terms")).alias("whitelist_counts"))

    +-----------------+-------+----------------+
    |             Text|keyword|whitelist_counts|
    +-----------------+-------+----------------+
    |this client has l|     LA|               0|
    |this client has l|     LA|               0|
    |the client as ada|    ada|               0|
    |the client as ada| client|               0|
    |the client as ada| client|               0|
    |this client has l| client|               0|
    |this client has l| client|               0|
    +-----------------+-------+----------------+
_

最後に、個別のTextのみを含むデータフレームに戻るために集計できます。

_res = df.groupBy("Text").agg(
    F.collect_set("keyword").alias("Keywords"),
    F.sum("whitelist_counts").alias("whitelist_counts"))
res.show()

    +-----------------+-------------+----------------+
    |             Text|     Keywords|whitelist_counts|
    +-----------------+-------------+----------------+
    |this client has l| [client, LA]|               0|
    |the client as ada|[ada, client]|               0|
    +-----------------+-------------+----------------+
_
9
MaFF