Apa perbedaan antara peta dan flatMap dan kasus penggunaan yang baik untuk masing-masing?


249

Dapatkah seseorang menjelaskan kepada saya perbedaan antara peta dan flatMap dan apa gunanya kasus yang baik untuk masing-masing?

Apa yang dimaksud dengan "meratakan hasil"? Apa gunanya?


4
Karena Anda menambahkan tag Spark, saya akan berasumsi bahwa Anda bertanya tentang RDD.mapdan RDD.flatMapdi Apache Spark . Secara umum, operasi RDD Spark dimodelkan setelah operasi pengumpulan Scala yang sesuai. Jawaban di stackoverflow.com/q/1059776/590203 , yang membahas perbedaan antara mapdan flatMapdi Scala, mungkin bermanfaat bagi Anda.
Josh Rosen

1
Sebagian besar contoh di sini tampaknya mengasumsikan flatMap hanya beroperasi pada koleksi, yang bukan itu masalahnya.
Boon

Jawaban:


195

Berikut adalah contoh perbedaannya, sebagai spark-shellsesi:

Pertama, beberapa data - dua baris teks:

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

rdd.collect

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

Sekarang, mapmengubah RDD panjang N menjadi RDD panjang N.

Misalnya, memetakan dari dua garis menjadi dua panjang garis:

rdd.map(_.length).collect

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

Tetapi flatMap(secara longgar) mengubah RDD dengan panjang N menjadi koleksi koleksi N, kemudian meratakannya menjadi RDD tunggal hasil.

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

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

Kami memiliki beberapa kata per baris, dan beberapa baris, tetapi kami berakhir dengan satu array output kata

Hanya untuk menggambarkan itu, pemetaan datar dari kumpulan garis ke kumpulan kata-kata terlihat seperti:

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

Oleh karena itu, RDD input dan output biasanya memiliki ukuran yang berbeda untuk flatMap.

Jika kami mencoba menggunakan mapdengan splitfungsi kami , kami akan berakhir dengan struktur bersarang (RDD array kata, dengan tipe RDD[Array[String]]) karena kami harus memiliki satu hasil per input:

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

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

Akhirnya, satu kasus khusus yang berguna adalah pemetaan dengan fungsi yang mungkin tidak mengembalikan jawaban, dan karenanya mengembalikan sebuah Option. Kita dapat menggunakan flatMapuntuk memfilter elemen yang mengembalikan Nonedan mengekstrak nilai dari yang mengembalikan 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)

(mencatat di sini bahwa Opsi berperilaku lebih seperti daftar yang memiliki satu elemen, atau elemen nol)


1
Apakah panggilan perpecahan di dalam peta memberi ["a b c", "", "d"] => [["a","b","c"],[],["d"]]?
user2635088

1
Ya - (tapi perlu diketahui bahwa notasi informal saya hanya dimaksudkan untuk menunjukkan kumpulan sejenis - sebenarnya pemetaan splitatas daftar Strings akan menghasilkan Daftar Array)
DNA

2
Terima kasih telah menulisnya, ini adalah penjelasan terbaik yang saya baca untuk membedakan perbedaan antara yang sama
Rajiv

97

Secara umum kami menggunakan contoh jumlah kata dalam hadoop. Saya akan menggunakan use case yang sama dan akan menggunakan mapdanflatMap dan kita akan melihat perbedaan bagaimana memproses data.

Di bawah ini adalah file data sampel.

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

File di atas akan diuraikan menggunakan mapdan flatMap.

Menggunakan 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']

Input memiliki 4 baris dan ukuran output adalah 4 juga, yaitu, elemen N ==> elemen N.

Menggunakan 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']

Outputnya berbeda dari peta.


Mari kita menetapkan 1 sebagai nilai untuk setiap kunci untuk mendapatkan jumlah kata.

  • fm: RDD dibuat dengan menggunakan flatMap
  • wc: RDD dibuat menggunakan 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)]

Sedangkan flatMappada RDD wcakan memberikan output yang tidak diinginkan di bawah ini:

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

Anda tidak bisa mendapatkan jumlah kata jika mapdigunakan alih-alih flatMap.

