Hadoop използва модела за програмиране MapReduce за обработка на данни на вход и изход за картата и за намаляване на функциите, представени като двойки ключ-стойност. Те са обект на паралелно изпълнение на набори от данни, разположени в широк спектър от машини в разпределена архитектура. Парадигмата на програмиране е по същество функционална по своята същност при комбиниране, докато се използва техниката на картиране и намаляване. Тази статия представя модела MapReduce и по-специално как се използват данните в различни формати, от обикновен текст до структурирани двоични обекти.
Типове MapReduce
Картографиране е основната техника за обработка на списък с елементи от данни, които идват в двойки ключове и стойности. Функцията map се прилага за отделни елементи, дефинирани като двойки ключ-стойност на списък и създава нов списък. Общата идея за функцията за картиране и намаляване на Hadoop може да бъде илюстрирана по следния начин:
map: (K1, V1) -> list (K2, V2) reduce: (K2, list(V2)) -> list (K3, V3)
Входните параметри на двойката ключ и стойност, представени съответно от K1 и V1, са различни от типа на изходната двойка:K2 и V2. Функцията за намаляване приема същия формат, изведен от картата, но типът на извеждане отново на операцията за намаляване е различен:K3 и V3. Java API за това е както следва:
public interface Mapper<K1, V1, K2, V2> extends JobConfigurable, Closeable { void map(K1 key, V1 value, OutputCollector<K2, V2> output, Reporter reporter) throws IOException; } public interface Reducer<K2, V2, K3, V3> extends JobConfigurable, Closeable { void reduce(K2 key, Iterator<V2> values, OutputCollector<K3, V3> output, Reporter reporter)throws IOException; }
OutputCollector е обобщения интерфейс на рамката Map-Reduce за улесняване на събирането на изходни данни от Mapper или Редуктора . Тези резултати не са нищо друго освен междинен резултат от работата. Следователно те трябва да бъдат параметризирани с техните типове. Репортер улеснява приложението Map-Reduce за отчитане на напредъка и актуализиране на броячите и информация за състоянието. Ако обаче се използва функцията за комбиниране, тя има същата форма като функцията за намаляване и изходът се подава към функцията за намаляване. Това може да се илюстрира по следния начин:
map: (K1, V1) -> list (K2, V2) combine: (K2, list(V2)) -> list (K2, V2) reduce: (K2, list(V2)) -> list (K3, V3)
Обърнете внимание, че функциите за комбиниране и намаляване използват един и същи тип, освен в имената на променливите, където K3 е K2, а V3 е V2.
Функцията за разделяне работи с междинните типове ключ-стойност. Той контролира разделянето на ключовете на изходите на междинната карта. Ключът извлича дяла, използвайки типична хеш функция. Общият брой дялове е същият като броя на задачите за намаляване на заданието. Разделът се определя само от ключа, игнориращ стойността.
public interface Partitioner<K2, V2> extends JobConfigurable { int getPartition(K2 key, V2 value, int numberOfPartition); }
Това е ключовата същност на типовете MapReduce накратко.
Входни формати
Hadoop трябва да приема и обработва различни формати, от текстови файлове до бази данни. Част от входа, наречена входно разделяне , се обработва от една карта. Всяко разделяне допълнително се разделя на логически записи, дадени на картата за обработка в двойка ключ-стойност. В контекста на базата данни, разделянето означава четене на набор от кортежи от SQL таблица, както е направено от DBInputFormat и създаване на LongWritables съдържащи номера на записи като ключове и DBWritables като ценности. Java API за разделяне на входа е както следва:
public interface InputSplit extends Writable { long getLength() throws IOException; String[] getLocations() throws IOException; }
InputSplit представлява данните, които трябва да бъдат обработени от Mapper . Той връща дължината в байтове и има препратка към входните данни. Той представя байт-ориентиран изглед на входа и е отговорност на RecordReader на задачата да обработи това и да представи изглед, ориентиран към запис. В повечето случаи не се занимаваме с InputSplit директно, защото са създадени от InputFormat . Това е отговорност на InputFormat за да създадете входните разделяния и да ги разделите на записи.
public interface InputFormat<K, V> { InputSplit[] getSplits(JobConf job, int numSplits) throws IOException; RecordReader<K, V> getRecordReader(InputSplit split, JobConf job, throws IOException; }
JobClient извиква getSplits() метод с подходящ брой разделени аргументи. Посоченото число е намек, тъй като действителният брой на разделянето може да е различен от даденото число. След като разделението бъде изчислено, то се изпраща на програмата за проследяване на заданията. Инструментът за проследяване на задания насрочва картографски задачи за тасктракерите, използвайки местоположение за съхранение. След това инструментът за проследяване на задачите предава разделянето, като извиква getRecordReader() метод на InputFormat за да получите RecordReader за разделянето.
FileInputFormat е основният клас за файловия източник на данни. Той носи отговорността да идентифицира файловете, които трябва да бъдат включени като вход на заданието и дефиницията за генериране на разделянето.
Hadoop също така включва обработка на неструктурирани данни, които често идват в текстов формат. TextInputFormat е InputFormat по подразбиране за такива данни.
SequenceInputFormat приема двоични входове и съхранява поредици от двоични двойки ключ-стойност.
По подобен начин DBInputFormat предоставя възможност за четене на данни от релационна база данни с помощта на JDBC.
Изходни формати
Класовете на изходния формат са подобни на съответните им класове за входен формат и работят в обратна посока.
Например TextOutputFormat е изходният формат по подразбиране, който записва записи като обикновени текстови файлове, докато ключ-стойностите са от всякакъв тип и ги трансформира в низ чрез извикване на toString() метод. Знакът ключ-стойност се разделя от табулатор, въпреки че това може да бъде персонализирано чрез манипулиране на свойството разделител на изходния текстов формат.
За двоичен изход има SequenceFileOutputFormat за да напишете последователност от двоичен изход във файл. Двоичните изходи са особено полезни, ако изходът стане вход за следващо задание на MapReduce.
Изходните формати за релационни бази данни и към HBase се обработват от DBOutputFormat . Той изпраща намаления изход към SQL таблица. Например TableOutputFormat на HBase позволява на програмата MapReduce да работи върху данните, съхранявани в таблицата HBase, и я използва за записване на изходни данни в таблицата HBase.
Заключение
Това накратко е същността на типовете и форматите MapReduce. Вижте списъка в препратката по-долу, за да получите повече подробности за тях. Има много сложни подробности за функциите на Java API, които стават по-ясни само когато се потопите в програмирането. Обърнете се към документите за API на Apache Hadoop Java за повече подробности и започнете да кодирате някои практики.
Препратки
- Том Уайт, Окончателното ръководство на Hadoop , О’Райли
- Документи за Java API на Apache Hadoop