Hive-partities en buckets met voorbeeld

โšก Slimme samenvatting

Partities en buckets zijn de twee manieren waarop Apache Hive tabelgegevens op schijf verdeelt: een partitie creรซert รฉรฉn map per sleutelwaarde, terwijl een bucket rijen hasht in een vast aantal bestanden.

  • ๐Ÿ—‚๏ธ Een partitie is een map: Elke unieke waarde van de partitiesleutel krijgt een eigen subdirectory onder de tabelmap in HDFS.
  • โœ‚๏ธ Partitie-snoeiing: Een query die filtert op de partitiesleutel leest alleen de overeenkomende mappen in plaats van de hele tabel te scannen.
  • โš™๏ธ Dynamische modus vereist: Om meerdere partities te laden met een SELECT-query, moet hive.exec.dynamic.partition.mode ingesteld zijn op nonstrict.
  • ๐Ÿงฎ Een bucket is een bestand: CLUSTERED BY berekent een hashwaarde voor de gekozen kolom en schrijft elke rij naar een van een vast aantal bestanden.
  • ๐Ÿ” Steekproeven en koppelingen: Gebuckete tabellen ondersteunen efficiรซnte TABLESAMPLE-leesbewerkingen en bucket-joins aan de mapzijde, iets wat gewone tabellen niet kunnen.
  • ๐Ÿ“ Kies op basis van het aantal personen: Partitioneer op kolommen met een lage kardinaliteit, zoals staat of datum, en groepeer kolommen met een hoge kardinaliteit, zoals gebruikers-ID's.

Hive-partities en -buckets uitgelegd aan de hand van een uitgewerkt voorbeeld.

Tabellen, partities en buckets vormen de basis van Hive-datamodellering. Een tabel definieert het schema, een partitie verdeelt die tabel in mappen op de schijf en een bucket verdeelt de gegevens binnen een map in een vast aantal bestanden.

Wat zijn partities?

Hive-partities is een manier om tabellen in partities te organiseren door ze op te delen in verschillende delen op basis van partitiesleutels. Fysiek gezien is elke partitie een aparte subdirectory onder de tabelmap in HDFS, waardoor Hive gegevens kan overslaan die het niet nodig heeft.

Partitionering is nuttig wanneer een tabel een of meer partitiesleutels heeft. Partitiesleutels zijn essentiรซle elementen voor het bepalen hoe de gegevens in de tabel worden opgeslagen. Een partitiesleutel wordt niet in de gegevensbestanden zelf opgeslagen; de waarde ervan is gecodeerd in de mapnaam. Een query die filtert op die sleutel kan daardoor hele mappen negeren voordat er ook maar รฉรฉn rij wordt gelezen. Dit wordt partitiepruning genoemd.

Bijvoorbeeld: -

"De klant beschikt over e-commercegegevens van activiteiten in India, waarbij de activiteiten per staat (38 staten) als รฉรฉn geheel worden weergegeven. Als we de kolom 'staat' als partitiesleutel gebruiken en partities toepassen op deze Indiase gegevens, krijgen we 38 partities, gelijk aan het aantal staten (38) in India. Op deze manier kunnen de gegevens van elke staat afzonderlijk in de partitietabellen worden weergegeven."

Sample Code Fragment voor partities

De zes onderstaande instructies worden in de Hive-shell in volgorde uitgevoerd. Elke instructie is een aparte stap en de volgende schermafbeeldingen tonen dezelfde reeks die wordt uitgevoerd op een live cluster.

  1. Aanmaken van tabel allstates
    create table allstates(state string, District string,Enrolments string)
    
    row format delimited
    
    fields terminated by ',';
    
  2. Gegevens laden in de aangemaakte tabel allstates
    Load data local inpath '/home/hduser/Desktop/AllStates.csv' into table allstates;
  3. Aanmaken van partitietabel
    create table state_part(District string,Enrolments string) PARTITIONED BY(state string);
  4. Voor partitie moeten we deze eigenschap instellen
    set hive.exec.dynamic.partition.mode=nonstrict
  5. Gegevens laden in partitietabel
    INSERT OVERWRITE TABLE state_part PARTITION(state)
    SELECT district,enrolments,state from  allstates;
  6. Feitelijke verwerking en vorming van partitietabellen op basis van de status als partitiesleutel

Er zullen 38 partitie-uitgangen in de HDFS-opslag zijn, waarbij de bestandsnaam de statusnaam is. We zullen dit in deze stap controleren.

