Map ve flatMap ve her biri için iyi bir kullanım durumu arasındaki fark nedir?


249

Birisi bana harita ve flatMap arasındaki farkı açıklayabilir ve her biri için iyi bir kullanım durumu nedir?

"Sonuçları düzleştir" ne anlama geliyor? Bu ne için iyi?


4
Spark etiketini eklediğinizden beri , Apache Spark hakkında RDD.mapve RDD.flatMapiçinde istediğinizi varsayalım . Genel olarak, Spark'ın RDD operasyonları karşılık gelen Scala toplama operasyonlarından sonra modellenir. Scala arasındaki ve Scala arasındaki farkı tartışan stackoverflow.com/q/1059776/590203 adresindeki yanıtlar size yardımcı olabilir. mapflatMap
Josh Rosen

1
Buradaki örneklerin çoğunun flatMap'in yalnızca koleksiyonda çalıştığını varsaydığı görülüyor, bu durum böyle değil.
Boon

Yanıtlar:


195

İşte bir spark-shelloturum olarak farkın bir örneği :

İlk olarak, bazı veriler - iki metin satırı:

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

rdd.collect

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

Şimdi, mapN uzunluğundaki bir RDD'yi N uzunluğundaki başka bir RDD'ye dönüştürür.

Örneğin, iki satırdan iki satır uzunluğuna eşler:

rdd.map(_.length).collect

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

Ancak flatMap(gevşekçe), N uzunluğunda bir RDD'yi N koleksiyonuna dönüştürür, sonra bunları tek bir RDD sonuçlarına düzleştirir.

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

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

Her satırda birden çok kelime ve birden çok satır var, ancak sonuçta tek bir çıktı dizisi elde ediyoruz

Bunu açıklamak için, bir satır koleksiyonundan bir kelime koleksiyonuna geçmek şu şekildedir:

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

Bu nedenle giriş ve çıkış RDD'leri tipik olarak farklı boyutlarda olacaktır flatMap.

Kullandığımız çalıştı olsaydı mapbizim ile splitfonksiyonu, biz iç içe yapılar (tip kelimelerin diziler RDD ile sona erdi olurdu RDD[Array[String]]biz girdi başına tam olarak bir sonuç olması gerekir çünkü):

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

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

Son olarak, kullanışlı bir özel durum, bir yanıtı döndürmeyebilecek bir işlevle eşleştirmektir ve bu nedenle bir Option. Biz kullanabilirsiniz flatMapo dönüş elemanları filtrelemek için Nonebir dönüş olanlar değerleri ve ayıklamak 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)

(burada bir Seçeneğin bir öğe veya sıfır öğe içeren bir liste gibi davranacağına dikkat edin)


1
Harita içindeki bölünmüş çağrı verir ["a b c", "", "d"] => [["a","b","c"],[],["d"]]mi?
user2635088

1
Evet - (ancak resmi olmayan gösterimin sadece bir çeşit koleksiyonu belirtmek olduğunu unutmayın - aslında splitbir Dizeler listesi eşlemek Dizilerin Listesi üretecektir)
DNA

2
Yazdığınız için teşekkürler, bu aynı arasındaki farkı ayırt etmek için okuduğum en iyi açıklama
Rajiv

98

Genellikle hadoop'ta kelime sayısı örneğini kullanırız. Aynı kullanım durumunu alacağım ve kullanacağım mapve flatMapverileri nasıl işlediğini göreceğiz.

Örnek veri dosyası aşağıdadır.

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

Yukarıdaki dosya mapve ile ayrıştırılacaktır flatMap.

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

Girdinin 4 satırı vardır ve çıktı boyutu da 4'tür, yani N öğeleri ==> N öğeleri.

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

Çıktı haritadan farklı.


Kelime sayısını elde etmek için her tuş için 1 değerini atayalım.

  • fm: RDD kullanılarak oluşturuldu flatMap
  • wc: RDD kullanılarak oluşturuldu 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)]

Oysa flatMapRDD üzerinde wcistenmeyen çıkış altında verir:

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

Bunun mapyerine kullanılırsa kelime sayısını alamazsınız flatMap.

Tanıma göre mapve arasındaki fark flatMap:

