web-dev-qa-db-ja.com

Spark RDDsで `map`と` reduce`メソッドはどのように機能しますか?

次のコードは、Apache Sparkのクイックスタートガイドからのものです。 「ライン」変数とは何か、どこから来たのかを誰かに説明してもらえますか?

textFile.map(line => line.split(" ").size).reduce((a, b) => if (a > b) a else b)

また、値はどのようにa、bに渡されますか?

QSGへのリンク http://spark.Apache.org/docs/latest/quick-start.html

18
DesirePRG

まず、リンクに従って、textfileが次のように作成されます。

val textFile = sc.textFile("README.md")

textfileRDD[String]であり、String型の復元力のある分散データセットであることを意味します。アクセスするAPIは、通常のScalaコレクションのAPIと非常によく似ています。

さて、これでmapは何をするのでしょうか?

Stringsのリストがあり、それを各ストリングの長さを表すIntsのリストに変換したいとします。

val stringlist: List[String] = List("ab", "cde", "f")
val intlist: List[Int] = stringlist.map( x => x.length )

mapメソッドには関数が必要です。 String => Intからの関数。この関数を使用すると、リストの各要素が変換されます。したがって、intlistの値はList( 2, 3, 1 )です

ここでは、String => Intから匿名関数を作成しました。それはx => x.lengthです。関数をより明示的に書くこともできます

stringlist.map( (x: String) => x.length )  

上記の明示的な記述を使用する場合、次のことができます。

val stringLength : (String => Int) = {
  x => x.length
}
val intlist = stringlist.map( stringLength )

したがって、ここでは、stringLengthがStringからIntまでの関数であることは明らかです。

備考:一般的に、mapはいわゆるファンクターを構成します。 A => Bから関数を提供する一方で、ファンクター(ここのリスト)のmapを使用すると、List[A] => List[B]からもその関数を使用できます。これはリフティングと呼ばれます。

質問への回答

「ライン」変数とは何ですか?

上記のように、lineは関数line => line.split(" ").sizeの入力パラメーターです

より明示的な(line: String) => line.split(" ").size

例:lineが「hello world」の場合、関数は2を返します。

"hello world" 
=> Array("hello", "world")  // split 
=> 2                        // size of Array

値はどのようにa、bに渡されますか?

reduceは、(A, A) => Aからの関数も想定しています。ここで、ARDDのタイプです。この関数をopと呼びましょう。

reduceとは何ですか。例:

List( 1, 2, 3, 4 ).reduce( (x,y) => x + y )
Step 1 : op( 1, 2 ) will be the first evaluation. 
  Start with 1, 2, that is 
    x is 1  and  y is 2
Step 2:  op( op( 1, 2 ), 3 ) - take the next element 3
  Take the next element 3: 
    x is op(1,2) = 3   and y = 3
Step 3:  op( op( op( 1, 2 ), 3 ), 4) 
  Take the next element 4: 
    x is op(op(1,2), 3 ) = op( 3,3 ) = 6    and y is 4

ここでの結果は、リスト要素の合計10です。

備考:一般的にreduceは計算します

op( op( ... op(x_1, x_2) ..., x_{n-1}), x_n)

完全な例

まず、テキストファイルはRDD [String]です。

TextFile
 "hello Tyth"
 "cool example, eh?"
 "goodbye"

TextFile.map(line => line.split(" ").size)
 2
 3
 1
TextFile.map(line => line.split(" ").size).reduce((a, b) => if (a > b) a else b)
 3
   Steps here, recall `(a, b) => if (a > b) a else b)`
   - op( op(2, 3), 1) evaluates to op(3, 1), since op(2, 3) = 3 
   - op( 3, 1 ) = 3
67
Martin Senne

MapおよびreduceはRDDクラスのメソッドであり、scalaコレクションに類似したインターフェースを持っています。

メソッドmapおよびreduceに渡すものは、実際には匿名関数です(mapに1つのパラメーターがあり、reduceに2つのパラメーターがあります)。 textFileは、含まれるすべての要素(このコンテキストのテキストの行)に対して提供された関数を呼び出します。

おそらく、最初にscalaコレクションの紹介を読んでください。

RDDクラスAPIの詳細については、こちらをご覧ください: https://spark.Apache.org/docs/1.2.1/api/scala/#org.Apache.spark.rdd.RDD

7
Tyth

map関数が行うことは、引数のリストを受け取り、それを何らかの関数にマップすることです。精通している場合、Pythonのマップ関数に似ています。

また、Fileは文字列のリストのようなものです。 (正確ではありませんが、それが反復されている方法です)

これがあなたのファイルだと考えてみましょう。

val list_a: List[String] = List("first line", "second line", "last line")

それでは、map関数がどのように機能するかを見てみましょう。

list of values既に持っているものとfunctionこの値をマッピングしたいもの。理解のために本当に簡単な関数を考えてみましょう。

val myprint = (arg:String)=>println(arg)

この関数は、単純に単一の文字列引数を取り、コンソールに出力します。

myprint("hello world")
hello world

この関数をリストに一致させると、すべての行が出力されます

list_a.map(myprint)

以下で説明するように、同じことを行う匿名関数も作成できます。

list_a.map(arg=>println(arg))

あなたの場合、lineはファイルの最初の行です。引数名は好きなように変更できます。たとえば、上記の例では、arglineに変更しても問題なく動作します

list_a.map(line=>println(line))
1
Gaurang Shah