Может ли кто-нибудь объяснить мне разницу между map и flatMap и что является хорошим вариантом использования для каждого?
Что означает "сгладить результаты"? Для чего это полезно?
Может ли кто-нибудь объяснить мне разницу между map и 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
преобразует СДР длиной N в другой СДР длины N.
Например, он отображается из двух строк в две длины строки:
rdd.map(_.length).collect
res1: Array[Int] = Array(13, 16)
Но flatMap
(условно говоря) преобразует СДР длины N в набор из N коллекций, а затем объединяет их в одну СДР результатов.
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)
(отмечая здесь, что Option ведет себя скорее как список, который имеет либо один элемент, либо ноль элементов)
Обычно мы используем пример подсчета слов в 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
: СДР создан с использованием flatMap
wc
: СДР создан с использованием 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
на СДР 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]
Вы не можете получить количество слов, если вместо flatMap
используется map
.
Согласно определению, разница между map
и flatMap
составляет:
map
: возвращает новый СДР, применяя данную функцию к каждому элементу СДР. Функция вmap
возвращает только один элемент.
flatMap
: аналогичноmap
, возвращает новую СДР, применяя функцию к каждому элементу СДР, но вывод выравнивается.
Если вы задаете разницу между 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) )
Используйте 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
часто для использования разделенных слов.
Это сводится к вашему первоначальному вопросу: что вы подразумеваете под сглаживанием?
Когда вы используете 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, когда,
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
map и flatMap аналогичны, в том смысле, что они берут строку из входного RDD и применяют к ней функцию. Их отличие заключается в том, что функция на карте возвращает только один элемент, а функция в flatMap может возвращать список элементов (0 или более) в качестве итератора.
Кроме того, вывод flatMap сплющен. Хотя функция в flatMap возвращает список элементов, flatMap возвращает RDD, который имеет все элементы из списка плоским способом (не список).
Разницу можно увидеть из приведенного ниже примера кода 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]]
все примеры хороши.... Вот хорошая наглядная иллюстрация... источник любезно: DataFlair обучение искры
Карта: карта - это операция преобразования в Apache Spark. Он применяется к каждому элементу СДР и возвращает результат как новый СДР. На карте разработчик операции может определить свою собственную бизнес-логику. Та же логика будет применяться ко всем элементам СДР.
Функция map
Spark RDD принимает один элемент в качестве входного процесса, обрабатывает его в соответствии с пользовательским кодом (указанным разработчиком) и возвращает один элемент за раз. Карта преобразует СДР длиной N в другой СДР длины N. Как правило, входные и выходные СДР имеют одинаковое количество записей.
Пример map
с использованием 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 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
. Он похож на Map, но FlatMap позволяет возвращать 0, 1 или более элементов из функции карты. В операции FlatMap разработчик может определить свою собственную бизнес-логику. Та же логика будет применяться ко всем элементам СДР.
Что значит "сгладить результаты"?
Функция FlatMap принимает один элемент в качестве входного, обрабатывает его в соответствии с пользовательским кодом (указанным разработчиком) и возвращает 0 или более элементов одновременно. flatMap
() преобразует СДР длины N в другой СДР длины M.
Пример flatMap
с использованием 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)
Flatmap и Map преобразуют коллекцию.
Difference:
карта (FUNC)
Верните новый распределенный набор данных, сформированный путем передачи каждого элемента источника с помощью функции func.
flatMap (FUNC)
Подобно карте, но каждый элемент ввода может быть сопоставлен с 0 или более выходными элементами (поэтому func должен возвращать Seq, а не один элемент).
Функция преобразования:
карта: один элемент в → один элемент.
flatMap: один элемент в → 0 или более элементов (коллекция).
RDD.map
возвращает все элементы в одном массиве
RDD.flatMap
возвращает элементы в 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()
['hello', 'what', 'are', 'you', 'doing']
>>> b=["hello what are you doing","this is rak"]
>>> b.split()
Traceback (последний последний вызов): Файл "", строка 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']
Надеюсь, это поможет:)
map
: возвращает новый RDD
, применяя функцию к каждому элементу RDD
. Функция в .map может вернуть только один элемент.
flatMap
: Аналогично map, он возвращает новый 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()
Вывод: уведомление о/п сведено в единый список [1, 2, 1, 2, 3, 1, 2, 3, 4]
Источник: https://www.linkedin.com/pulse/difference-between-map-flatmap-transformations-spark-pyspark-pandey/
карта:
это метод более высокого порядка, который принимает функцию в качестве входных данных и применяет ее к каждому элементу в исходном СДР.
flatMap:
метод высшего порядка и операция преобразования, которая принимает входную функцию.
Разница в выходе карты и 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
в то время как