De volgende schermafbeeldingen tonen de uitvoering van de bovengenoemde code.

In het eerste scherm wordt stap 1 uitgevoerd op het volgende niveau: bijenkorf> prompt en creรซert de alle staten Een tabel met drie kolommen en een komma als veldscheidingsteken.

Hive shell maakt de tabel 'allstates' aan met drie gescheiden kolommen.

Het volgende scherm toont stap 2 en 3: het bestand AllStates.csv wordt geladen in alle statenen de gepartitioneerde tabel staat_deel wordt aangemaakt met de status gedeclareerd als de partitiesleutel.

Het bestand AllStates.csv wordt in de map allstates geladen en de gepartitioneerde tabel state_part wordt aangemaakt.

Stappen 4 en 5 volgen. De dynamische partitiemodus wordt ingesteld op 'niet-strikt' en de INSERT OVERWRITE-instructie start een MapReduce-taak waarvan de logregels laten zien dat er voor elke statuswaarde รฉรฉn partitie wordt geladen.

MapReduce-taakuitvoer laadt รฉรฉn Hive-partitie per statuswaarde.

Het weergeven van de warehouse-directory in HDFS bevestigt het resultaat van stap 6: de shell meldt 38 items, waarvan รฉรฉn staat_deel/staat= directory per staat.

HDFS-lijst met 38 state_part-partitiemappen in het Hive-warehouse.

Vanuit de bovenstaande code doen we het volgende

  1. Het aanmaken van de tabel allstates met 3 kolomnamen: staat, district en inschrijvingen.
  2. Gegevens laden in tabel allstates
  3. Creรซren van partitietabel met status als partitiesleutel
  4. In deze stap wordt de partitiemodus ingesteld op 'niet-strikt' (deze modus activeert de dynamische partitiemodus).
  5. Gegevens laden in de partitietabel state_part
  6. Feitelijke verwerking en vorming van partitietabellen op basis van de status als partitiesleutel
  7. Er zullen 38 partitie-uitgangen in de HDFS-opslag zijn, waarbij de bestandsnaam de statusnaam is. In deze stap bekijken we de 38 partitie-uitgangen in HDFS.

Statische versus dynamische partitionering in Hive

Het bovenstaande voorbeeld maakt gebruik van dynamische partitionering, maar Hive ondersteunt twee laadstijlen en het verschil daartussen bepaalt hoeveel typing โ€“ en hoeveel risico โ€“ elke lading met zich meebrengt.

Statische partitionering De partitiewaarde wordt in de instructie zelf vermeld, dus de waarde moet bekend zijn voordat de laadbewerking wordt uitgevoerd en รฉรฉn instructie vult precies รฉรฉn partitie. Dynamische partitie Hierdoor kan Hive de partitiewaarde uit de laatste kolom van de SELECT-lijst lezen en de mappen tijdens de uitvoering aanmaken. Daarom is er in dit voorbeeld slechts รฉรฉn INSERT-instructie nodig om 38 mappen te genereren.

Aspect Statische partitionering Dynamische partitie
Partitiewaarde Handmatig verstrekt in de PARTITION-clausule Lees tijdens de uitvoering uit de SELECT-kolom
Partities per verklaring One Veel
Configuratie Werkt in de standaard strikte modus. Vereist dat hive.exec.dynamic.partition.mode is ingesteld op nonstrict.
Laad snelheid Sneller, omdat er geen waardescan nodig is. Langzamer, omdat de taak rijen groepeert op basis van de sleutel.
Het meest geschikt voor: Kleine, bekende sets, zoals een dagelijkse lading. Grote of onbekende sleutelsets, zoals 38 staten.

Dynamische loads hebben ook een limiet. Hive beperkt het aantal partities dat รฉรฉn taak mag aanmaken โ€“ standaard 100 per mapper of reducer en 1000 voor de hele statement โ€“ โ€‹โ€‹en de taak mislukt zodra een van deze limieten wordt overschreden. Daarom vereist een sleutel met een zeer hoge cardinaliteit een verhoging van deze limieten of een ander ontwerp.

Wat zijn emmers?

