web-dev-qa-db-ja.com

mapとflatMapの違いとそれぞれの良い使用例は何ですか?

誰かが私にmapとflatMapの違いを説明できますか、そしてそれぞれの良いユースケースは何ですか?

「結果を平坦化する」とはどういう意味ですか?何がいいの?

208
Eran Witkon

これがspark-Shellセッションとしての違いの例です。

まず、いくつかのデータ - 2行のテキスト:

val rdd = sc.parallelize(Seq("Roses are red", "Violets are blue"))  // lines

rdd.collect

    res0: Array[String] = Array("Roses are red", "Violets are blue")

さて、mapは長さNのRDDを長さNの別のRDDに変換します。

たとえば、2行から2行の長さにマッピングします。

rdd.map(_.length).collect

    res1: Array[Int] = Array(13, 16)

しかしflatMap(おおまかに言って)は長さNのRDDをN個のコレクションのコレクションに変換し、それからこれらを単一の結果のRDDにフラット化します。

rdd.flatMap(_.split(" ")).collect

    res2: Array[String] = Array("Roses", "are", "red", "Violets", "are", "blue")

1行に複数の単語があり、複数の行がありますが、最終的には単一の単語の出力配列になります。

これを説明するために、行の集合から単語の集合へのflatMappingは、次のようになります。

["aa bb cc", "", "dd"] => [["aa","bb","cc"],[],["dd"]] => ["aa","bb","cc","dd"]

そのため、入力RDDと出力RDDは通常、flatMapに対して異なるサイズになります。

mapsplit関数で使用しようとした場合、入力ごとに1つの結果がなければならないため、入れ子になった構造体(型がRDD[Array[String]]のRDD配列)になります。

rdd.map(_.split(" ")).collect

    res3: Array[Array[String]] = Array(
                                     Array(Roses, are, red), 
                                     Array(Violets, are, blue)
                                 )

最後に、1つの便利な特別な場合は、答えを返さないかもしれない関数を使ってマッピングすることで、Optionを返します。 flatMapを使用して、Noneを返す要素を除外し、Someを返す要素から値を抽出できます。

val rdd = sc.parallelize(Seq(1,2,3,4))

def myfn(x: Int): Option[Int] = if (x <= 2) Some(x * 10) else None

rdd.flatMap(myfn).collect

    res3: Array[Int] = Array(10,20)

(ここでは、Optionは、1つの要素または0つの要素を持つリストのように動作することに注意してください)

166
DNA

一般的に我々はhadoopでワードカウントの例を使います。私は同じユースケースを取り、mapflatMapを使います。そしてそれがどのようにデータを処理しているかの違いを見るでしょう。

以下はサンプルデータファイルです。

hadoop is fast
Hive is sql on hdfs
spark is superfast
spark is awesome

上記のファイルはmapflatMapを使って解析されます。

mapを使う

>>> wc = data.map(lambda line:line.split(" "));
>>> wc.collect()
[u'hadoop is fast', u'Hive is sql on hdfs', u'spark is superfast', u'spark is awesome']

入力は4行であり、出力サイズも4であり、すなわち、N要素==> N要素である。

flatMapを使う

>>> fm = data.flatMap(lambda line:line.split(" "));
>>> fm.collect()
[u'hadoop', u'is', u'fast', u'Hive', u'is', u'sql', u'on', u'hdfs', u'spark', u'is', u'superfast', u'spark', u'is', u'awesome']

出力はmapとは異なります。


Word数を取得するために、各キーの値として1を割り当てましょう。

  • fmflatMapを使用して作成されたRDD
  • wcmapを使用して作成されたRDD
>>> fm.map(lambda Word : (Word,1)).collect()
[(u'hadoop', 1), (u'is', 1), (u'fast', 1), (u'Hive', 1), (u'is', 1), (u'sql', 1), (u'on', 1), (u'hdfs', 1), (u'spark', 1), (u'is', 1), (u'superfast', 1), (u'spark', 1), (u'is', 1), (u'awesome', 1)]

一方、RDD mapwcは、以下の望ましくない出力を生成します。

>>> wc.flatMap(lambda Word : (Word,1)).collect()
[[u'hadoop', u'is', u'fast'], 1, [u'Hive', u'is', u'sql', u'on', u'hdfs'], 1, [u'spark', u'is', u'superfast'], 1, [u'spark', u'is', u'awesome'], 1]

mapの代わりにflatMapが使用されている場合は、Wordの数を取得できません。

定義によれば、mapflatMapの違いは次のとおりです。

map:RDDの各要素に与えられた関数を適用することによって新しいRDDを返します。 mapの関数は1つの項目だけを返します。

flatMapmapと同様に、RDDの各要素に関数を適用して新しいRDDを返しますが、出力は平坦化されます。

79
yoga

SparkでRDD.mapとRDD.flatMapの違いを尋ねる場合、mapはサイズNのRDDをサイズNの別のものに変換します。例えば。

myRDD.map(x => x*2)

たとえば、myRDDがDoublesで構成されている場合などです。

一方、flatMapはRDDを別のサイズのものに変換することができます。

myRDD.flatMap(x =>new Seq(2*x,3*x))

サイズ2 * NのRDDを返すか、

myRDD.flatMap(x =>if x<10 new Seq(2*x,3*x) else new Seq(x) )
16
Oussama

例としてtest.mdを使用してください。

➜  spark-1.6.1 cat test.md
This is the first line;
This is the second line;
This is the last line.

scala> val textFile = sc.textFile("test.md")
scala> textFile.map(line => line.split(" ")).count()
res2: Long = 3

scala> textFile.flatMap(line => line.split(" ")).count()
res3: Long = 15

scala> textFile.map(line => line.split(" ")).collect()
res0: Array[Array[String]] = Array(Array(This, is, the, first, line;), Array(This, is, the, second, line;), Array(This, is, the, last, line.))

scala> textFile.flatMap(line => line.split(" ")).collect()
res1: Array[String] = Array(This, is, the, first, line;, This, is, the, second, line;, This, is, the, last, line.)

mapメソッドを使用すると、test.mdの行が表示されます。flatMapメソッドの場合は、単語数が表示されます。

mapメソッドはflatMapに似ています、それらはすべて新しいRDDを返します。 mapメソッドはしばしば新しいRDDを返し、flatMapメソッドは分割語を使うことがよくあります。

13
pangpang

mapは同数の要素のRDDを返しますが、flatMapはそうでない場合があります。

flatMapの使用例欠落データまたは誤ったデータを除外します。

mapのユースケースの例入力と出力の要素数が同じであるような、さまざまなケースでの使用.

number.csv

1
2
3
-
4
-
5

map.pyはadd.csvにすべての番号を追加します。

from operator import *

def f(row):
  try:
    return float(row)
  except Exception:
    return 0

rdd = sc.textFile('a.csv').map(f)

print(rdd.count())      # 7
print(rdd.reduce(add))  # 15.0

flatMap.pyは足し算の前にflatMapを使って欠損データを除外します。以前のバージョンと比較して、追加される数字が少なくなります。

from operator import *

def f(row):
  try:
    return [float(row)]
  except Exception:
    return []

rdd = sc.textFile('a.csv').flatMap(f)

print(rdd.count())      # 5
print(rdd.reduce(add))  # 15.0
9
wannik

それはあなたの最初の質問に帰結します:あなたが平らにすることによって意味するもの

FlatMapを使用すると、 "多次元"コレクションは "一次元"コレクションになります。

val array1d = Array ("1,2,3", "4,5,6", "7,8,9")  
//array1d is an array of strings

val array2d = array1d.map(x => x.split(","))
//array2d will be : Array( Array(1,2,3), Array(4,5,6), Array(7,8,9) )

val flatArray = array1d.flatMap(x => x.split(","))
//flatArray will be : Array (1,2,3,4,5,6,7,8,9)

以下の場合にflatMapを使用します。

  • あなたのマップ関数は多層構造を作成することになります
  • しかし、必要なのは、すべての内部グループを削除することによって、単純で平らな1次元構造だけです。
8
ramu

mapとflatMapは、入力RDDから線を引き、それに関数を適用するという意味で似ています。違いは、mapの関数は1つの要素のみを返すのに対し、flatMapの関数はイテレータとして要素のリスト(0以上)を返すことができるという点です。

また、flatMapの出力は平坦化されています。 flatMapの関数は要素のリストを返しますが、flatMapはリストからのすべての要素を(リストではなく)フラットな方法で持つRDDを返します。

7
Bhasker

違いは、以下のサンプルのpysparkコードから見ることができます。

rdd = sc.parallelize([2, 3, 4])
rdd.flatMap(lambda x: range(1, x)).collect()
Output:
[1, 1, 2, 1, 2, 3]


rdd.map(lambda x: range(1, x)).collect()
Output:
[[1], [1, 2], [1, 2, 3]]
5
awadhesh pathak

RDD.mapはすべての要素を単一の配列で返します

RDD.flatMapは配列の配列の要素を返します

text.txtファイルに次のようなテキストがあるとしましょう。

Spark is an expressive framework
This text is to understand map and faltMap functions of Spark RDD

地図を使う

val text=sc.textFile("text.txt").map(_.split(" ")).collect

出力:

text: **Array[Array[String]]** = Array(Array(Spark, is, an, expressive, framework), Array(This, text, is, to, understand, map, and, faltMap, functions, of, Spark, RDD))

FlatMapを使う

val text=sc.textFile("text.txt").flatMap(_.split(" ")).collect

出力:

 text: **Array[String]** = Array(Spark, is, an, expressive, framework, This, text, is, to, understand, map, and, faltMap, functions, of, Spark, RDD)
3
veera

FlatmapとMapは両方ともコレクションを変換します。

差:

map(func)
関数funcを介してソースの各要素を渡すことによって形成された新しい分散データセットを返します。