map: RDD'nin her öğesine verilen işlevi uygulayarak yeni bir RDD döndürür. İçindeki işlev mapyalnızca bir öğe döndürür.

flatMap: Benzer şekilde map, RDD'nin her öğesine bir işlev uygulayarak yeni bir RDD döndürür, ancak çıktı düzleştirilir.


14
bu cevabın kabul edilen cevaptan daha iyi olduğunu hissediyorum.
Krishna

15
Çıktı metnini kopyalayıp yapıştırabildiğinizde neden yeryüzünde okunaksız ekran görüntüleri oluşturuyorsunuz?
nbubis

Yani flatMap () map () + "flatten" dir ve çok mantıklı olmadığını biliyorum ama map () sonrasında kullanabileceğimiz herhangi bir "flatten" işlevi var mı?
burakongun

2
Kodunuzda yanıltıcı bir yazım hatası var. Sonucu .map(lambda line:line.split(" "))dizelerden oluşan bir dizi değil. Sen değişmelidir data.collect() için wc.collectve diziler içeren bir dizi göreceksiniz.
swdev

1
evet, ama komutun sonucu hala yanlış. koştun wc.collect()mu
swdev

18

Spark'da RDD.map ve RDD.flatMap arasındaki farkı soruyorsanız, harita N boyutundaki bir RDD'yi N boyutundaki başka bir RDD'ye dönüştürür. Örneğin.

myRDD.map(x => x*2)

örneğin, myRDD, Çiftler'den oluşuyorsa.

FlatMap, RDD'yi farklı boyuttaki bir taneye dönüştürebilir:

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

2 * N boyutunda bir RDD döndürecek veya

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

17

İlk sorunuza kaynar: düzleştirmekle ne demek istiyorsun ?

FlatMap kullandığınızda, "çok boyutlu" bir koleksiyon "tek boyutlu" bir koleksiyon haline gelir .

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)

Aşağıdaki durumlarda flatMap kullanmak istiyorsunuz,

  • harita işleviniz çok katmanlı yapılar oluşturmanıza neden olur
  • ama tüm istediğiniz TÜM iç gruplamaları kaldırarak basit - düz - tek boyutlu bir yapı

15

test.mdÖrnek olarak kullanın :

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

mapMetod kullanırsanız, metod test.mdiçin flatMapkelime sayısını alırsınız.

mapYöntem benzer flatMap, hepsi dönüş yeni RDD vardır. mapyöntem genellikle yeni bir RDD döndürmek için flatMapyöntem, genellikle bölünmüş sözcükleri kullanmak için yöntem.


9

mapeşit flatMapolmasa da eşit sayıda öğenin RDD değerini döndürür .

flatMapEksik veya yanlış verileri filtrelemek için örnek bir kullanım örneği .

mapGiriş ve çıkış elemanlarının sayısının aynı olduğu çok çeşitli durumlarda Kullanım için örnek bir kullanım örneği .

number.csv

1
2
3
-
4
-
5

map.py tüm numaraları add.csv dosyasına ekler.

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 kullanırflatMap ilave edilmeden önce eksik verilere filtre için. Önceki sürüme kıyasla daha az sayı eklenir.

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 ve flatMap benzerdir, yani RDD girişinden bir çizgi alırlar ve üzerine bir işlev uygularlar. Farklı olmaları, haritadaki işlevin yalnızca bir öğe döndürmesidir; flatMap'teki işlev ise yineleyici olarak bir öğe listesi (0 veya daha fazla) döndürebilir.

Ayrıca, flatMap'in çıktısı düzleştirilir. FlatMap içindeki işlev bir öğe listesi döndürse de, flatMap listeden tüm öğeleri düz bir şekilde içeren (bir liste değil) bir RDD döndürür.


7

tüm örnekler iyi .... İşte güzel görsel illüstrasyon ... kaynak nezaket: Spark kıvılcım DataFlair eğitimi

Harita: Harita, Apache Spark'daki bir dönüşüm işlemidir. RDD'nin her bir öğesi için geçerlidir ve sonucu yeni RDD olarak döndürür. Harita'da, operasyon geliştiricisi kendi özel iş mantığını tanımlayabilir. Aynı mantık RDD'nin tüm elemanlarına uygulanacaktır.