Buckets in Hive worden gebruikt om tabelgegevens in meerdere bestanden of mappen te verdelen. Ze zorgen voor efficiรซnte query's en, in tegenstelling tot een partitie, is het aantal buckets vastgelegd bij het aanmaken van de tabel, waardoor het nooit meegroeit met de hoeveelheid gegevens.

  • De gegevens in die partities kunnen verder worden onderverdeeld in buckets.
  • De deling wordt uitgevoerd op basis van de hash van specifieke kolommen die we in de tabel hebben geselecteerd.
  • Buckets gebruiken een of ander hash-algoritme aan de achterkant om elk record te lezen en in de juiste bucket te plaatsen.
  • In welke emmer een rij terechtkomt, wordt bepaald door hash_functie(bucketing_kolom) modulo aantal_buckets, zodat gelijke waarden altijd in hetzelfde bestand terechtkomen
  • In Hive 0.x en 1.x moest bucketing ingeschakeld worden met set hive.enforce.bucketing=true; vรณรณr de invoeging

Die laatste instelling behoort tot het verleden op een huidig โ€‹โ€‹cluster: de Apache Hive-handleiding Merk op dat dit vanaf Hive 2.x niet meer nodig is, omdat de engine het aantal reducers en de kolom 'cluster-by' nu automatisch uit de tabeldefinitie haalt.

Stap 1) Maak een bucket zoals hieronder weergegeven.

Het onderstaande scherm toont de CREATE TABLE-instructie voor samplebucket, waarbij de CLUSTERED BY-clausule onderaan het aantal buckets vastlegt.

Hive CREATE TABLE-instructie om samplebucket in vier buckets te clusteren

Uit de bovenstaande schermafdruk

  • We maken een samplebucket aan met kolomnamen zoals first_name, job_id, department, salary en country.
  • We maken hier 4 emmers.
  • Zodra de gegevens geladen zijn, worden ze automatisch in 4 buckets geplaatst.
  • De kolom 'land' is de clusterkolom, dus elke rij voor een bepaald land wordt naar hetzelfde bucketbestand geschreven.

Stap 2) Gegevens laden in tabel samplebucket

Ervan uitgaande dat de tabel "employees" al is aangemaakt in het Hive-systeem, zullen we in deze stap de gegevens uit de tabel "employees" in de tabel "samplebucket" laden.

Voordat we de werknemersgegevens in buckets gaan indelen, moeten we ervoor zorgen dat de buckets kolomnamen bevatten zoals first_name, job_id, department, salary en country.

Hier laden we gegevens uit de tabel 'employees' in de tabel 'samplebucket'. Het onderstaande scherm toont de INSERT OVERWRITE-instructie die de kopie uitvoert.

INSERT OVERWRITE-instructie die rijen met werknemersgegevens kopieert naar de tabel samplebucket.

Stap 3) De 4 emmers die in stap 1 zijn gemaakt, worden weergegeven.

Als je de tabeldirectory in HDFS opvraagt, zie je het fysieke resultaat: vier genummerde gegevensbestanden in plaats van รฉรฉn.

HDFS-lijst van de vier bucketbestanden die zijn aangemaakt in de map samplebucket.

Uit de bovenstaande schermafbeelding kunnen we zien dat de gegevens uit de tabel met werknemers worden overgezet naar de 4 buckets die in stap 1 zijn aangemaakt.

Hive-partitionering versus bucketing: belangrijkste verschillen

Beide functies verdelen een tabel in kleinere stukken, maar ze doen dit op verschillende niveaus van het bestandssysteem en ze bieden oplossingen voor verschillende problemen. De onderstaande tabel zet ze naast elkaar.

Punt van vergelijking Partitioning Emmer
Eenheid gecreรซerd Een map per sleutelwaarde Een bestand per hash-bucket
Verklaard met VERDEELD DOOR GEGROEPEERD DOOR โ€ฆ IN n EMMER
Aantal stukken Groeit met het aantal verschillende waarden. Vastgelegd tijdens het aanmaken van de tabel.
Kolom opgeslagen in gegevensbestanden Nee, de waarde bevindt zich in de mapnaam. Ja, de kolom blijft een normale kolom.
Beste kolomtype Lage cardinaliteit, zoals staat, jaar of land Hoge kardinaliteit, zoals user_id of transaction_id
Grootste voordeel Partitieopschoning slaat onnodige mappen over. Gelijkmatige bestandsgroottes, goedkope sampling en koppelingen aan de kaartzijde

De twee zijn geen concurrenten. Een gangbare productielayout verdeelt een feitentabel op datum en groepeert vervolgens elke dag op basis van de koppelingssleutel, zodat een query de gegevens filtert tot รฉรฉn map en vervolgens de groepen daarbinnen samenvoegt.

