Как методы `map` и` reduce` работают в Spark RDD?

Следующий код приведен в кратком руководстве по началу работы Apache Spark. Может ли кто-нибудь объяснить мне, что такое переменная "строка" и откуда она взялась?

textFile.map(line => line.split(" ").size).reduce((a, b) => if (a > b) a else b)

Также, как передается значение в a, b?

Ссылка на QSG http://spark.apache.org/docs/latest/quick-start.html

Ответ 1

Сначала, согласно вашей ссылке, textfile создается как

val textFile = sc.textFile("README.md")

так что textfile является RDD[String], что означает гибкий распределенный набор данных типа String. API для доступа очень похож на API обычных коллекций Scala.

Итак, что делает это map?

Представьте, что у вас есть список String и вы хотите преобразовать его в список Ints, представляющий длину каждой строки.

val stringlist: List[String] = List("ab", "cde", "f")
val intlist: List[Int] = stringlist.map( x => x.length )

Метод map ожидает функцию. Функция, которая идет от String => Int. С помощью этой функции каждый элемент списка преобразуется. Таким образом, значение intlist равно List( 2, 3, 1 )

Здесь мы создали анонимную функцию из String => Int. Это x => x.length. Можно даже написать функцию более явную как

stringlist.map( (x: String) => x.length )  

Если вы используете запись выше, вы можете

val stringLength : (String => Int) = {
  x => x.length
}
val intlist = stringlist.map( stringLength )

Итак, здесь совершенно очевидно, что stringLength является функцией от String до Int.

Примечание: В общем, map - это то, что составляет так называемый Functor. Пока вы предоставляете функцию от A = > B, map функтора (здесь List), вы можете использовать эту функцию также для перехода от List[A] => List[B]. Это называется подъем.

Ответы на ваши вопросы

Что такое переменная "строка"?

Как упоминалось выше, line является входным параметром функции line => line.split(" ").size

Более явный (line: String) => line.split(" ").size

Пример: Если line является "hello world", функция возвращает 2.

"hello world" 
=> Array("hello", "world")  // split 
=> 2                        // size of Array

Как передается значение a, b?

reduce также ожидает функцию от (A, A) => A, где A - тип вашего RDD. Позволяет называть эту функцию op.

Что делает reduce. Пример:

List( 1, 2, 3, 4 ).reduce( (x,y) => x + y )
Step 1 : op( 1, 2 ) will be the first evaluation. 
  Start with 1, 2, that is 
    x is 1  and  y is 2
Step 2:  op( op( 1, 2 ), 3 ) - take the next element 3
  Take the next element 3: 
    x is op(1,2) = 3   and y = 3
Step 3:  op( op( op( 1, 2 ), 3 ), 4) 
  Take the next element 4: 
    x is op(op(1,2), 3 ) = op( 3,3 ) = 6    and y is 4

Результат здесь - сумма элементов списка, 10.

Примечание: обычно reduce вычисляет

op( op( ... op(x_1, x_2) ..., x_{n-1}), x_n)

Полный пример

Во-первых, текстовый файл является RDD [String], скажем

TextFile
 "hello Tyth"
 "cool example, eh?"
 "goodbye"

TextFile.map(line => line.split(" ").size)
 2
 3
 1
TextFile.map(line => line.split(" ").size).reduce((a, b) => if (a > b) a else b)
 3
   Steps here, recall `(a, b) => if (a > b) a else b)`
   - op( op(2, 3), 1) evaluates to op(3, 1), since op(2, 3) = 3 
   - op( 3, 1 ) = 3

Ответ 2

Map и reduce являются методами класса RDD, который имеет интерфейс, подобный коллекциям scala.

То, что вы передаете методам Map и reduce, на самом деле является анонимной функцией (с одним параметром на карте и с двумя параметрами в сокращении). textFile вызывает предоставленную функцию для каждого элемента (строка текста в этом контексте).

Возможно, сначала вы должны прочитать введение коллекции scala.

Подробнее о API класса RDD вы можете прочитать здесь: https://spark.apache.org/docs/1.2.1/api/scala/#org.apache.spark.rdd.RDD

Ответ 3

какая функция map есть, она принимает список аргументов и сопоставляет их с некоторой функцией. Подобно функции map в python, если вы знакомы.

Кроме того, файл похож на список строк. (не совсем, а то, как он повторяется)

Давайте рассмотрим, что это ваш файл.

val list_a: List[String] = List("first line", "second line", "last line")

Теперь посмотрим, как работает функция map.

Нам нужны вещи, list of values, которые у нас уже есть, и функции, которым мы хотим сопоставить эти значения. рассмотрим действительно простую функцию для понимания.

val myprint = (arg:String)=>println(arg)

эта функция просто принимает один аргумент String и выводит на консоль.

myprint("hello world")
hello world

Теперь, если мы сопоставим эту функцию с вашим списком, она напечатает все строки

list_a.map(myprint)

Теперь мы можем написать анонимную функцию, как указано ниже, что делает то же самое.

list_a.map(arg=>println(arg))

в вашем случае line - это первая строка файла. вы можете изменить имя аргумента по своему усмотрению. например, в приведенном выше примере, если я изменю arg на line, он будет работать без каких-либо проблем.

list_a.map(line=>println(line))