Sesuai definisi, perbedaan antara mapdan flatMapadalah:

map: Ini mengembalikan RDD baru dengan menerapkan fungsi yang diberikan ke setiap elemen RDD. Berfungsi dalam mapmengembalikan hanya satu item.

flatMap: Mirip dengan map, ia mengembalikan RDD baru dengan menerapkan fungsi ke setiap elemen RDD, tetapi output diratakan.


14
Saya merasa jawaban ini lebih baik daripada jawaban yang diterima.
Krishna

15
Mengapa Anda membuat tangkapan layar yang tidak terbaca, padahal Anda hanya bisa menyalin tempel teks keluaran?
nbubis

Jadi flatMap () adalah map () + "ratakan" dan saya tahu itu tidak masuk akal tetapi apakah ada fungsi "ratakan" yang bisa kita gunakan setelah peta ()?
burakongun

2
Kode Anda memiliki kesalahan ketik yang menyesatkan. Hasil .map(lambda line:line.split(" "))bukan array string. Anda harus mengubah data.collect() ke wc.collectdan Anda akan melihat array array.
swdev

1
ya, tapi hasil dari perintahnya masih salah. apakah kamu lari wc.collect()?
swdev

18

Jika Anda menanyakan perbedaan antara RDD.map dan RDD.flatMap di Spark, peta mengubah RDD ukuran N ke yang lain dari ukuran N. misalnya.

myRDD.map(x => x*2)

misalnya, jika myRDD terdiri dari Doubles.

Sementara flatMap dapat mengubah RDD menjadi antera dengan ukuran berbeda: mis .:

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

yang akan mengembalikan RDD ukuran 2 * N atau

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

17

Itu bermuara pada pertanyaan awal Anda: apa yang Anda maksud dengan meratakan ?

Saat Anda menggunakan flatMap, koleksi "multi dimensi" menjadi koleksi "satu dimensi" .

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)

Anda ingin menggunakan flatMap ketika,

  • fungsi peta Anda menghasilkan pembuatan struktur berlapis-lapis
  • tetapi semua yang Anda inginkan adalah struktur satu dimensi sederhana - rata - rata, dengan menghilangkan SEMUA pengelompokan internal

15

Gunakan test.mdsebagai contoh:

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

Jika Anda menggunakan mapmetode, Anda akan mendapatkan garis test.md, untuk flatMapmetode, Anda akan mendapatkan jumlah kata.

The mapMetode ini mirip dengan flatMap, mereka semua kembali sebuah RDD baru. mapMetode sering menggunakan mengembalikan RDD baru, flatMapmetode sering menggunakan kata-kata split.


9

map mengembalikan RDD dengan jumlah elemen yang sama flatMap mungkin tidak.

Contoh kasus penggunaan untukflatMap Menyaring data yang hilang atau salah.

Contoh use case untukmap Use dalam berbagai kasus dimana jumlah elemen input dan outputnya sama.

number.csv

1
2
3
-
4
-
5

map.py menambahkan semua angka di 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 digunakan flatMapuntuk menyaring data yang hilang sebelum penambahan. Jumlah yang lebih sedikit ditambahkan dibandingkan dengan versi sebelumnya.

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

peta dan flatMap serupa, dalam arti mereka mengambil garis dari RDD input dan menerapkan fungsi di atasnya. Perbedaannya adalah bahwa fungsi di peta hanya mengembalikan satu elemen, sedangkan fungsi di flatMap dapat mengembalikan daftar elemen (0 atau lebih) sebagai iterator.

Juga, output dari flatMap diratakan. Meskipun fungsi dalam flatMap mengembalikan daftar elemen, flatMap mengembalikan RDD yang memiliki semua elemen dari daftar dengan cara datar (bukan daftar).


7

semua contoh baik .... Berikut ini adalah ilustrasi visual yang bagus ... sumber sumber: Pelatihan dataFlair percikan

