2016-03-23 12 views
0

を指定すると、r.nameまたはr.ageをそれぞれ使用して、ドット表記を使用してPySpark 要素にアクセスできます。名前が変数elementに保存されている要素を取得する必要がある場合はどうなりますか? 1つの方法はr.toDict()[element]です。しかし、大きな数字のDataFrameがあり、そのデータフレームの各行に関数をマップしたい場合を考えてみましょう。我々は確かしかし、すべての行にtoDict()を呼び出すと、非常に非効率になると思わpPySpark行オブジェクト:変数名で行要素にアクセスする

def f(row, element1, element2): 
    row = row.asDict() 
    return ", ".join(str(row[element1]), str(row[element2])) 

result = dataframe.map(lambda row: f(row, 'age', 'name')) 

ような何かを行うことができます。より良い方法がありますか?

+0

>おそらく 'filter' 例を示すことができますが、私はこのために' filter'を使う方法を理解できません。 –

+0

私の間違い申し訳ありませんが、私の小さな説明の第二部分は正しいです。 'map'は並列化が容易なため、最も速いジョブの1つです。 –

+0

私は 'map'が良いことを知っています。私はそれをより良くしたいと思いますが、すべての行をdictに変換する必要はありません –

答えて

2

いつものようにPythonで動作するものがあれば、そこには魔法はありません。ここでドットシンタックスのようなものが動作するときは、予測可能な一連のイベントを意味します。

from pyspark.sql import Row 

a_row = Row(foo=1, bar=True) 

a_row.__getattr__("foo") 
## 1 
a_row.__getattr__("bar") 
True 

行も同じ動作を持つように__getitem__を上書きします:

a_row.__getitem__("foo") 
## 1 

それはあなたがブラケット表記を使用できることを意味します:

a_row["bar"] 
## True 
特にあなたは __getattr__メソッドが呼び出されることを期待することができます

効率的ではないという問題があります。各コールはO(N)です。したがって、幅の広い行と複数のコールがある場合は、dictへの1回の変換が効率的になります。あなたはいけない

  • map好まれるべき内蔵のSQL式を使用して
  • 一般的にUDFは非効率であるが、多くのクリーナーを使用して

    • 一般的には次のような呼び出しを避ける必要がありますDataFrameに直接マップします。すぐに廃止される予定です。

  • +0

    >各呼び出しはO(N)です Nは列の数ですか?私の場合、これはかなり小さく、 '.asDict()'に付随するメモリ割り当て/ガベージコレクションにはもっと時間がかかると思われます。私はちょうどタイミングを測定する必要があると思う。ありがとうございました –

    +0

    面白いことに、私はこの質問をする前の日で、たくさんのラッパーを書いて、いくつかの '__getattr__'と' __getitem__'関数を実装しました。コンテキストを切り替えて、忘れてしまいました:-) –

    +0

    Spark SQLでPythonマッパーを避けても、マッパーを実行する前にこの抽出値を明示的に使用するのは間違いありません。 – zero323

    関連する問題