PythonでのSpark UDF(ユーザー定義関数)の書き方

PythonでのSpark UDF(ユーザー定義関数)の書き方

  • オーケストレーション
6分で読めます 更新日 Dec 12, 2019

ポイント: Apache SparkのためにPythonでユーザー定義関数(UDF)を書く方法を学び、データ処理を強化します。このチュートリアルでは、withColumn()、SQL文、RDDマップ変換の3つの方法を説明します。

  • UDFにより、カスタム関数が登録され、Sparkデータフレームに適用されます。
  • コード例がそれぞれの方法の実装を効果的に示しています。

この記事では、Apache SparkのためのPythonでユーザー定義関数(UDF)を書く方法について説明します。この例のコードはこちらです。

UDFが必要な理由

SparkはデータをデータフレームまたはRDD(弾力的分散データセット)に保存します。これをデータベースのように考えてください。従来のSQLデータベース(例えば、mySQL)と同様に、カスタム関数を作成してそれをデータベースに直接実行することはできません。最初に関数を登録する必要があります。つまり、それをデータベースに保存する必要があります。これは組み込みデータベース関数の一つであるかのように、sum()、average、count()などのようにです。

これがSparkデータフレームにおける状況です。Spark RDDでは、RDDの行に直接関数を実行できます。

UDFの3つのアプローチ

UDFを作成する方法は3つあります:

  • df = df.withColumn
  • df = sqlContext.sql("からのSQL文")
  • rdd.map(customFunction())

以下に3つのアプローチを示します。最初から始めましょう。

アプローチ1:withColumn()

以下に、シンプルなデータフレームとRDDを作成します。データ構造内の唯一のテキストフィールドを整数に変換する関数を作成します。これは、たとえば、すべてのデータを数値に変換する必要がある機械学習を行っている場合に行うかもしれません。

以下のインポートに注意してください。各例でそれらを参照して、3つのアプローチのそれぞれに必要なオブジェクトをインポートする方法を知ってください。

以下はアプローチ1の完全なコードです。まず、重要なセクションを見てみましょう。通常の方法を使用してデータフレームを作成します:

    df = spark.createDataFrame(data,schema=schema)

さて、私たちは2つのことを行います。まず、関数colsIntを作成し、それを登録します。その登録された関数はtoInt()という別の関数を呼び出しますが、これは登録する必要はありません。udf.register("colsInt", colsInt)の最初の引数は、関数を参照するために使用する名前です。2番目は、登録したい関数です。

    colsInt = udf(lambda z: toInt(z), IntegerType())
spark.udf.register("colsInt", colsInt)

def toInt(s):
    if isinstance(s, str) == True:
        st = [str(ord(i)) for i in s]
        return(int(''.join(st)))
    else:
         return Null

次に、関数colinsIntを次のように呼び出します。最初の引数は、作成したい新しい列の名前です。2番目は、関数にプラグインするデータフレーム内の列です。

    df2 = df.withColumn( 'semployee',colsInt('employee'))

注意してください。df['employees']は列オブジェクトであり、単一の従業員ではありません。つまり、その列のすべての行に対してループする必要があります。したがって、このラムダ(インライン)ループを使用します。

    colsInt = udf(lambda z: toInt(z), IntegerType())

こちらがアプローチ1全体です:

    import pyspark
from pyspark import SQLContext
from pyspark.sql.types import StructType, StructField, IntegerType, FloatType, StringType
from pyspark.sql.functions import udf
from pyspark.sql import Row


conf = pyspark.SparkConf() 

 
sc = pyspark.SparkContext.getOrCreate(conf=conf)
spark = SQLContext(sc)

schema = StructType([
    StructField("sales", FloatType(),True),    
    StructField("employee", StringType(),True),
    StructField("ID", IntegerType(),True)
])

data = [[ 10.2, "Fred",123]]

df = spark.createDataFrame(data,schema=schema)

colsInt = udf(lambda z: toInt(z), IntegerType())
spark.udf.register("colsInt", colsInt)

def toInt(s):
    if isinstance(s, str) == True:
        st = [str(ord(i)) for i in s]
        return(int(''.join(st)))
    else:
         return Null


df2 = df.withColumn( 'semployee',colsInt('employee'))

今、結果を示します。新しい列semployeeが追加されたことに注意してください。withColumn()は新しいデータフレームを作成するので、df2を作成しました。

    df2.show()

+-----+--------+---+----------+
|sales|employee| ID| semployee|
+-----+--------+---+----------+
| 10.2|    Fred|123|1394624364|
+-----+--------+---+----------+

アプローチ2:SQLの使用

ここでの最初のステップは、データフレームをテーブルとして登録することです。これにより、SQL文を実行できるようになります。dfはデータフレームであり、dftabは作成する一時テーブルです。

    spark.registerDataFrameAsTable(df, "dftab")

次に、既存のdfから新しいデータフレームdf3を作成し、employee列にcolsInt関数を適用します。

    df3 = spark.sql("select sales, employee, ID, colsInt(employee) as iemployee from dftab")

結果は以下の通りです:

    df3.show()

+-----+--------+---+----------+
|sales|employee| ID| iemployee|
+-----+--------+---+----------+
| 10.2|    Fred|123|1394624364|
+-----+--------+---+----------+

アプローチ3:RDDマップ

データフレームにはmap()関数がありません。その関数を使用したい場合は、dff.rddを使用してデータフレームをRDDに変換する必要があります。

関数を次のように適用します:

    rdd = df.rdd.map(toIntEmployee)

これは、行オブジェクトをtoIntEmployee関数に渡します。したがって、行オブジェクトを返す必要があります。RDDは不変であるため、新しい行を作成する必要があります。

以下では、そのフィールド内の各文字を整数に変換し、それらを連結します。

    def toIntEmployee(rdd):
    s = rdd["employee"]
    if isinstance(s, str) == True:
        st = [str(ord(i)) for i in s]
        e = int(''.join(st)) 
    else:
        e = s
    
    return Row(rdd["sales"],rdd["employee"],rdd["ID"],e)

結果を印刷します:

    for x in rdd.collect():
    print(x)

これらの投稿は私自身の意見であり、BMCの立場、戦略、または意見を必ずしも代表するものではありません。

オーケストレーションの関連記事

BMCからのさらなる情報に興味がありますか?

ザ・ブリーフは、メインフレームとエンタープライズオーケストレーションに関する月刊メールです:研究、顧客ストーリー、製品ニュース、イベント。

このオファーに登録することで、あなたはBMCのプライバシーポリシーを読み、同意したことを確認します。

ザ・ブリーフに登録しました

ザ・ブリーフは、メインフレームとエンタープライズオーケストレーション—BMC AMIおよびControl-M—に関するアナリストの研究、顧客の展開、両者にわたるイベントを網羅しています。