Wanneer moet je partitionering, bucketing of beide gebruiken?

De keuze tussen beide begint met de cardinaliteit van de kolom en de structuur van de query's die de tabel zullen lezen.

  • Tussenschot wanneer query's bijna altijd filteren op dezelfde kolom met een lage kardinaliteit, en wanneer het aantal unieke waarden in de honderden blijft in plaats van in de miljoenen.
  • Emmer wanneer de nuttige kolom te veel verschillende waarden bevat om een โ€‹โ€‹directory te zijn, of wanneer de tabel herhaaldelijk wordt samengevoegd of bemonsterd op die kolom.
  • Gebruik allebei Voor grote feitentabellen: partitioneer op de datum en maak vervolgens binnen elke partitie een bucket op basis van de koppelingssleutel.

Het probleem waar je op moet letten, is het probleem met de kleine bestanden. Partitioneren op een kolom met een zeer hoge kardinaliteit โ€“ een tijdstempel of een klantidentificatie โ€“ resulteert in duizenden kleine mappen, elk met een bestand dat veel kleiner is dan de HDFS-blokgrootte. Dit zorgt voor een overmatig geheugenverbruik van de NameNode en vertraagt โ€‹โ€‹elke scan, precies het resultaat dat partitionering juist moest voorkomen. Bucketing voorkomt dit, omdat het aantal bestanden wordt beperkt door de tabeldefinitie.

Het gebruik van buckets kent een eigen kanttekening: de indeling is alleen correct als elke schrijver zich eraan houdt. Het aantal buckets dat bij de aanmaak is opgegeven, is metadata. Een taak die naar de tabel schrijft zonder de juiste clustering toe te passen, kan bestanden achterlaten die niet overeenkomen met de opgegeven indeling. Latere sampling of het samenvoegen van buckets zal dan de verkeerde rijen lezen.

Veelgestelde vragen

Voer SHOW PARTITIONS table_name uit in de Hive-shell. Hiermee wordt de metastore uitgelezen en wordt รฉรฉn regel per partitiemap afgedrukt. Dit is sneller dan het opvragen van het warehousepad in HDFS en bevestigt bovendien dat de metastore gesynchroniseerd is.

ALTER TABLE table_name ADD PARTITION (state='Goa') registreert een nieuwe map, en ALTER TABLE table_name DROP PARTITION (state='Goa') verwijdert deze. Dropping Een beheerde partitie verwijdert zijn gegevens, terwijl dropping Een externe verwijdert alleen de metastore-vermelding.

Hive beperkt dynamische partities standaard tot 100 per node en 1000 per statement. Een sleutel met meer unieke waarden overschrijdt deze limiet en beรซindigt de taak. Verhoog hive.exec.max.dynamic.partitions.pernode en hive.exec.max.dynamic.partitions, of kies een grovere sleutel.

Nee. Het was nodig in Hive 0.x en 1.x om het aantal reducers gelijk te stellen aan het aantal buckets. HIVE-12331 heeft dit verwijderd in Hive 2.0, en de engine leidt nu zowel het aantal reducers als de kolom 'cluster-by' af uit de tabel.

TABLESAMPLE(BUCKET x OUT OF y ON column) leest alleen de overeenkomende bucketbestanden in plaats van alles te scannen. Omdat de rijen tijdens het schrijven op dezelfde kolom zijn gehasht, is de steekproef herhaalbaar en veel goedkoper dan een filter op willekeurige rijen.

Het opsplitsen van een tabel in duizenden kleine bestanden verspilt NameNode-geheugen en start รฉรฉn taak per bestand, waardoor scans vertragen. Dit komt meestal voor bij een partitiesleutel met een zeer hoge kardinaliteit. Grovere sleutels, bucketing of bestandscompressie lossen dit op.

Ja. Analyse van querylogboeken en machine learning-modellen in tools zoals Cloudera Workload XM rangschikken kolommen op basis van filterfrequentie, scheefheid en kardinaliteit, en stellen vervolgens een lay-out voor. De suggestie moet nog worden beoordeeld, omdat deze geen inzicht heeft in geplande workloads.

Copilot genereert snel PARTITIONED BY- en CLUSTERED BY-instructies op basis van een opmerking, en agentische assistenten kunnen een volledig laadscript genereren. Controleer altijd het gegenereerde aantal buckets en de sleutel met de werkelijke kardinaliteit, omdat het model alleen op basis van namen een schatting maakt.

Vat dit bericht samen met: