Как скопировать ключ предыдущей строки в ключевое поле следующей строки в RDD пары ключ-значение

Пример набора данных:

$, Claw         "OnCreativity" (2012)  [Himself]

$, Homo         Nykytaiteen museo (1986)  [Himself]  <25>
            Suuri illusioni (1985)  [Guests]  <22>

$, Steve        E.R. Sluts (2003) (V)  <12>

$hort, Too      2012 AVN Awards Show (2012) (TV)  [Himself - Musical Guest]
            2012 AVN Red Carpet Show (2012) (TV)  [Himself]
            5th Annual VH1 Hip Hop Honors (2008) (TV)  [Himself]
            American Pimp (1999)  [Too $hort]

Я создал RDD пары ключ-значение, используя следующий код:

To split data: val actorTuple = actor.map(l => l.split("\t"))
 To make KV pair: val actorKV = actorTuple.map(l => (l(0), l(l.length-1))).filter{case(x,y) => y != "" }

Вывод ключ-значение RDD на консоли:

Array(($, Claw,"OnCreativity" (2012)  [Himself]), ($, Homo,Nykytaiteen museo (1986)  [Himself]  <25>), ("",Suuri illusioni (1985)  [Guests]  <22>), ($, Steve,E.R. Sluts (2003) (V)  <12>).......

Но во многих строках это «» в качестве ключа, то есть пустое (см. Вывод RDD выше), из-за характера набора данных, поэтому я хочу иметь функцию, которая копирует действующее лицо предыдущей строки в эту строку, если она пустой. Как это можно сделать.


person Roshan Br    schedule 12.11.2014    source источник


Ответы (2)


Новое в Spark и Scala. Но, возможно, было бы проще изменить разбор строк и сначала создать пару RDD со значениями списка типов, например.

($, Homo, (Nykytaiteen museo (1986) [Сам] №25>, Suuri Illusioni (1985) [Гости] №22>))

Я не знаю ваших данных, но, возможно, если строка не начинается с "$", вы добавляете ее в список значений.

Затем, в зависимости от того, что вы хотите сделать, возможно, вы могли бы использовать flatMapValues(func) для пары RDD, описанной выше. Это применяет функцию, которая возвращает итератор для каждого значения пары RDD и для каждого возвращаемого элемента создает запись "ключ-значение" со старым ключом.

ДОБАВЛЕНО: В каком формате находятся ваши входные данные («Образец набора данных»)? Это текстовый файл или .tsv? Вероятно, вы хотите загрузить весь файл сразу. То есть используйте .wholeTextFiles() вместо .textFile() для загрузки ваших данных. Это связано с тем, что ваши записи хранятся более чем в одной строке файла.

ДОБАВЛЕНО Файл качать не буду, но мне кажется, что каждая интересующая вас запись начинается с "$". Spark может работать с любым из входных форматов Hadoop, поэтому проверьте их, чтобы узнать, есть ли тот, который будет работать с вашими образцами данных.

Если нет, вы можете написать свою собственную реализацию Hadoop InputFormat, которая разбирает файлы на записи, разделенные этим символом, вместо стандартного для TextFiles символа '\n'.

person xyzzy    schedule 12.11.2014
comment
Я также новичок в Spark и Scala. Не могли бы вы привести пример того же с точки зрения кода/команды, а $ является частью имени актера, которое меняется, поэтому я не могу использовать его в обычной логике. - person Roshan Br; 13.11.2014
comment
Описанная логика не является коммутативной. Элементы RDD разделены между машинами, что, если предыдущий элемент для пустого ключа находится на другой машине? Кроме того, я думаю, что структура данных RDD не упорядочена. Я подумал, что было бы проще иметь логику синтаксического анализа, которая анализирует ваш файл в паре RDD с ключом имени актера и значением в виде списка всех фильмов, в которых был этот актер. Любая логика, которую вы надеялись понять apply в API Spark RDD, я думаю, вы сможете применить его при анализе файла и создании базового RDD. - person xyzzy; 14.11.2014
comment
Я точно хочу иметь логику синтаксического анализа, которая анализирует файл в паре RDD, с ключом в качестве имени актера и значением в виде списка всех фильмов, в которых был этот актер, но когда вы анализируете набор данных (который можно загрузить из приведенной ниже ссылки), невозможно действительно извлечь список фильмов как значение и актера как ключ, просто проанализировав, потому что нам нужно разбить строки на поля, чтобы создать пару. Более того, это набор данных с разделителями табуляции, и если мы используем .wholeTextFiles(), то мы получим всего 1 строку в RDD. Я предлагаю пользовательскую функцию для копирования ключа из предыдущей строки, если она пуста. - person Roshan Br; 14.11.2014
comment
ftp.fu-berlin.de/pub/misc/ movies/database/actors.list.gz для загрузки набора данных, для этого гигантского текстового файла рекомендуется использовать текстовый редактор, такой как VIM. - person Roshan Br; 14.11.2014

Продолжая идею xyzzy, как насчет того, чтобы попробовать это после загрузки файла в виде строки:

val actorFileSplit = actorsFile.split("\n\n")
val actorData = sc.parallelize(actorsFileSplit)
val actorDataSplit = actorsData.map(x => x.split("\t+",2).toList).map(line => (line(0), line(1).split("\n\t+").toList))

Чтобы объяснить, что я делаю, я начинаю с разбиения строки каждый раз, когда мы находим разрыв строки. Последовательно я распараллеливаю это в sparkcontext для сопоставления функций. Затем я разделяю каждую запись на две части, которые разделяются первым появлением ряда вкладок (одна или несколько). Первая часть теперь должна быть актером, а вторая часть по-прежнему должна быть строкой с названиями фильмов. Вторая часть снова может быть разделена на каждую новую строку, за которой следует несколько вкладок. Это должно создать список со всеми названиями для каждого актера. Окончательный результат имеет вид:

actorDataSplit = [(String, [String])]

Удачи

person Remy Kabel    schedule 18.11.2014