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


249

誰かがmapとflatMapの違いを説明してもらえますか?それぞれの良い使用例は何ですか?

「結果を平坦化する」とはどういう意味ですか?それは何に適していますか?


4
あなたはスパークタグを追加しましたので、私はあなたがについて尋ねていると仮定しますRDD.mapRDD.flatMapApacheのスパーク。一般に、SparkのRDD操作は、対応するScalaコレクション操作をモデルにしています。Scala との違いについて説明しているstackoverflow.com/q/1059776/590203の回答は、参考になるかもしれません。mapflatMap
Josh Rosen

1
ここでの例のほとんどは、flatMapがコレクションのみで動作することを前提としているようですが、そうではありません。
ブーン2017年

回答:


195

以下は、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ます。

関数で使用しようとした場合map、入力ごとに1つの結果しか得られないためsplit、ネストされた構造(型の単語の配列のRDD)になってしまいRDD[Array[String]]ます。

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

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

最後に、便利な特殊なケースの1つは、応答を返さない可能性がある関数を使用してマッピングすることOptionです。を使用flatMapして、返される要素を除外し、Noneaを返す要素から値を抽出できます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)

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


1
地図ギブ内の分裂を呼び出すだろうか["a b c", "", "d"] => [["a","b","c"],[],["d"]]
user2635088

1
はい-(ただし、私の非公式な表記はある種のコレクションを示すためのものでした-実際にsplitは文字列のリストへのマッピングは配列のリストを生成します)
DNA

2
それを書いてくれてありがとう、これは私が同じものの違いを区別するために読んだ最高の説明です
Rajiv

97

通常、hadoopでは単語数の例を使用します。私は同じユースケースを使用して使用mapflatMap、データの処理方法の違いを確認します。

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

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

上記のファイルはmapおよびを使用して解析されますflatMap

使用する 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']

出力はマップとは異なります。


各キーの値として1を割り当てて、単語数を取得します。

  • fm:を使用して作成されたRDD flatMap
  • wc:を使用して作成されたRDD map
>>> 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)]

一方flatMap、RDD wcは以下の望ましくない出力を提供します。

>>> 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

定義に従って、違いmapflatMapされています。

map:RDDの各要素に特定の関数を適用することにより、新しいRDDを返します。関数in mapは1つのアイテムのみを返します。

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


14
私はこの答えが受け入れられた答えよりも優れていると感じています。
クリシュナ

15
出力テキストをコピーして貼り付けることができるのに、なぜ判読できないスクリーンショットを作成するのですか?
nbubis 2016年

つまり、flatMap()はmap()+ "flatten"であり、あまり意味がないことはわかっていますが、map()の後に使用できる "flatten"関数はありますか?
ブラコンガン2016

2
コードに誤解を招くタイプミスがあります。の結果は.map(lambda line:line.split(" "))文字列の配列ではありません。に変更data.collect() するwc.collect必要があり、配列の配列が表示されます。
swdev 2017年

1
ええ、でもコマンドの結果はまだ間違っています。走ったwc.collect()
swdev 2017年

18

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

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) )

17

それはあなたの最初の質問に要約されます:あなたが平らにすることはどういう意味ですか?

flatMapを使用すると、「多次元」コレクションは「1次元」コレクションになります。

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次元構造です。

15

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.)

mapmethod を使用すると、の行が表示されtest.mdflatMapmethodには、単語の数が表示されます。

mapこの方法は、に似ているflatMap、彼らはすべての新しいRDDを返しています。map多くの場合、新しいRDDを返すために使用する方法、flatMap分割した単語を使用するために頻繁に使用する方法。


9

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.pyflatMap、追加する前に欠落データを除外するために使用します。以前のバージョンと比較して追加される数は少なくなっています。

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

8

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

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


7

すべての例は良いです...ここに素敵な視覚的なイラストがあります...ソースの礼儀:スパークのDataFlairトレーニング

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

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

ここに画像の説明を入力してください

mapscala の使用例:

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:

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

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

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

ここに画像の説明を入力してください

flatMapscala の使用例:

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)

5

違いは、以下のサンプル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]]

3

FlatmapとMapはどちらもコレクションを変換します。

差:

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

flatMap(func)
mapに似ていますが、各入力項目は0以上の出力項目にマップできます(そのため、funcは単一の項目ではなくSeqを返す必要があります)。

変換関数:
map:1つの要素が入る-> 1つの要素が出る。
flatMap:1つの要素が入っている-> 0以上の要素が入っている(コレクション)。


3

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)

2

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

変換の例:flatMap

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

['やあ、元気']

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

トレースバック(最後の最後の呼び出し):ファイル ""、行1、AttributeError: '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()

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

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


2

mapRDD関数をの各要素に適用することにより、新しいを返しますRDD。.map内の関数は1つのアイテムのみを返すことができます。

flatMap:マップと同様に、それは新しいを返すRDDことにより、RDDの各要素に関数を適用しますが、出力が平坦化されています。

また、関数in 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、2、1、2、3、1、2、3、4]

出典:https : //www.linkedin.com/pulse/difference-between-map-flatmap-transformations-spark-pyspark-pandey/



-1

mapとflatMapの出力の違い:

1。flatMap

val a = sc.parallelize(1 to 10, 5)

a.flatMap(1 to _).collect()

出力:

 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

2. map

val a = sc.parallelize(List("dog", "salmon", "salmon", "rat", "elephant"), 3)

val b = a.map(_.length).collect()

出力:

3 6 6 3 8

-1
  • map(func)宣言された関数funcを介してソースの各要素を渡すことによって形成された新しい分散データセットを返します。somap()は単一の用語です

  • flatMap(func)mapに似ていますが、各入力項目は0以上の出力項目にマップできるため、funcは単一の項目ではなくシーケンスを返す必要があります。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.