Чи може хтось пояснити мені різницю між картою та flatMap та чим корисним є використання для кожного?
Що означає "вирівнювання результатів"? Для чого це добре?
Чи може хтось пояснити мені різницю між картою та flatMap та чим корисним є використання для кожного?
Що означає "вирівнювання результатів"? Для чого це добре?
Відповіді:
Ось приклад різниці, як spark-shell
сеанс:
По-перше, деякі дані - два рядки тексту:
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
перетворює RDD довжиною N в інший RDD довжини N.
Наприклад, він відображає з двох рядків на дві довжини рядків:
rdd.map(_.length).collect
res1: Array[Int] = Array(13, 16)
Але flatMap
(слабко кажучи) перетворює RDD довжиною N в колекцію N колекцій, а потім згладжує їх в єдину RDD результатів.
rdd.flatMap(_.split(" ")).collect
res2: Array[String] = Array("Roses", "are", "red", "Violets", "are", "blue")
У нас є кілька слів на рядок і кілька рядків, але ми закінчуємо одним вихідним масивом слів
Просто для того, щоб проілюструвати це, flatMapping із колекції рядків до колекції слів виглядає так:
["aa bb cc", "", "dd"] => [["aa","bb","cc"],[],["dd"]] => ["aa","bb","cc","dd"]
Отже, вхідні та вихідні RDD зазвичай будуть різного розміру для flatMap
.
Якби ми намагалися використовувати map
свою split
функцію, ми б закінчилися вкладеними структурами (RDD масивів слів з типом RDD[Array[String]]
), тому що ми повинні мати рівно один результат на кожен вхід:
rdd.map(_.split(" ")).collect
res3: Array[Array[String]] = Array(
Array(Roses, are, red),
Array(Violets, are, blue)
)
Нарешті, один корисний особливий випадок - це відображення з функцією, яка може не повернути відповідь, і таким чином повертає відповідь 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)
(тут зазначаючи, що Опція поводиться скоріше як список, який містить або один елемент, або нульові елементи)
["a b c", "", "d"] => [["a","b","c"],[],["d"]]
?
split
списку рядків створить список масивів)
Зазвичай ми використовуємо приклад підрахунку слів у hadoop. Я візьму один і той же випадок використання і буде використовувати map
і flatMap
ми побачимо різницю , як вона обробляє дані.
Нижче наведено зразок файлу даних.
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
.
Відповідно до визначення, різниця між map
та flatMap
становить:
map
: Він повертає новий RDD, застосовуючи задану функцію до кожного елемента RDD. Функціяmap
повертає лише один елемент.
flatMap
: Подібно до цьогоmap
, він повертає новий RDD, застосовуючи функцію до кожного елемента RDD, але вихід вирівнюється.
.map(lambda line:line.split(" "))
не є масив рядків. Ви повинні перейти data.collect()
на, wc.collect
і ви побачите масив масивів.
wc.collect()
?
Якщо ви запитуєте різницю між RDD.map та RDD.flatMap в Spark, карта перетворює RDD розміром N в інший розміром N. напр.
myRDD.map(x => x*2)
наприклад, якщо myRDD складається з парних пар.
У той час як flatMap може перетворити RDD в пильовик одного розміру: напр .:
myRDD.flatMap(x =>new Seq(2*x,3*x))
який поверне RDD розміром 2 * N або
myRDD.flatMap(x =>if x<10 new Seq(2*x,3*x) else new Seq(x) )
Це зводиться до вашого первинного питання: що ви маєте на увазі під сплющенням ?
Коли ви використовуєте 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, коли,
Використовуйте 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
, вони все повертаються новий РДД. map
метод часто використовувати повернення нового RDD, flatMap
метод часто використовувати розділені слова.
map
повертає RDD з рівною кількістю елементів при цьому flatMap
може не бути.
Приклад використання випадку дляflatMap
фільтрації відсутніх або неправильних даних.
Приклад використання випадку дляmap
використання в найрізноманітніших випадках, коли кількість елементів введення та виведення однакові.
номер.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
map і flatMap схожі, в тому сенсі вони беруть рядок від вхідного RDD і застосовують до нього функцію. Вони відрізняються тим, що функція в карті повертає лише один елемент, тоді як функція в flatMap може повертати список елементів (0 або більше) як ітератор.
Також вихід плоскої карти згладжений. Хоча функція в flatMap повертає список елементів, flatMap повертає RDD, який містить усі елементи зі списку рівним способом (а не список).
всі приклади хороші .... Ось приємна візуальна ілюстрація ... ввічливість джерела: Навчання DataFlair іскри
Карта: Карта - це операція перетворення в Apache Spark. Він застосовується до кожного елемента RDD і повертає результат як новий RDD. На карті розробник операцій може визначити власну логіку бізнесу. Така ж логіка буде застосована до всіх елементів RDD.
map
Функція Іскра ІРД приймає один елемент як процес введення його відповідно до користувальницького коду (вказаний розробником) і повертає один елемент за один раз. Карта перетворює RDD довжиною N в інший RDD довжини N. Вхідні та вихідні RDD зазвичай мають однакову кількість записів.
Приклад 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:
A flatMap
- операція перетворення. Він застосовується до кожного елемента RDD і повертає результат як новий RDD
. Це схоже на Map, але FlatMap дозволяє повернути 0, 1 або більше елементів з функції карти. В операції FlatMap розробник може визначити власну власну логіку бізнесу. Така ж логіка буде застосована до всіх елементів RDD.
Що означає "вирівнювання результатів"?
Функція FlatMap приймає один елемент як процес введення його відповідно до користувальницького коду (вказаного розробником) і одночасно повертає 0 або більше елементів. flatMap
() перетворює RDD довжини N в інший RDD довжини M.
Приклад 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)
Різниця видно знизу зразкового коду 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]]
Flatmap та Map перетворюють колекцію.
Різниця:
map (func)
Повернення нового розподіленого набору даних, сформованого шляхом передачі кожного елемента джерела через функцію func.
flatMap (func)
Подібно до карти, але кожен елемент введення може бути відображений до 0 або більше вихідних елементів (тому функція повинна повертати Seq, а не один елемент).
Функція перетворення:
map : один елемент у -> один елемент.
flatMap : Один елемент у -> 0 або більше елементів (колекція).
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)
Для всіх, хто хотів пов'язати PySpark:
Приклад перетворення: flatMap
>>> a="hello what are you doing"
>>> a.split()
['Привіт, що ти робиш']
>>> b=["hello what are you doing","this is rak"]
>>> b.split()
Traceback (останній виклик останній): Файл "", рядок 1, в AttributeError: "список" об'єкта не має атрибута "розділити"
>>> rline=sc.parallelize(b)
>>> type(rline)
>>> def fwords(x):
... return x.split()
>>> rword=rline.map(fwords)
>>> rword.collect()
[['привіт', 'що', 'є', 'ти', 'робиш]], [' це ',' є ',' рейк ']]
>>> rwordflat=rline.flatMap(fwords)
>>> rwordflat.collect()
['привіт', 'що', 'є', 'ти', 'робиш', 'це', 'є', 'рейк']
Сподіваюся, це допомагає :)
map
: Він повертає нове RDD
, застосовуючи функцію до кожного елемента RDD
. Функція в .map може повертати лише один елемент.
flatMap
: Подібно до карти, він повертає нове RDD
, застосовуючи функцію до кожного елемента RDD, але вихід вирівнюється.
Також функція в 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/
карта:
- метод вищого порядку, який приймає функцію як вхідну інформацію і застосовує її до кожного елемента вихідної RDD.
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
вили
RDD.map
іRDD.flatMap
в Apache Спарк . Взагалі, RDD-операції Spark моделюються після відповідних операцій збору Scala. Відповіді в stackoverflow.com/q/1059776/590203 , в яких обговорюється відмінність між Scalamap
таflatMap
в ньому, можуть бути корисними для вас.