Spark RDD mapişlevi, bir öğeyi özel koda (geliştirici tarafından belirtilir) göre girdi işlemi olarak alır ve her defasında bir öğe döndürür. Harita, N uzunluğundaki bir RDD'yi N uzunluğundaki başka bir RDD'ye dönüştürür. Giriş ve çıkış RDD'leri tipik olarak aynı sayıda kayda sahip olacaktır.

resim açıklamasını buraya girin

mapScala kullanımına örnek :

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

Düz harita :

A flatMapbir dönüşüm işlemidir. RDD'nin her bir öğesi için geçerlidir ve sonucu yeni olarak döndürür RDD. Harita'ya benzer, ancak FlatMap harita işlevinden 0, 1 veya daha fazla öğenin döndürülmesine izin verir. FlatMap işleminde, bir geliştirici kendi özel iş mantığını tanımlayabilir. Aynı mantık RDD'nin tüm elemanlarına uygulanacaktır.

"Sonuçları düzleştir" ne anlama geliyor?

Bir FlatMap işlevi, bir öğeyi özel koda (geliştirici tarafından belirtilir) göre girdi işlemi olarak alır ve bir seferde 0 veya daha fazla öğe döndürür. flatMap() N uzunluğunda bir RDD'yi M uzunluğunda başka bir RDD'ye dönüştürür.

resim açıklamasını buraya girin

flatMapScala kullanımına örnek :

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

Fark aşağıdaki örnek pyspark kodundan görülebilir:

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 ve Map, koleksiyonu dönüştürür.

Fark:

map (fonk)
Kaynağın her elemanını bir fonksiyon fonkusundan geçirerek oluşturulan yeni dağıtılmış veri kümesini döndürür.

flatMap (fonk)
Haritaya benzer, ancak her girdi öğesi 0 veya daha fazla çıktı öğesine eşlenebilir (bu nedenle işlev, tek bir öğe yerine Seq döndürmelidir).

Dönüştürme işlevi:
map : Bir öğe girişi -> bir öğe çıkışı.
flatMap : -> 0 veya daha fazla öğe içeren bir öğe (bir koleksiyon).


3

RDD.map tek bir dizideki tüm öğeleri döndürür

RDD.flatMap Dizi Dizileri'ndeki öğeleri döndürür

metin.txt dosyasında şu şekilde metin bulunduğumuzu varsayalım:

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

Haritayı kullanma

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

çıktı:

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 kullanma

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

çıktı:

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

2

PySpark ile ilgili isteyenler için:

Örnek dönüşüm: flatMap

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

['Merhaba ne yapıyorsun']

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

İzleme

>>> rline=sc.parallelize(b)
>>> type(rline)

>>> def fwords(x):
...     return x.split()


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

[['merhaba', 'ne', 'vardır', 'siz', 'yapıyor'], ['bu', '', 'rak']]]

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

['merhaba', 'ne', 'vardır', 'siz', 'yapıyor', 'bu', '', 'rak']

Umarım yardımcı olur :)


2

map: RDDÖğesinin her öğesine bir işlev uygulayarak yeni bir değer döndürür RDD. .Map içindeki işlev yalnızca bir öğe döndürebilir.

flatMap: Benzer yeni bir döner, haritaya RDDgöre RDD her öğesi için bir işlev uygulayarak, ancak çıkış düzleşir.

Ayrıca, flatMap bir öğe listesi döndürebilir (0 veya daha fazla)

Örneğin:

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

Çıktı: [[1, 2], [1, 2, 3], [1, 2, 3, 4]]

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

Çıktı: o / p bildirimi tek bir listede düzleştirilir [1, 2, 1, 2, 3, 1, 2, 3, 4]

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



-1

Harita ve flatMap çıktılarındaki fark:

1.flatMap

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

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

Çıktı:

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

Çıktı:

3 6 6 3 8

-1
  • map (func) Kaynağın her bir öğesini bildirilen func işlevinden geçirerek oluşturulan yeni dağıtılmış veri kümesini döndürür. so map () tek terimdir

whiles

  • flatMap (fonk) Haritaya benzer, ancak her girdi öğesi 0 veya daha fazla çıktı öğesine eşlenebilir; bu nedenle işlev, tek bir öğe yerine bir Sıra döndürmelidir.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.