Salta el contingut

Hadoop i l'Ecosistema Big Data

Introducció

Apache Hadoop va néixer d'una necessitat real: Google havia publicat el 2003 el paper del Google File System (GFS) i el 2004 el de MapReduce, però el codi era propietari. Doug Cutting i Mike Cafarella van crear Hadoop el 2006 com a reimplementació open source d'aquests conceptes mentre treballaven en el motor de cerca Nutch. Yahoo va ser el primer gran usuari, utilitzant Hadoop per indexar la web amb un clúster de 10.000 màquines.

Avui, el 2025, l'ecosistema Hadoop ha evolucionat enormement. MapReduce ja no és l'eina de processament principal (Spark l'ha substituït àmpliament), però HDFS i YARN segueixen sent la base de moltes plataformes de Big Data on-premise. A més, Apache Kafka s'ha convertit en l'espina dorsal del streaming de dades a escala empresarial, independent de Hadoop.


HDFS: Hadoop Distributed File System

Arquitectura

HDFS és un sistema de fitxers distribuït dissenyat per emmagatzemar fitxers molt grans de forma fiable a través d'un clúster de màquines commodity (ordinadors de baix cost estàndard).

graph TB
    subgraph Client
        C[Client HDFS]
    end

    subgraph Master
        NN[NameNode\nMetadades\nEspai de noms\nDirectori de blocs]
        SN[Secondary NameNode\nCheckpoints\nNO es backup!]
        NN -.->|checkpoint periodic| SN
    end

    subgraph Workers
        DN1[DataNode 1\nBloc A1\nBloc B2\nBloc C1]
        DN2[DataNode 2\nBloc A2\nBloc B1\nBloc C3]
        DN3[DataNode 3\nBloc A3\nBloc B3\nBloc C2]
        DN4[DataNode 4\nBloc A1 rep\nBloc B2 rep]
    end

    C -->|1. On estic bloc X?| NN
    NN -->|2. DataNode 2, port 50010| C
    C -->|3. Llegir dades directament| DN2
    DN1 -.->|heartbeat cada 3s| NN
    DN2 -.->|heartbeat cada 3s| NN
    DN3 -.->|heartbeat cada 3s| NN

Components principals:

NameNode: el "cervell" del clúster HDFS. Emmagatzema tots els metadades del sistema de fitxers: l'arbre de directoris, els permisos, i la llista de blocs que formen cada fitxer i quins DataNodes els contenen. NO emmagatzema les dades reals. El NameNode és l'únic punt de fallada (SPOF) en la configuració bàsica, per la qual cosa Hadoop 2+ suporta High Availability amb dos NameNodes (actiu i de reserva).

DataNode: on es guarden físicament els blocs de dades. Cada DataNode envia un "heartbeat" al NameNode cada 3 segons per indicar que està viu. Si el NameNode no rep heartbeat durant 10 minuts, considera el DataNode mort i replica els seus blocs en altres DataNodes per mantenir el factor de replicació.

Secondary NameNode: NOM és un backup del NameNode! És un servei que periòdicament fa un checkpoint de l'estat del NameNode, fusionant el fitxer fsimage (estat del sistema de fitxers) amb el edits log (canvis recents) per evitar que el log creixi indefinidament.

Blocs i replicació

Per defecte, HDFS divideix cada fitxer en blocs de 128 MB (configurable) i emmagatzema 3 còpies de cada bloc en DataNodes diferents (factor de replicació 3). La política de placement per defecte intenta: - Posar la primera còpia al DataNode on s'escriu - La segona còpia en un rack diferent - La tercera còpia en un altre DataNode del segon rack

Això garanteix que si falla tot un rack (tall de corrent, error de switch), les dades segueixen disponibles.

Càlcul d'espai:

Espai físic necessari = Mida de les dades × Factor de replicació

Exemple:
- Dataset: 10 TB
- Factor replicació: 3
- Espai físic necessari: 10 TB × 3 = 30 TB
- Amb un 20% de marge operatiu: 36 TB

Operacions HDFS bàsiques

# Llistar el directori arrel
hdfs dfs -ls /

# Crear un directori
hdfs dfs -mkdir -p /user/alumne/dades

# Pujar un fitxer local a HDFS
hdfs dfs -put fitxer_local.csv /user/alumne/dades/

# Descarregar un fitxer d'HDFS
hdfs dfs -get /user/alumne/dades/fitxer_local.csv ./

# Veure el contingut d'un fitxer (com cat)
hdfs dfs -cat /user/alumne/dades/fitxer_local.csv | head -20

# Copiar dins HDFS
hdfs dfs -cp /user/alumne/dades/a.csv /user/alumne/backup/

# Esborrar un fitxer (va a la paperera per defecte)
hdfs dfs -rm /user/alumne/dades/fitxer_vell.csv

# Esborrar un directori i tot el seu contingut
hdfs dfs -rm -r /user/alumne/dades_velles/

# Veure l'ús de disc
hdfs dfs -du -s -h /user/alumne/

# Informació del sistema de fitxers
hdfs dfsadmin -report

# Comprovar l'estat del sistema (safe mode, blocs sub-replicats)
hdfs dfsadmin -safemode get

# Balancejar les dades entre DataNodes
hdfs balancer -threshold 10

Safe Mode

En iniciar-se, el NameNode entra en "safe mode" mentre verifica que té prou blocs reportats pels DataNodes. En safe mode, HDFS és de lectura i no permet modificacions. Si un clúster es queda en safe mode indefinidament, pot indicar un problema de DataNodes amb blocs perduts.

HDFS en alta disponibilitat

Per a entorns de producció, HDFS HA usa: - Dos NameNodes: un actiu (active) i un standby - JournalNodes: un quorum de nodes (mínim 3) que emmagatzemen el log d'edicions compartit - ZooKeeper: per a l'elecció automàtica del NameNode actiu i el failover


MapReduce: el paradigma original

MapReduce és un model de programació per al processament distribuït de grans datasets. Inspirat en les funcions funcionals map i reduce, simplifica el processament distribuït amagant tota la complexitat de la distribució, la tolerància a fallades i la gestió de la xarxa.

Com funciona

Dataset gran (TB):
[record1, record2, ..., record_N]

FASE MAP (paral·lela, un mapper per split):
Mapper 1: record1 → [(clau_A, val1), (clau_B, val2)]
Mapper 2: record2 → [(clau_A, val3), (clau_C, val4)]
Mapper N: record_N → [(clau_B, val5), (clau_C, val6)]

FASE SHUFFLE & SORT (framework automàtic):
Agrupa per clau:
clau_A → [val1, val3]
clau_B → [val2, val5]
clau_C → [val4, val6]

FASE REDUCE (un reducer per clau o grup):
Reducer 1: clau_A, [val1, val3] → resultat_A
Reducer 2: clau_B, [val2, val5] → resultat_B
Reducer 3: clau_C, [val4, val6] → resultat_C

Exemple: WordCount en Python (Hadoop Streaming)

#!/usr/bin/env python3
# mapper.py - compta les paraules d'un text

import sys

for linia in sys.stdin:
    linia = linia.strip()
    paraules = linia.split()
    for paraula in paraules:
        # Emet (paraula, 1) per a cada paraula
        print(f"{paraula.lower()}\t1")
#!/usr/bin/env python3
# reducer.py - suma les ocurrències de cada paraula

import sys

paraula_actual = None
comptador = 0

for linia in sys.stdin:
    linia = linia.strip()
    paraula, count = linia.split('\t', 1)
    count = int(count)

    if paraula == paraula_actual:
        comptador += count
    else:
        if paraula_actual is not None:
            print(f"{paraula_actual}\t{comptador}")
        paraula_actual = paraula
        comptador = count

# Emet l'última paraula
if paraula_actual:
    print(f"{paraula_actual}\t{comptador}")
# Executar el job MapReduce amb Hadoop Streaming
hadoop jar $HADOOP_HOME/share/hadoop/tools/lib/hadoop-streaming-*.jar \
    -input /user/alumne/text_entrada/ \
    -output /user/alumne/wordcount_resultat/ \
    -mapper mapper.py \
    -reducer reducer.py \
    -file mapper.py \
    -file reducer.py

Quan NO usar MapReduce

MapReduce té limitacions importants que el fan inadequat per a molts casos d'ús moderns:

  • Iteracions: algoritmes com k-means o PageRank requereixen múltiples passades sobre les dades. Cada iteració MapReduce escriu i llegeix d'HDFS, introduint una latència enorme.
  • Interactivitat: no és possible fer una consulta ad-hoc amb MapReduce en segons; cada job triga minuts.
  • Streaming: MapReduce és inherentment batch; no pot processar dades en temps real.
  • Complexitat de programació: expressar lògica complexa en parells Map/Reduce és laboriós.

Per a tots aquests casos, Apache Spark (que llegeix de HDFS però processa en memòria) és la solució actual.


YARN: Yet Another Resource Negotiator

YARN és el sistema de gestió de recursos d'Hadoop 2+. Desacobla la gestió de recursos del model de programació, permetent executar no només jobs MapReduce sinó qualsevol framework de computació distribuïda (Spark, Flink, Tez...).

graph TB
    subgraph YARN
        RM[ResourceManager\nGestiona recursos globals\nPlanífica aplicacions]
        NM1[NodeManager 1\nGestiona contenidors\nMonitora recursos]
        NM2[NodeManager 2\nGestiona contenidors\nMonitora recursos]
        NM3[NodeManager 3\nGestiona contenidors\nMonitora recursos]
    end

    subgraph App["Aplicacio Spark"]
        AM[ApplicationMaster\ns'executa en un contenidor\nNegoci recursos amb RM]
        E1[Executor 1]
        E2[Executor 2]
    end

    Client --> RM
    RM --> NM1
    RM --> NM2
    RM --> NM3
    NM1 --> AM
    NM2 --> E1
    NM3 --> E2
    AM -->|sol·licita contenidors| RM

Conceptes clau YARN: - Container: unitat de recursos assignada (CPU + memòria) - ApplicationMaster: un procés per aplicació que negocia els recursos amb el ResourceManager - NodeManager: el "daemon" que s'executa a cada worker node i gestiona els contenidors locals


L'Ecosistema Hadoop: les eines complementàries

Apache Hive

Hive és una capa de SQL sobre HDFS/Hadoop que permet fer consultes en SQL (HiveQL) sense programar MapReduce manualment. Tradueix automàticament les consultes SQL en jobs MapReduce o Spark (Hive on Spark).

-- Crear una taula externa sobre dades en HDFS (no copia les dades)
CREATE EXTERNAL TABLE IF NOT EXISTS logs_web (
    timestamp_event STRING,
    ip_client STRING,
    metode STRING,
    url STRING,
    codi_resposta INT,
    mida_resposta BIGINT,
    user_agent STRING
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
STORED AS TEXTFILE
LOCATION '/user/alumne/logs/';

-- Crear una taula optimitzada en format Parquet amb particionament
CREATE TABLE logs_web_parquet (
    timestamp_event STRING,
    ip_client STRING,
    metode STRING,
    url STRING,
    codi_resposta INT,
    mida_resposta BIGINT
)
PARTITIONED BY (any INT, mes INT)
STORED AS PARQUET;

-- Carregar dades de la taula original a la particionada
INSERT INTO TABLE logs_web_parquet PARTITION (any=2025, mes=3)
SELECT timestamp_event, ip_client, metode, url, codi_resposta, mida_resposta
FROM logs_web
WHERE year(timestamp_event) = 2025 AND month(timestamp_event) = 3;

-- Anàlisi: top 10 URLs més visitades el 2025
SELECT url, COUNT(*) AS visites
FROM logs_web_parquet
WHERE any = 2025 AND codi_resposta = 200
GROUP BY url
ORDER BY visites DESC
LIMIT 10;

Apache HBase

HBase és una base de dades NoSQL columnar distribuïda sobre HDFS, inspirada en Google Bigtable. Les seves característiques:

  • Latència molt baixa per a lectures i escriptures aleatòries (mil·lisegons)
  • Escalabilitat horitzontal: pot gestionar trilions de files i milions de columnes
  • Consistència forta: a diferència de Cassandra, HBase garanteix consistència en cada lectura

Casos d'ús típics: historial de navegació web, feeds de xarxes socials, missatgeria, registres de trucades (CDR en telecomunicacions).

Apache Sqoop

Sqoop (SQL-to-Hadoop) és l'eina estàndard per a importar dades de bases de dades relacionals (MySQL, Oracle, PostgreSQL) a HDFS o Hive, i viceversa. Usa JDBC internament i paral·lelitza la importació.

# Importar tota una taula de MySQL a HDFS en format Parquet
sqoop import \
    --connect jdbc:mysql://servidor-mysql:3306/ecommerce \
    --username admin --password secret \
    --table comandes \
    --target-dir /user/alumne/comandes/ \
    --as-parquetfile \
    --num-mappers 8 \
    --split-by id_comanda

# Exportar dades d'HDFS a MySQL
sqoop export \
    --connect jdbc:mysql://servidor-mysql:3306/reporting \
    --username admin --password secret \
    --table resum_vendes_mensuals \
    --export-dir /user/alumne/resum_vendes/ \
    --input-fields-terminated-by ','

Sqoop el 2025

Sqoop està en mode de manteniment i no s'actualitza activament. Les alternatives modernes són Apache Nifi per a la ingestió en temps real i Kafka Connect amb connectors JDBC per a la captura de canvis (CDC). Per a migracions batch, moltes empreses usen directament connectors JDBC de Spark.

Apache Oozie

Oozie és el planificador de fluxos de treball (workflow scheduler) natiu de l'ecosistema Hadoop. Permet definir pipelines de jobs MapReduce, Spark i Hive com a grafs DAG en XML. El 2025, ha estat pràcticament substituït per Apache Airflow en noves implantacions.

Apache ZooKeeper

ZooKeeper és un servei de coordinació distribuïda que proporciona: - Configuració distribuïda: emmagatzemar i distribuir configuració entre nodes del clúster - Naming service: descoberta de serveis en un clúster - Sincronització: locks distribuïts per coordinar processos concurrents - Elecció de líder: determinar quin node és el mestre (usat per HBase, YARN HA, Kafka antic)


Apache Kafka: l'espina dorsal del streaming 2025

Visió general

Apache Kafka és una plataforma de streaming distribuïda creada per LinkedIn el 2011. El 2025 és la tecnologia de streaming de dades dominant a l'empresa moderna: Netflix, Uber, Airbnb, LinkedIn (el creador!), Twitter i milers d'empreses el fan servir com a "sistema nerviós central" per a la comunicació entre microserveis i l'ingesta de dades en temps real.

Kafka no és simplement una cua de missatges (com RabbitMQ o ActiveMQ). És una plataforma de streaming de dades que ofereix:

  • Alta throughput: milions de missatges per segon en un sol clúster
  • Persistència: els missatges s'emmagatzemen en disc (no s'eliminen en ser consumits)
  • Replicació: tolerància a fallades via replicació entre brokers
  • Retrocés en el temps: els consumidors poden rellegir missatges antics (configurable fins a X dies)
  • Escalabilitat horitzontal: afegir particions i brokers per escalar

Arquitectura Kafka

graph LR
    subgraph Productors
        P1[Microservei\nComandes]
        P2[Aplicacio\nWeb - Events]
        P3[Sensor\nIoT]
    end

    subgraph Kafka Cluster
        subgraph Topic vendes - 3 particions
            T1P0[Particio 0\nBroker 1\nLider]
            T1P1[Particio 1\nBroker 2\nLider]
            T1P2[Particio 2\nBroker 3\nLider]
        end
    end

    subgraph Consumidors
        CG1A[Consumer Group\nAnalytics - Consumer A]
        CG1B[Consumer Group\nAnalytics - Consumer B]
        CG2[Consumer Group\nFrau - Consumer]
        CG3[Consumer Group\nStorage - Consumer]
    end

    P1 --> T1P0
    P2 --> T1P1
    P3 --> T1P2

    T1P0 --> CG1A
    T1P1 --> CG1B
    T1P2 --> CG2
    T1P0 --> CG3

Conceptes clau:

Topic: una categoria lògica de missatges. Pot tenir un nom arbitrari (vendes, events-usuari, telemetria-sensors). Cada topic es divideix en particions.

Partició: la unitat d'escalabilitat de Kafka. Cada partició és una cua ordenada i immutable de missatges. Més particions = més paral·lelisme = major throughput.

Broker: un servidor Kafka. Un clúster té típicament 3 a N brokers. Cada partició té un broker lider (que gestiona les lectures i escriptures) i N-1 seguidors (rèpliques).

Productor: una aplicació que escriu missatges en un topic. Pot especificar una clau (key) per garantir que missatges amb la mateixa clau sempre van a la mateixa partició (i, per tant, es processen en ordre).

Consumidor: una aplicació que llegeix missatges d'un o més topics. Els consumidors s'agrupen en Consumer Groups: cada missatge es lliura a exactament un consumidor del grup, permetent el processament paral·lel.

Offset: la posició d'un missatge dins d'una partició. Kafka emmagatzema el offset de cada consumer group per saber on va cada grup en la seva lectura.

Exemple pràctic: productor i consumidor Kafka en Python

# productor_kafka.py
from kafka import KafkaProducer
import json
import time
import random
from datetime import datetime

producer = KafkaProducer(
    bootstrap_servers=['localhost:9092'],
    value_serializer=lambda v: json.dumps(v).encode('utf-8'),
    key_serializer=lambda k: k.encode('utf-8') if k else None
)

def generar_event_compra():
    """Genera un event de compra simulat"""
    return {
        "id_comanda": random.randint(100000, 999999),
        "id_usuari": random.randint(1, 10000),
        "producte": random.choice(["laptop", "teclat", "monitor", "ratolí", "auriculars"]),
        "preu": round(random.uniform(10, 2000), 2),
        "timestamp": datetime.now().isoformat(),
        "pais": random.choice(["ES", "FR", "DE", "IT", "PT"])
    }

# Enviar 100 events de compra
for i in range(100):
    event = generar_event_compra()
    # Usar l'id_usuari com a clau per garantir ordre per usuari
    producer.send(
        topic='vendes',
        key=str(event['id_usuari']),
        value=event
    )
    print(f"Enviat: {event}")
    time.sleep(0.1)

producer.flush()
producer.close()
# consumidor_kafka.py
from kafka import KafkaConsumer
import json

consumer = KafkaConsumer(
    'vendes',
    bootstrap_servers=['localhost:9092'],
    group_id='analytics-group',
    auto_offset_reset='earliest',  # Llegir des del principi si no hi ha offset guardat
    value_deserializer=lambda m: json.loads(m.decode('utf-8')),
    key_deserializer=lambda k: k.decode('utf-8') if k else None
)

total_vendes = 0
comptador_per_pais = {}

print("Consumidor iniciat. Esperant missatges...")

for missatge in consumer:
    event = missatge.value
    total_vendes += event['preu']
    pais = event['pais']
    comptador_per_pais[pais] = comptador_per_pais.get(pais, 0) + 1

    print(f"Particio: {missatge.partition}, Offset: {missatge.offset}")
    print(f"Usuari {event['id_usuari']} ha comprat {event['producte']} per {event['preu']}€")
    print(f"Total acumulat: {total_vendes:.2f}€ | Vendes per pais: {comptador_per_pais}")
    print("---")
# docker-compose.yml per a iniciar Kafka localment
version: '3.8'
services:
  zookeeper:
    image: confluentinc/cp-zookeeper:7.5.0
    container_name: zookeeper
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000

  kafka:
    image: confluentinc/cp-kafka:7.5.0
    container_name: kafka
    depends_on:
      - zookeeper
    ports:
      - "9092:9092"
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_AUTO_CREATE_TOPICS_ENABLE: 'true'

  kafka-ui:
    image: provectuslabs/kafka-ui:latest
    container_name: kafka-ui
    ports:
      - "8080:8080"
    environment:
      KAFKA_CLUSTERS_0_NAME: local
      KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9092
    depends_on:
      - kafka
# Iniciar el clúster
docker compose up -d

# Crear un topic manualment (opcional, Kafka pot crear-lo automàticament)
docker exec kafka kafka-topics --create \
    --bootstrap-server localhost:9092 \
    --topic vendes \
    --partitions 3 \
    --replication-factor 1

# Llistar topics
docker exec kafka kafka-topics --list --bootstrap-server localhost:9092

# Veure la descripció d'un topic
docker exec kafka kafka-topics --describe \
    --bootstrap-server localhost:9092 \
    --topic vendes

# Consumir missatges des del terminal (per debugging)
docker exec kafka kafka-console-consumer \
    --bootstrap-server localhost:9092 \
    --topic vendes \
    --from-beginning

Miniactivitat

Inicia el docker-compose.yml anterior, executa el productor i el consumidor en dues terminals separades i observa el flux de missatges. Modifica el productor per enviar events amb preus aleatoris i el consumidor per mostrar l'alerta quan el preu superi 1000€.


graph LR
    subgraph Casos["Cas d'us"]
        B1[Batch\nHistoric gran]
        B2[Batch\nIteratiu]
        B3[Near real-time]
        B4[Real-time\nstrict]
        B5[ML distribuit]
        B6[Grafos]
    end

    subgraph Eines
        MR[MapReduce]
        SP[Spark]
        FL[Flink]
        KS[Kafka Streams]
    end

    B1 -->|adequat| MR
    B1 -->|millor opcio| SP
    B2 -->|NO adequat| MR
    B2 -->|ideal| SP
    B3 -->|Structured Streaming| SP
    B3 -->|ideal| FL
    B4 -->|NO| SP
    B4 -->|ideal latencia ms| FL
    B4 -->|simple| KS
    B5 -->|MLlib| SP
    B6 -->|GraphX| SP

Resum de la decisió:

Eina Millor per a Latència Complexitat
MapReduce ETL batch molt gran, compatibilitat legacy Minuts/hores Alta (Java)
Spark Batch, ML, streaming near-real-time Segons/minuts Mitjana (Python)
Flink Streaming real-time, event-time processing Mil·lisegons Alta (Java/Scala)
Kafka Streams Streaming simple en microserveis Java Mil·lisegons Baixa (Java)

Cloud-native Big Data

AWS EMR (Elastic MapReduce)

AWS EMR és un servei gestionat que permet executar Hadoop, Spark, Hive i altres eines de l'ecosistema Big Data sense gestionar la infraestructura manualment.

# Crear un clúster EMR amb Spark
aws emr create-cluster \
    --name "Cluster-Analytics-2025" \
    --release-label emr-7.0.0 \
    --applications Name=Spark Name=Hive Name=Hadoop \
    --instance-type m5.xlarge \
    --instance-count 5 \
    --use-default-roles \
    --ec2-attributes KeyName=la-teva-clau \
    --auto-terminate

# Submetre un job Spark a EMR
aws emr add-steps \
    --cluster-id j-XXXXXXXXXX \
    --steps Type=Spark,Name="Analisi Vendes",\
ActionOnFailure=CONTINUE,\
Args=[--deploy-mode,cluster,\
s3://bucket/codi/analisi_vendes.py,\
--input,s3://bucket/dades/,\
--output,s3://bucket/resultats/]

Google Dataproc

L'equivalent de Google Cloud, conegut per la seva velocitat d'aprovisionament (clústers disponibles en 90 segons) i la seva integració nativa amb BigQuery, Cloud Storage i Vertex AI.

Azure HDInsight

La plataforma de Microsoft per a Big Data, integrada amb Azure Data Lake Storage Gen2 i Synapse Analytics.

Databricks

Databricks, fundada pels creadors de Spark i Delta Lake, ofereix el que molts consideren la plataforma de Big Data més completa del 2025. Disponible a AWS, Azure i GCP, ofereix:

  • Clusters Spark gestionats amb autoscaling
  • Databricks Runtime (versió optimitzada de Spark)
  • Delta Lake integrat nativament
  • Unity Catalog: governança unificada de dades i ML
  • Databricks SQL: SQL Warehouse per a analytics
  • MLflow: plataforma de ML integrada
  • Notebooks col·laboratius (com Jupyter però més potents)

Miniactivitat

Accedeix a Databricks Community Edition (gratuït: community.cloud.databricks.com) i crea un notebook PySpark que llegeixi les dades del dataset de vols de airlines (disponible a Databricks Datasets) i calculi els retards mitjans per aerolínia.


Exercici pràctic: commandaments HDFS + Hive

Escenari

Tens accés a un clúster Hadoop Docker (o pots usar la imatge bde2020/hadoop-namenode). Has de:

  1. Preparar les dades localment:
# Descarregar dataset de vendes públic (exemple)
curl -L "https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv" \
    -o titanic.csv

# Iniciar el contenidor Hadoop
docker run -d --name hadoop-demo \
    -p 9870:9870 -p 8088:8088 \
    -e CLUSTER_NAME=demo \
    bde2020/hadoop-namenode:2.0.0-hadoop3.2.1-java8
  1. Pujar dades a HDFS:
# Entrar al contenidor
docker exec -it hadoop-demo bash

# Crear directori a HDFS
hdfs dfs -mkdir -p /user/alumne/titanic

# Pujar el CSV (suposem que l'hem copiat al contenidor)
docker cp titanic.csv hadoop-demo:/tmp/
hdfs dfs -put /tmp/titanic.csv /user/alumne/titanic/

# Verificar
hdfs dfs -ls /user/alumne/titanic/
hdfs dfs -du -h /user/alumne/titanic/
  1. Crear taula Hive i fer consultes:
-- Iniciar Hive
hive

-- Crear base de dades
CREATE DATABASE IF NOT EXISTS exercici;
USE exercici;

-- Crear taula externa sobre el CSV d'HDFS
CREATE EXTERNAL TABLE passatgers_titanic (
    PassengerId INT,
    Survived INT,
    Pclass INT,
    Name STRING,
    Sex STRING,
    Age DOUBLE,
    SibSp INT,
    Parch INT,
    Ticket STRING,
    Fare DOUBLE,
    Cabin STRING,
    Embarked STRING
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE
LOCATION '/user/alumne/titanic/'
TBLPROPERTIES ("skip.header.line.count"="1");

-- Taxa de supervivència per classe i sexe
SELECT
    Pclass AS classe,
    Sex AS sexe,
    COUNT(*) AS total,
    SUM(Survived) AS supervivents,
    ROUND(SUM(Survived) * 100.0 / COUNT(*), 1) AS taxa_supervivencia
FROM passatgers_titanic
WHERE Age IS NOT NULL
GROUP BY Pclass, Sex
ORDER BY Pclass, Sex;

-- Edat mitjana dels supervivents vs no supervivents
SELECT
    CASE WHEN Survived = 1 THEN 'Supervivent' ELSE 'No supervivent' END AS estat,
    ROUND(AVG(Age), 1) AS edat_mitjana,
    ROUND(AVG(Fare), 2) AS tarifa_mitjana
FROM passatgers_titanic
WHERE Age IS NOT NULL
GROUP BY Survived;

Preguntes de reflexió:

  1. Quina diferència hi ha en el rendiment si converteixes el CSV a format Parquet i repeteixes les consultes?
  2. Quin impacte tindria augmentar el factor de replicació de 3 a 5 en aquest clúster d'un sol node?
  3. Com modificaries el disseny de la taula Hive per optimitzar les consultes per rang de dates si afegíssim una columna de data?

Consulta el fitxer ../bigdata_aplicat/practiques/practica_hadoop.md per a la pràctica completa de Hadoop amb Docker.