flatMap(func)
mapと似ていますが、各入力項目は0個以上の出力項目にマップできます(したがってfuncは単一の項目ではなくSeqを返すべきです)。

変換関数
map:1要素中 - > 1要素要素。
flatMap:内の1つの要素 - > 0以上の要素(コレクション)。

3
Ajit K'sagar

PySpark関連を望んでいるすべての人のために:

変換例:flatMap

>>> a="hello what are you doing"
>>> a.split()

['やあ、元気']

>>> b=["hello what are you doing","this is rak"]
>>> b.split()

トレースバック(最新の呼び出しは最後):AttributeError:のファイル ""、行1、 'list'オブジェクトには属性 'split'がありません

>>> rline=sc.parallelize(b)
>>> type(rline)
>>> def fwords(x):
...     return x.split()


>>> rword=rline.map(fwords)
>>> rword.collect()

[[['hello'、 'what'、 'are'、 'you'、 'doing']、['this'、 'is'、 'rak']]

>>> rwordflat=rline.flatMap(fwords)
>>> rwordflat.collect()

['こんにちは'、 '何'、 'ある'、 'あなた'、 'やってる'、 'これ'、 'is'、 'rak']

それが役に立てば幸い :)

2

mapRDDの各要素に関数を適用して新しいRDDを返します。 .map内の関数は1つの項目のみを返すことができます。

flatMap:mapと同様に、RDDの各要素に関数を適用して新しいRDD byを返しますが、出力は平坦化されます。

また、flatMapの関数は要素のリスト(0以上)を返すことができます。

例えば:

sc.parallelize([3,4,5]).map(lambda x: range(1,x)).collect()

出力:[[1、2]、[1、2、3]、[1、2、3、4]]

sc.parallelize([3,4,5]).flatMap(lambda x: range(1,x)).collect()

出力:o/pが1つのリストにフラット化されていることに注意してください[1、2、1、2、3、1、2、3、4]

ソース: https://www.linkedin.com/Pulse/difference-between-map-flatmap-transformations-spark-pyspark-pandey/

1

すべての例は良いです....ここにいい視覚的な図があります...ソース提供: DataFlairによるスパークトレーニング

マップ:マップはApache Sparkの変換操作です。これはRDDの各要素に適用され、結果を新しいRDDとして返します。マップでは、操作開発者は自分のカスタムビジネスロジックを定義できます。同じ論理がRDDのすべての要素に適用されます。

Spark RDDのmap関数は、(開発者が指定した)カスタムコードに従って、1つの要素を入力処理として取り、一度に1つの要素を返します。 Mapは、長さNのRDDを長さNの別のRDDに変換します。入力RDDと出力RDDは通常、同じ数のレコードを持ちます。

enter image description here

scalaを使ったmapの例:

val x = spark.sparkContext.parallelize(List("spark", "map", "example",  "sample", "example"), 3)
val y = x.map(x => (x, 1))
y.collect
// res0: Array[(String, Int)] = 
//    Array((spark,1), (map,1), (example,1), (sample,1), (example,1))

// rdd y can be re writen with shorter syntax in scala as 
val y = x.map((_, 1))
y.collect
// res1: Array[(String, Int)] = 
//    Array((spark,1), (map,1), (example,1), (sample,1), (example,1))

// Another example of making Tuple with string and it's length
val y = x.map(x => (x, x.length))
y.collect
// res3: Array[(String, Int)] = 
//    Array((spark,5), (map,3), (example,7), (sample,6), (example,7))

FlatMap:

flatMapは変換操作です。これはRDDの各要素に適用され、結果を新しいRDDとして返します。これはMapと似ていますが、FlatMapではmap関数から0、1、またはそれ以上の要素を返すことができます。 FlatMap操作では、開発者は自分のカスタムビジネスロジックを定義できます。同じ論理がRDDのすべての要素に適用されます。

「結果を平坦化する」とはどういう意味ですか?

FlatMap関数は、(開発者が指定した)カスタムコードに従って入力処理として1つの要素を取り、一度に0以上の要素を返します。 flatMap()は、長さNのRDDを長さMの別のRDDに変換します。

enter image description here

scalaを使ったflatMapの例:

val x = spark.sparkContext.parallelize(List("spark flatmap example",  "sample example"), 2)

// map operation will return Array of Arrays in following case : check type of res0
val y = x.map(x => x.split(" ")) // split(" ") returns an array of words
y.collect
// res0: Array[Array[String]] = 
//  Array(Array(spark, flatmap, example), Array(sample, example))

// flatMap operation will return Array of words in following case : Check type of res1
val y = x.flatMap(x => x.split(" "))
y.collect
//res1: Array[String] = 
//  Array(spark, flatmap, example, sample, example)

// RDD y can be re written with shorter syntax in scala as 
val y = x.flatMap(_.split(" "))
y.collect
//res2: Array[String] = 
//  Array(spark, flatmap, example, sample, example)
1
Ram Ghadiyaram