次の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)
しばらく試してみてもわかりません。誰かが問題とそれを修正する方法を指摘するのを手伝ってくれるでしょうか?ありがとう。
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|
+-----------------+-------------+----------------+
_