map과 flatMap의 차이점은 무엇이며 각각의 좋은 사용 사례는 무엇입니까?


249

누군가 map과 flatMap의 차이점과 각각의 좋은 사용 사례를 설명해 줄 수 있습니까?

"결과 평평"이란 무엇을 의미합니까? 무엇이 좋은가요?


4
당신은 스파크 태그를 추가하기 때문에, 나는 당신에 대해 요구하고 있다고 가정합니다 RDD.mapRDD.flatMap아파치 스파크 . 일반적으로 Spark의 RDD 작업은 해당 Scala 수집 작업 후에 모델링됩니다. 스칼라 와 의 차이점을 설명하는 stackoverflow.com/q/1059776/590203 의 답변 이 도움이 될 수 있습니다. mapflatMap
Josh Rosen

1
여기서 대부분의 예제는 flatMap이 콜렉션에서만 작동한다고 가정하는 것 같습니다.
Boon

답변:


195

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의 RDD를 길이 N의 다른 RDD로 변환합니다.

예를 들어 두 줄에서 두 줄 길이로 매핑됩니다.

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

한 줄에 여러 단어가 있고 여러 줄이 있지만 단어의 단일 출력 배열로 끝납니다.

설명을 위해, 줄 모음에서 단어 모음으로의 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은 하나의 요소 또는 0 개의 요소가있는 목록과 비슷하게 작동 함)


1
지도 내에서 스플릿을 호출하면 ["a b c", "", "d"] => [["a","b","c"],[],["d"]]?
user2635088

1
예-(그러나 비공식적 인 표기법은 일종의 모음을 나타냅니다. 실제로 split문자열 목록을 매핑 하면 배열 목록이 생성됩니다)
DNA

2
그것을 작성해 주셔서 감사합니다, 이것은 제가 동일한 내용의 차이점을 구별하기 위해 읽은 최고의 설명입니다
Rajiv

97

일반적으로 hadoop에서 단어 수 예제를 사용합니다. 나는 동일한 유스 케이스를 사용 map하고 사용할 flatMap것이며 데이터를 처리하는 방법의 차이점을 볼 것입니다.

아래는 샘플 데이터 파일입니다.

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

위의 파일은 mapand를 사용하여 구문 분석됩니다 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)]

반면 flatMapRDD 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:와 마찬가지로 mapRDD의 각 요소에 함수를 적용하여 새 RDD를 반환하지만 출력은 평평합니다.


14
이 답변이 허용되는 답변보다 낫다고 생각합니다.
Krishna

15
출력 텍스트를 복사하여 붙여 넣기 만하면 왜 읽을 수없는 스크린 샷을 만들어야합니까?
nbubis 2016 년

그래서 flatMap ()은 map () + "flatten"이며 이해가되지 않지만 map () 뒤에 사용할 수있는 "flatten"함수가 있습니까?
burakongun

2
코드에 잘못된 오타가 있습니다. 결과는 .map(lambda line:line.split(" "))문자열 배열이 아닙니다. 당신은 변경해야합니다 data.collect() 으로 wc.collect당신은 배열의 배열을 볼 수 있습니다.
swdev

1
예, 그러나 명령 결과는 여전히 잘못되었습니다. 뛰었 어 wc.collect()?
swdev 2016 년

18

Spark에서 RDD.map과 RDD.flatMap의 차이점을 묻는 경우 map은 N 크기의 RDD를 N 크기의 다른 것으로 변환합니다. 예.

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

당신이 사용하는 경우 map방법, 당신의 라인을 얻을 것이다 test.md위해, flatMap방법, 당신은 단어의 수를 얻을 것이다.

map방법 flatMap은와 유사하며 모두 새로운 RDD를 반환합니다. map자주 사용하는 flatMap메소드 는 새로운 RDD를 리턴하고, 종종 분리 단어를 사용하는 메소드입니다.


9

map동일 flatMap하지 않은 요소 수의 RDD를 반환합니다 .

flatMap누락되거나 잘못된 데이터 필터링하는 사용 사례의 예 입니다.

map입력 및 출력 요소의 수가 동일한 다양한 경우에 사용 하기위한 사용 사례의 예 .

number.csv

1
2
3
-
4
-
5

map.pyadd.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에서 한 줄을 가져 와서 함수를 적용한다는 점에서 비슷합니다. 차이점은 map의 함수는 하나의 요소 만 반환하지만 flatMap의 함수는 요소 목록 (0 이상)을 반복자로 반환 할 수 있다는 것입니다.

또한 flatMap의 출력이 평탄화됩니다. flatMap의 함수는 요소 목록을 리턴하지만 flatMap은 목록의 모든 요소를 ​​목록이 아닌 플랫 방식으로 갖는 RDD를 리턴합니다.


7

모든 예제가 훌륭합니다 ... 여기에 멋진 시각적 인 그림이 있습니다 ... 소스 예의 : 스파크의 DataFlair 교육

지도 :지도는 Apache Spark에서 변형 작업입니다. RDD의 각 요소에 적용되며 결과를 새 RDD로 리턴합니다. 맵에서 운영 개발자는 자신의 사용자 정의 비즈니스 로직을 정의 할 수 있습니다. RDD의 모든 요소에 동일한 논리가 적용됩니다.

Spark RDD map함수는 사용자 정의 코드 (개발자가 지정한)에 따라 입력 프로세스로 하나의 요소를 가져와 한 번에 하나의 요소를 반환합니다. 맵은 길이 N의 RDD를 길이 N의 다른 RDD로 변환합니다. 입력 및 출력 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의 각 요소에 적용되며 결과를 new로 반환합니다 RDD. Map과 비슷하지만 FlatMap을 사용하면 map 함수에서 0, 1 개 이상의 요소를 반환 할 수 있습니다. FlatMap 작업에서 개발자는 자신의 사용자 지정 비즈니스 논리를 정의 할 수 있습니다. RDD의 모든 요소에 동일한 논리가 적용됩니다.

"결과 평평"이란 무엇을 의미합니까?

FlatMap 함수는 사용자 정의 코드 (개발자가 지정한)에 따라 하나의 요소를 입력 프로세스로 사용하여 한 번에 0 개 이상의 요소를 리턴합니다. flatMap()는 길이 N의 RDD를 길이 M의 다른 RDD로 변환합니다.

여기에 이미지 설명을 입력하십시오

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)

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

플랫 맵과 맵은 모두 컬렉션을 변환합니다.

차:

map (func)
소스의 각 요소를 함수 func에 전달하여 형성된 새로운 분산 데이터 세트를 반환합니다.

flatMap (func)
map과 비슷하지만 각 입력 항목을 0 개 이상의 출력 항목에 매핑 할 수 있습니다. 따라서 func은 단일 항목이 아닌 Seq를 반환해야합니다.

변환 함수 :
map : 하나의 요소-> 하나의 요소 출력.
flatMap :-> 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()

역 추적 (가장 최근 호출 마지막) : AttributeError : 'list'개체의 파일 "", 행 1에 '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

map:의 RDD각 요소에 함수를 적용 하여 새 를 반환 합니다 RDD. .map의 함수는 하나의 항목 만 반환 할 수 있습니다.

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를 통해 전달 된 새로운 분산 데이터 세트를 반환합니다.

그런데

  • flatMap (func) map과 비슷하지만 각 입력 항목을 0 개 이상의 출력 항목에 매핑 할 수 있으므로 func은 단일 항목이 아닌 시퀀스를 반환해야합니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.