Peta: Peta adalah operasi transformasi di Apache Spark. Ini berlaku untuk setiap elemen RDD dan mengembalikan hasilnya sebagai RDD baru. Di Peta, pengembang operasi dapat menentukan logika bisnis kustomnya sendiri. Logika yang sama akan diterapkan ke semua elemen RDD.

mapFungsi Spark RDD mengambil satu elemen sebagai input, memprosesnya sesuai dengan kode khusus (ditentukan oleh pengembang) dan mengembalikan satu elemen sekaligus. Peta mentransformasikan RDD dengan panjang N menjadi RDD dengan panjang lain dari N. RDD input dan output biasanya akan memiliki jumlah catatan yang sama.

masukkan deskripsi gambar di sini

Contoh mapmenggunakan scala:

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 flatMapadalah operasi transformasi. Ini berlaku untuk setiap elemen RDD dan mengembalikan hasilnya seperti baru RDD. Ini mirip dengan Peta, tetapi FlatMap memungkinkan pengembalian 0, 1 atau lebih elemen dari fungsi peta. Dalam operasi FlatMap, pengembang dapat menentukan logika bisnis kustomnya sendiri. Logika yang sama akan diterapkan ke semua elemen RDD.

Apa yang dimaksud dengan "meratakan hasil"?

Fungsi FlatMap mengambil satu elemen sebagai input, memprosesnya sesuai dengan kode khusus (ditentukan oleh pengembang) dan mengembalikan 0 elemen atau lebih sekaligus. flatMap() mengubah RDD dengan panjang N menjadi RDD dengan panjang M.

masukkan deskripsi gambar di sini

Contoh flatMapmenggunakan scala:

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

Perbedaannya dapat dilihat dari contoh kode pyspark di bawah ini:

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 dan Map, keduanya mengubah koleksi.

Perbedaan:

map (func)
Mengembalikan dataset terdistribusi baru yang dibentuk dengan melewatkan setiap elemen dari sumber melalui sebuah fungsi func.

flatMap (func)
Mirip dengan peta, tetapi setiap item input dapat dipetakan ke 0 atau lebih item output (jadi func harus mengembalikan Seq daripada satu item).

Fungsi transformasi:
peta : Satu elemen dalam -> satu elemen keluar.
flatMap : Satu elemen dalam -> 0 elemen atau lebih keluar (koleksi).


3

RDD.map mengembalikan semua elemen dalam array tunggal

RDD.flatMap mengembalikan elemen dalam array array

mari kita asumsikan kita memiliki teks dalam file text.txt sebagai

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

Menggunakan peta

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

keluaran:

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

Menggunakan flatMap

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

keluaran:

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

2

Untuk semua yang menginginkan PySpark terkait:

Contoh transformasi: flatMap

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

['Halo apa yang kamu lakukan']

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

Traceback (panggilan terakhir terakhir): File "", line 1, di AttributeError: objek 'list' tidak memiliki atribut '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']

Semoga bermanfaat :)


2

map: Ini mengembalikan yang baru RDDdengan menerapkan fungsi ke setiap elemen RDD. Fungsi dalam .map hanya dapat mengembalikan satu item.

flatMap: Mirip dengan peta, ia mengembalikan yang baru RDDdengan menerapkan fungsi ke setiap elemen RDD, tetapi hasilnya rata.

Juga, fungsi dalam flatMapdapat mengembalikan daftar elemen (0 atau lebih)

Sebagai contoh:

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

Output: [[1, 2], [1, 2, 3], [1, 2, 3, 4]]

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

Keluaran: pemberitahuan o / p diratakan dalam satu daftar [1, 2, 1, 2, 3, 1, 2, 3, 4]

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



-1

Perbedaan dalam output peta dan flatMap:

1.flatMap

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

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

Keluaran:

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

Keluaran:

3 6 6 3 8

-1
  • map (func) Mengembalikan dataset terdistribusi baru yang dibentuk dengan melewatkan setiap elemen sumber melalui fungsi func yang dinyatakan. jadi map () adalah istilah tunggal

sementara

  • flatMap (func) Mirip dengan peta, tetapi setiap item input dapat dipetakan ke 0 atau lebih item output sehingga func harus mengembalikan urutan daripada satu item.
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.