Hadoop gebruikt het MapReduce-programmeermodel voor de gegevensverwerking van invoer en uitvoer voor de kaart en om functies te verminderen die worden weergegeven als sleutel-waardeparen. Ze zijn onderhevig aan parallelle uitvoering van datasets die zich in een breed scala aan machines in een gedistribueerde architectuur bevinden. Het programmeerparadigma is in wezen functioneel van aard in het combineren terwijl het de techniek van kaart en verkleinen gebruikt. Dit artikel introduceert het MapReduce-model, en in het bijzonder hoe gegevens in verschillende formaten, van eenvoudige tekst tot gestructureerde binaire objecten, worden gebruikt.
MapReduce-typen
In kaart brengen is de kerntechniek voor het verwerken van een lijst met gegevenselementen die in paren van sleutels en waarden komen. De kaartfunctie is van toepassing op individuele elementen die zijn gedefinieerd als sleutel-waardeparen van een lijst en produceert een nieuwe lijst. Het algemene idee van de kaart- en reductiefunctie van Hadoop kan als volgt worden geïllustreerd:
map: (K1, V1) -> list (K2, V2) reduce: (K2, list(V2)) -> list (K3, V3)
De ingangsparameters van het sleutel- en waardepaar, respectievelijk weergegeven door K1 en V1, verschillen van het type uitgangspaar:K2 en V2. De functie verkleinen accepteert hetzelfde formaat uitvoer door de kaart, maar het type uitvoer van de bewerking verkleinen is anders:K3 en V3. De Java API hiervoor is als volgt:
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; }
De OutputCollector is de algemene interface van het Map-Reduce-framework om het verzamelen van gegevensuitvoer door de Mapper te vergemakkelijken of de Verloopstuk . Deze outputs zijn niets anders dan een tussentijdse output van de job. Daarom moeten ze worden geparametriseerd met hun typen. De Reporter faciliteert de Map-Reduce-applicatie om voortgang te rapporteren en tellers en statusinformatie bij te werken. Als echter de combineerfunctie wordt gebruikt, heeft deze dezelfde vorm als de reduceerfunctie en wordt de uitvoer naar de reduceerfunctie gevoerd. Dit kan als volgt worden geïllustreerd:
map: (K1, V1) -> list (K2, V2) combine: (K2, list(V2)) -> list (K2, V2) reduce: (K2, list(V2)) -> list (K3, V3)
Merk op dat de functies combineren en verkleinen hetzelfde type gebruiken, behalve in de namen van variabelen waar K3 K2 is en V3 V2 is.
De partitiefunctie werkt op de tussenliggende sleutel-waardetypes. Het bestuurt de partitionering van de toetsen van de tussenliggende kaartuitgangen. De sleutel leidt de partitie af met behulp van een typische hash-functie. Het totale aantal partities is gelijk aan het aantal reduceertaken voor de job. De partitie wordt alleen bepaald door de sleutel die de waarde negeert.
public interface Partitioner<K2, V2> extends JobConfigurable { int getPartition(K2 key, V2 value, int numberOfPartition); }
Dit is in het kort de belangrijkste essentie van MapReduce-typen.
Invoerformaten
Hadoop moet verschillende formaten accepteren en verwerken, van tekstbestanden tot databases. Een stuk invoer, genaamd invoersplitsing , wordt verwerkt door een enkele kaart. Elke splitsing is verder onderverdeeld in logische records die aan de kaart worden gegeven om te verwerken in een sleutel-waardepaar. In de context van een database betekent de splitsing het lezen van een reeks tuples uit een SQL-tabel, zoals gedaan door de DBInputFormat en het produceren van LongWritables met recordnummers als sleutels en DBWritables als waarden. De Java API voor invoersplitsingen is als volgt:
public interface InputSplit extends Writable { long getLength() throws IOException; String[] getLocations() throws IOException; }
De InputSplit vertegenwoordigt de gegevens die moeten worden verwerkt door een Mapper . Het retourneert de lengte in bytes en heeft een verwijzing naar de invoergegevens. Het geeft een byte-georiënteerd beeld van de invoer en is de verantwoordelijkheid van de RecordReader van de baan om dit te verwerken en een recordgericht beeld te presenteren. In de meeste gevallen werken we niet met InputSplit rechtstreeks omdat ze zijn gemaakt door een InputFormat . Het is de verantwoordelijkheid van het InputFormat om de invoersplitsingen te maken en deze in records te verdelen.
public interface InputFormat<K, V> { InputSplit[] getSplits(JobConf job, int numSplits) throws IOException; RecordReader<K, V> getRecordReader(InputSplit split, JobConf job, throws IOException; }
De JobClient roept de getSplits() . op methode met het juiste aantal split-argumenten. Het gegeven aantal is een hint, aangezien het werkelijke aantal splitsingen kan verschillen van het gegeven aantal. Zodra de splitsing is berekend, wordt deze naar de jobtracker gestuurd. De jobtracker plant kaarttaken voor de tasktrackers met behulp van de opslaglocatie. De tasktracker geeft dan de splitsing door door getRecordReader() . aan te roepen methode op het InputFormat om RecordReader . te krijgen voor de splitsing.
Het FileInputFormat is de basisklasse voor de bestandsgegevensbron. Het heeft de verantwoordelijkheid om de bestanden te identificeren die moeten worden opgenomen als de taakinvoer en de definitie voor het genereren van de splitsing.
Hadoop omvat ook de verwerking van ongestructureerde gegevens die vaak in tekstformaat worden geleverd. Het TextInputFormat is het standaard InputFormat voor dergelijke gegevens.
Het SequenceInputFormat neemt binaire invoer op en slaat reeksen binaire sleutel-waardeparen op.
Op dezelfde manier biedt DBInputFormat de mogelijkheid om gegevens uit een relationele database te lezen met behulp van JDBC.
Uitvoerformaten
De klassen van het uitvoerformaat zijn vergelijkbaar met hun corresponderende klassen van het invoerformaat en werken in omgekeerde richting.
Bijvoorbeeld de TextOutputFormat is het standaard uitvoerformaat dat records schrijft als platte tekstbestanden, terwijl sleutelwaarden van elk type kunnen zijn, en ze in een tekenreeks transformeert door de toString() aan te roepen methode. Het sleutelwaarde-teken wordt gescheiden door het tab-teken, hoewel dit kan worden aangepast door de scheidingstekeneigenschap van het tekstuitvoerformaat te manipuleren.
Voor binaire uitvoer is er SequenceFileOutputFormat om een reeks binaire uitvoer naar een bestand te schrijven. Binaire outputs zijn met name handig als de output input wordt voor een volgende MapReduce-taak.
De uitvoerformaten voor relationele databases en naar HBase worden afgehandeld door DBOutputFormat . Het stuurt de verminderde uitvoer naar een SQL-tabel. Bijvoorbeeld het TableOutputFormat . van de HBase stelt het MapReduce-programma in staat om te werken met de gegevens die zijn opgeslagen in de HBase-tabel en gebruikt deze om uitvoer naar de HBase-tabel te schrijven.
Conclusie
Dit is in het kort de crux van MapReduce-typen en -formaten. Raadpleeg de lijst in de onderstaande referentie voor meer informatie over hen. Er zijn veel ingewikkelde details over de functies van de Java-API's die pas duidelijker worden als men zich in programmeren verdiept. Raadpleeg de Apache Hadoop Java API-documenten voor meer details en begin met het coderen van enkele praktijken.
Referenties
- Tom White, Hadoop De definitieve gids , O'Reilly
- Apache Hadoop Java API-documenten