В этом присвоении вы реализуете кэширование результатов UDF (определенная пользовательская функция) в Apache Spark, которая является основой для распределенных вычислений в форме MapReduce. Этот проект проиллюстрирует ключевые концепции в рамках данных и оценке запросов, и вы получите некоторый практический опыт, изменяя Spark, которая широко используется в этой области. Кроме того, вы получите экспозицию Scala, языка на основе JVM, который набирает популярность за его чистый функциональный стиль.
Дата назначения назначена на веб -сайте класса.
Вы можете завершить это парами , если вы решите. Наконец, в этом каталоге много кода. Пожалуйста, посмотрите здесь, чтобы найти каталог, где находится код.
Spark-это распределенная вычислительная система с открытым исходным кодом, записанная в Scala. Проект был начат доктором философии. Студенты из Amplab и являются неотъемлемой частью стека аналитики данных в Беркли (BDAS-недостаточно выражены как «плохой заседание»).
Как и Hadoop MapReduce, Spark предназначена для выполнения функций в больших коллекциях данных, поддерживая упрощенный набор операций по обработке данных высокого уровня, сродни итераторам, о которых мы изучали в классе. Одним из наиболее распространенных применений таких систем является реализация обработки параллельных запросов на языках высокого уровня, таких как SQL. Фактически, многие недавние исследования и разработки в области Spark пошли на поддержку масштабируемой и интерактивной абстракции реляционной базы данных.
Мы будем использовать, изменять и изучать аспекты Spark в этом классе, чтобы понять ключевые концепции современных систем данных. Что еще более важно, вы увидите, что идеи, которые мы освещаем в классе - некоторые из которых десятилетия - все еще очень актуальны сегодня. В частности, мы будем добавлять функции для Spark SQL.
Одним из ключевых ограничений Spark SQL является то, что в настоящее время он является системой только для основной памяти. В рамках этого класса мы расширим его, чтобы включить и некоторые алгоритмы вне контроля.
Scala-это статический язык, который поддерживает множество различных парадигм программирования. Его гибкость, мощность и портативность стали особенно полезными в исследованиях распределенных систем.
Scala напоминает Java, но она обладает гораздо более широким набором синтаксических функций, чтобы облегчить несколько парадигм. Знание Java поможет вам понять какой -то код Scala, но не очень его, и не зная, что Scala не позволит вам полностью воспользоваться ее выразительной силой. Поскольку вы должны написать код в Scala, мы настоятельно рекомендуем вам получить хотя бы проходящее знакомство с языком.
INTELLIJ IDEA, как правило, является наиболее часто используемой IDE для развития в Spark. Intellij - это Java IDE, в котором есть плагин Scala (и Vim!). Есть также другие параметры, такие как Scala-Ide.
Вы можете найти следующие уроки полезными:
Пользовательские функции позволяют разработчикам определять и эксплуатировать пользовательские операции в рамках выражений. Представьте, например, у вас есть каталог продукта, который включает в себя фотографии упаковки продукта. Вы можете зарегистрировать пользовательную функцию extract_text
, которая вызывает алгоритм OCR, и возвращает текст в изображении, чтобы вы могли получить запросную информацию из фотографий. В SQL вы можете представить себе такой запрос:
SELECT P.name, P.manufacturer, P.price, extract_text(P.image),
FROM Products P;
Возможность регистрации UDFS очень мощная - она по сути превращает вашу структуру обработки данных в общую распределенную вычислительную структуру. Но UDF часто могут представлять узкие места производительности, особенно когда мы запускаем их по миллионам элементов данных.
Если входной столбец (ы) в UDF содержит много дублирующих значений, он может быть полезен для повышения производительности, обеспечивая, чтобы UDF назывался только один раз на различное входное значение , а не один раз на строку . (Например, в примере наших продуктов выше, все различные конфигурации конкретного ПК могут иметь одинаковое изображение.) В этом задании мы будем реализовать эту оптимизацию. Мы возьмем его поэтапно-сначала заставим его работать для данных, которые подходят в память, а затем для больших наборов, которые требуют отключения подхода. Мы будем использовать внешнее хэширование в качестве метода для «Rendezvous» всех строк с одинаковыми входными значениями для UDF.
Если вы заинтересованы в этой теме, следующая статья будет интересным чтением (включая дополнительные оптимизации, помимо того, что у нас есть время в этой домашней работе):
Весь код, который вы будете прикоснуться, будет в трех файлах - CS143Utils.scala
, basicOperators.scala
и DiskHashedRelation.scala
. Однако вам может потребоваться проконсультироваться с другими файлами в Spark или общих API Scala, чтобы полностью выполнить задание. Пожалуйста, убедитесь, что вы просмотрите весь предоставленный код в трех файлах, упомянутых выше, прежде чем начать писать свой собственный код. Есть много полезных функций в CS143Utils.scala
, а также в DiskHashedRelation.scala
, который сэкономит вам много времени и проклят - воспользуйтесь ими!
В целом, мы определили большинство (если не все) методов, которые вам понадобятся. Как и прежде, в этом проекте вам нужно заполнить скелет. Размер кода, который вы напишете, не очень высок - общее решение персонала составляет меньше 100 строк кода (не включая тесты). Тем не менее, объединение правильных компонентов экономичным образом (т.е. не чтение всего отношения в память одновременно) потребует некоторого мысли и тщательного планирования.
Существуют некоторые потенциально запутанные различия между терминологией, которую мы используем в классе, и терминологией, используемой в базе кода SparksQL:
Концепция «Итератор», которую мы изучили в лекции, называется «узел» в коде SparksQL - в коде есть определения для UnaryNode и BinaryNode. План запросов называется Sparkplan, и на самом деле UnaryNode и BinaryNode Extend SparkPlan (в конце концов, один итератор - это небольшой план запросов!) Вы можете найти файл SparkPlan.scala
в источнике SparksQl, чтобы увидеть API для них узлы.
В некоторых комментариях в Sparksql они также используют термин «оператор», чтобы означать «узел». File basicOperators.scala
определяет ряд конкретных узлов (например, сортировка, различные и т. Д.).
Не путайте Iterator
интерфейса Scala с концепцией итератора, которую мы рассмотрели в лекции. Iterator
, который вы будете использовать в этом проекте, - это функция языка Scala, которую вы будете использовать для реализации своих узлов SparksQL. Iterator
обеспечивает интерфейс для коллекций Scala, который обеспечивает соблюдение конкретного API: next
функции и функции hasNext
.
git
и github git
- это система управления версиями , помогающая вам отслеживать различные версии вашего кода, синхронизировать их на разных машинах и сотрудничать с другими. Github - это сайт, который поддерживает эту систему, размещая ее в качестве услуги.
Если вы не знаете много о git
, мы настоятельно рекомендуем вам ознакомиться с этой системой; Вы будете проводить с этим много времени! Есть много руководств по использованию git
Online - вот отличный для чтения.
Сначала вы должны настроить удаленный частный репозиторий (например, Harke-Homework). GitHub дает частное хранилище студентам (но это может занять некоторое время). Если у вас нет частного репозитория, подумайте дважды о проверке его в общественном репозитории, так как он будет доступен для других.
$ cd ~
Клонировать свой личный репозиторий. Это должно быть пусто.
$ git clone "https://github.com/xx/yy.git"
Введите клонированный репозиторий, отслеживайте репозиторий курса и клонируйте его.
$ cd yy/
$ git remote add course "https://github.com/ariyam/cs143_spark_hw.git"
$ git pull course master
Примечание. Пожалуйста, не будьте перегружены количеством кода, который здесь есть. Spark - это большой проект с множеством функций. Код, к которому мы свяжемся, будет содержаться в одном конкретном каталоге: SQL/Core/SRC/MAIN/SCALA/ORG/APACHE/SPARK/SQL/выполнение/. Все тесты будут содержаться в SQL/Core/SRC/TEST/SCALA/ORG/APACHE/SPARK/SQL/выполнение/
Подтолкните клон к вашему личному репозиторию.
$ git push origin master
Каждый раз, когда вы добавляете какой -то код, вы можете совершить изменения в удаленном репозитории.
$ git commit -m 'update to homework'
$ git push origin master
Может потребоваться получить обновления для нашего задания (даже если мы стараемся выпустить их как можно «идеально» в первый раз). Предполагая, что вы правильно настроили отслеживание, вы можете просто запустить следующую команду, чтобы получить обновления назначения:
$ git pull course master
Следующая команда Unix пригодится, когда вам нужно найти местоположение файла. Пример- найти местоположение файла с именем 'DiskhashedRelation.scala' в моем текущем репозитории.
$ find ./ -name 'DiskHashedRelation.scala'
После того, как вы получите Code, cd
в {repo root}
и запустите make compile
. В первый раз, когда вы запустите эту команду, она займет некоторое время - sbt
загрузит все зависимости и компилируется весь код в Spark (есть немного кода). Как только начальные команды сборки завершится, вы можете начать свой проект! (Будущие сборки не должны занять так долго - sbt
достаточно умна, чтобы перекомпилировать измененные файлы, если вы не запускаете make clean
, что удалит все скомпилированные файлы класса.)
Мы предоставили вам код скелета для DiskHashedRelation.scala
. Этот файл имеет 4 важных вещах:
trait DiskHashedRelation
определяет границу интерфейсаDiskedHashedRelation
class GeneralDiskHashedRelation
class DiskPartition
представляет собой единый раздел на дискеobject DiskHashedRelation
может рассматриваться как объектная фабрика, которая конструирует GeneralDiskHashedRelation
SDiskPartition
и GeneralDiskHashedRelation
Во -первых, вам необходимо будет реализовать методы insert
, closeInput
и getData
в DiskPartition
для этой части. Для первых двух Docstrings должен предоставить исчерпывающее описание того, что вы должны реализовать. Предостережение с getData
заключается в том, что вы не можете прочитать весь раздел в память один раз. Причина, по которой мы обеспечиваем это ограничение, заключается в том, что нет хорошего способа обеспечения освобождения памяти в JVM, и при преобразовании данных в разные формы будут много копий. Таким образом, наличие нескольких копий целого перегородка приведет к тому, что вещи будут проливаться на диск и вызвать нас всех. Вместо этого вы должны транслировать один блок в память за раз.
На этом этапе вы должны пройти тесты в DiskPartitionSuite.scala
.
object DiskHashedRelation
Ваша задача в этой части будет заключаться в реализации фазы 1 внешнего хеширования-использование крупнозернистой хеш-функции для передачи ввода в несколько разделам отношения на диске. Для наших целей метод hashCode
, который имеет каждый объект, является достаточным для получения значения хэша, и принятие модуля по количеству разделов является приемлемой хэш -функцией.
На этом этапе вы должны пройти все тесты в DiskHashedRelationSuite.scala
.
В этом разделе мы будем иметь дело с case class CacheProject
в basicOperators.scala
. Вы можете заметить, что в этом классе есть только 4 строки кода и, что более важно, нет // IMPLEMENT ME
. Вам на самом деле не нужно писать здесь код. Однако, если вы отследите вызов функции в строке 66, вы обнаружите, что есть две части этого стека, которую вы должны реализовать, чтобы иметь функциональную реализацию UDF в памяти.
CS143Utils
Для этой задачи вам необходимо будет реализовать getUdfFromExpressions
и применить методы Iterator
в CachingIteratorGenerator#apply
. Пожалуйста, прочитайте Docstrings - особенно для apply
- тщательно перед началом работы.
После реализации этих методов вы должны пройти тесты в CS143UtilsSuite.scala
.
Подсказка: Тщательно подумайте о том, почему эти методы могут быть частью утильников
Теперь наступает момент истины! Мы внедрили хэш-разделение на основе дисков, и мы внедрили кэширование UDF в памяти-что иногда называют памятью. Мемуализация является очень мощным инструментом во многих контекстах, но здесь, в базах данных, мы имеем дело с большими объемами данных, чем может обработать память. Если у нас есть больше уникальных значений, чем можно вписать в кэш в памяти, наша производительность быстро разлагается. Таким образом, мы возвращаемся к проверенной временем традиции баз данных о разделении и привлечении. Если наши данные не вписываются в память, то мы можем разместить их на диск один раз, прочитать один раздел за раз (подумайте о том, почему это работает (подсказка: Rendezvous!) И выполните кэширование UDF, оценивая одно разделение за раз Полем
PartitionProject
Эта последняя задача требует, чтобы вы заполняли реализацию PartitionProject
. Весь код, который вам нужно будет написать, находится в методе generateIterator
. Тщательно подумайте о том, как вам нужно организовать свою реализацию. Вы не должны буферизировать все данные в памяти или что -то подобное.
На этом этапе вы должны пройти все заданные тесты.
Здесь нет кода, но для вашего собственного назидания потратьте некоторое время на размышления о следующем вопросе:
Одним из основных точек продажи Spark является то, что это «в памяти». Они означают следующее: когда вы связываете ряд заданий Hadoop (или любых других работ MapReduce) вместе, Hadoop напишет результаты каждого этапа на диск и снова прочитайте их, что очень дорого; Spark, с другой стороны, поддерживает свои данные в памяти. Однако, если наше предположение состоит в том, что, если наши данные не вписываются в память, то почему Spark SQL уже не поставляется с реализацией этих операторов на основе дисков? В этом отношении, почему Spark отличается от «традиционных» параллельных реляционных баз данных, о которых мы узнаем в классе? На этот вопрос нет правильного ответа!
Мы предоставили вам некоторые образцы тестов в DiskPartitionSuite.scala
, DiskHasedRelationSuite.scala
, CS143UtilsSuite.scala
и ProjectSuite.scala
. Эти тесты могут направить вас по мере завершения этого проекта. Тем не менее, имейте в виду, что они не являются всеобъемлющими, и вам рекомендуется написать свои собственные тесты, чтобы поймать ошибки. Надеемся, что вы можете использовать эти тесты в качестве моделей для создания собственных тестов.
Чтобы запустить наши тесты, мы предоставили простую макияж. Чтобы запустить тесты для задачи 1, запустите make t1
. Соответственно для задачи, запустите, make t2
и одинаково для всех других тестов. make all
запуск всех тестов.
Ссылка на отправку будет создана в CCLE, где вы можете отправить свой код до даты срока.
Большое спасибо Matteo Interlandi.
Удачи!