Sparkはデータフレームで使用できる定義済みの機能を提供するようになり、高度に最適化されているようです。私の元々の質問はどちらが速いかということでしたが、私は自分自身でいくつかのテストを行い、spark関数が少なくとも1つのインスタンスで約10倍速くなることを発見しました。だから、いつudfが高速になるのですか(同じspark関数が存在する場合のみ)?
これが私のテストコードです(Databricksコミュニティedで実行)。
# UDF vs Spark function
from faker import Factory
from pyspark.sql.functions import lit, concat
fake = Factory.create()
fake.seed(4321)
# Each entry consists of last_name, first_name, ssn, job, and age (at least 1)
from pyspark.sql import Row
def fake_entry():
name = fake.name().split()
return (name[1], name[0], fake.ssn(), fake.job(), abs(2016 - fake.date_time().year) + 1)
# Create a helper function to call a function repeatedly
def repeat(times, func, *args, **kwargs):
for _ in xrange(times):
yield func(*args, **kwargs)
data = list(repeat(500000, fake_entry))
print len(data)
data[0]
dataDF = sqlContext.createDataFrame(data, ('last_name', 'first_name', 'ssn', 'occupation', 'age'))
dataDF.cache()
UDF関数:
concat_s = udf(lambda s: s+ 's')
udfData = dataDF.select(concat_s(dataDF.first_name).alias('name'))
udfData.count()
スパーク機能:
spfData = dataDF.select(concat(dataDF.first_name, lit('s')).alias('name'))
spfData.count()
両方とも複数回実行され、udfは通常約1.1-1.4秒かかり、Spark concat
関数は常に0.15秒未満でした。
uDFが高速になるのはいつですか
Python UDFについて尋ねると、おそらく答えは決してありません*。 SQL関数は比較的単純で、複雑なタスク向けに設計されていないため、PythonインタープリターとJVMの間で繰り返されるシリアル化、逆シリアル化、およびデータ移動のコストを補うことはほとんど不可能です。
誰がこれがそうなのか知っていますか
主な理由は既に上記に列挙されており、Spark DataFrame
はネイティブにJVM構造であり、標準アクセスメソッドはJavaの単純な呼び出しによって実装されるという単純な事実に還元できます。 _ API。一方、UDFはPythonで実装されており、データを前後に移動する必要があります。
PySparkは一般にJVMとPython間のデータの移動を必要としますが、低レベルのRDD APIの場合、通常は高価なserdeアクティビティを必要としません。 Spark SQLは、シリアル化とシリアル化のコストを追加し、JVMでの安全でない表現との間でデータを移動するコストを追加します。後者はすべてのUDF(Python、ScalaおよびJava)に固有ですが、前者は非ネイティブ言語に固有です。
UDFとは異なり、Spark SQL関数はJVMで直接動作し、通常、CatalystとTungstenの両方とうまく統合されています。これは、実行計画でこれらを最適化できることを意味し、ほとんどの場合、codgenおよびその他のタングステンの最適化の恩恵を受けることができます。さらに、これらは「ネイティブ」表現のデータを操作できます。
ある意味、ここでの問題はPython UDFがコードにデータを持ち込む必要がある一方で、SQL式が逆方向に移動することです。
* 概算 PySparkウィンドウによると、UDFはScalaウィンドウ関数に勝つことができます。
2017年10月30日以降、Spark=はpysparkのベクトル化されたudfsを導入しました。
https://databricks.com/blog/2017/10/30/introducing-vectorized-udfs-for-pyspark.html
Python UDFが遅い理由は、おそらくPySpark UDFが最も最適化された方法で実装されていないためです:
リンクの段落によると。
Sparkは、ユーザー定義関数をサポートするPython APIをバージョン0.7に追加しました。これらのユーザー定義関数は、一度に1行ずつ動作します、したがって、高いシリアル化と呼び出しオーバーヘッドの影響を受けます。
ただし、新しくベクトル化されたudfsはパフォーマンスを大幅に改善しているようです。
3倍から100倍以上の範囲です。