Introduzione ad Apache Beam

1. Panoramica

In questo tutorial, introdurremo Apache Beam ed esploreremo i suoi concetti fondamentali.

Inizieremo dimostrando il caso d'uso e i vantaggi dell'utilizzo di Apache Beam, quindi tratteremo concetti e terminologie fondamentali. Successivamente, esamineremo un semplice esempio che illustra tutti gli aspetti importanti di Apache Beam.

2. Cos'è Apache Beam?

Apache Beam (Batch + strEAM) è un modello di programmazione unificato per processi di elaborazione dati in batch e in streaming. Fornisce un kit di sviluppo software per definire e costruire pipeline di elaborazione dati e runner per eseguirle.

Apache Beam è progettato per fornire un livello di programmazione portatile. Infatti, i Beam Pipeline Runners traducono la pipeline di elaborazione dati nell'API compatibile con il backend scelto dall'utente. Attualmente, questi backend di elaborazione distribuita sono supportati:

  • Apache Apex
  • Apache Flink
  • Apache Gearpump (incubazione)
  • Apache Samza
  • Apache Spark
  • Google Cloud Dataflow
  • Hazelcast Jet

3. Perché Apache Beam?

Apache Beam fonde l'elaborazione in batch e in streaming dei dati, mentre altri spesso lo fanno tramite API separate. Di conseguenza, è molto facile cambiare un processo di streaming in un processo batch e viceversa, ad esempio, quando i requisiti cambiano.

Apache Beam aumenta la portabilità e la flessibilità. Ci concentriamo sulla nostra logica piuttosto che sui dettagli sottostanti. Inoltre, possiamo modificare il backend per l'elaborazione dei dati in qualsiasi momento.

Sono disponibili SDK Java, Python, Go e Scala per Apache Beam. In effetti, tutti i membri del team possono usarlo con la loro lingua preferita.

4. Concetti fondamentali

Con Apache Beam, possiamo costruire grafici del flusso di lavoro (pipeline) ed eseguirli. I concetti chiave nel modello di programmazione sono:

  • PCollection : rappresenta un set di dati che può essere un batch fisso o un flusso di dati
  • PTransform - un'operazione di elaborazione dati che richiede uno o più PCollection s e uscite zero o più PCollection s
  • Pipeline : rappresenta un grafico aciclico diretto di PCollection e PTransform e, quindi, incapsula l'intero lavoro di elaborazione dei dati
  • PipelineRunner : esegue una pipeline su un back-end di elaborazione distribuito specificato

In poche parole, un PipelineRunner esegue una pipeline e una pipeline è composta da PCollection e PTransform .

5. Esempio di conteggio parole

Ora che abbiamo appreso i concetti di base di Apache Beam, progettiamo e testiamo un'attività di conteggio parole.

5.1. Costruzione di una pipeline di travi

La progettazione del grafico del flusso di lavoro è il primo passo in ogni lavoro di Apache Beam. Definiamo i passaggi di un'attività di conteggio parole:

  1. Leggi il testo da una fonte.
  2. Dividi il testo in un elenco di parole.
  3. Tutte le parole in minuscolo.
  4. Taglia la punteggiatura.
  5. Filtra le parole chiave.
  6. Conta ogni parola unica.

Per ottenere ciò, dovremo convertire i passaggi precedenti in una singola pipeline utilizzando le astrazioni PCollection e PTransform .

5.2. Dipendenze

Prima di poter implementare il nostro grafico del flusso di lavoro, dobbiamo aggiungere la dipendenza principale di Apache Beam al nostro progetto:

 org.apache.beam beam-sdks-java-core ${beam.version} 

I Beam Pipeline Runner si affidano a un backend di elaborazione distribuito per eseguire le attività. Aggiungiamo DirectRunner come dipendenza di runtime:

 org.apache.beam beam-runners-direct-java ${beam.version} runtime 

A differenza di altri Pipeline Runner, DirectRunner non necessita di alcuna configurazione aggiuntiva, il che lo rende una buona scelta per i principianti.

5.3. Implementazione

Apache Beam utilizza il paradigma di programmazione Map-Reduce (lo stesso di Java Streams). In effetti, è una buona idea avere un concetto di base di reduce () , filter () , count () , map () e flatMap () prima di continuare.

La creazione di una pipeline è la prima cosa che facciamo:

PipelineOptions options = PipelineOptionsFactory.create(); Pipeline p = Pipeline.create(options);

Ora applichiamo la nostra attività di conteggio delle parole in sei passaggi:

PCollection
    
      wordCount = p .apply("(1) Read all lines", TextIO.read().from(inputFilePath)) .apply("(2) Flatmap to a list of words", FlatMapElements.into(TypeDescriptors.strings()) .via(line -> Arrays.asList(line.split("\\s")))) .apply("(3) Lowercase all", MapElements.into(TypeDescriptors.strings()) .via(word -> word.toLowerCase())) .apply("(4) Trim punctuations", MapElements.into(TypeDescriptors.strings()) .via(word -> trim(word))) .apply("(5) Filter stopwords", Filter.by(word -> !isStopWord(word))) .apply("(6) Count words", Count.perElement());
    

Il primo argomento (opzionale) di apply () è una stringa che serve solo per una migliore leggibilità del codice. Ecco cosa fa ciascuna apply () nel codice sopra:

  1. Innanzitutto, leggiamo un file di testo di input riga per riga utilizzando TextIO .
  2. Dividendo ogni riga per spazi bianchi, la mappiamo a un elenco di parole.
  3. Il conteggio delle parole non fa distinzione tra maiuscole e minuscole, quindi tutte le parole vengono minuscole.
  4. In precedenza, abbiamo diviso le righe per spazi bianchi, finendo con parole come "parola!" e "parola?", quindi rimuoviamo i segni di punteggiatura.
  5. Parole non significative come "is" e "by" sono frequenti in quasi tutti i testi inglesi, quindi le rimuoviamo.
  6. Infine, contiamo parole uniche utilizzando la funzione incorporata Count.perElement () .

Come accennato in precedenza, le pipeline vengono elaborate su un backend distribuito. Non è possibile iterare su una PCollection in memoria poiché è distribuita su più backend. Invece, scriviamo i risultati su un database o file esterno.

Innanzitutto, convertiamo la nostra PCollection in String . Quindi, usiamo TextIO per scrivere l'output:

wordCount.apply(MapElements.into(TypeDescriptors.strings()) .via(count -> count.getKey() + " --> " + count.getValue())) .apply(TextIO.write().to(outputFilePath));

Now that our Pipeline definition is complete, we can run and test it.

5.4. Running and Testing

So far, we've defined a Pipeline for the word count task. At this point, let's run the Pipeline:

p.run().waitUntilFinish();

On this line of code, Apache Beam will send our task to multiple DirectRunner instances. Consequently, several output files will be generated at the end. They'll contain things like:

... apache --> 3 beam --> 5 rocks --> 2 ...

Defining and running a distributed job in Apache Beam is as simple and expressive as this. For comparison, word count implementation is also available on Apache Spark, Apache Flink, and Hazelcast Jet.

6. Where Do We Go From Here?

Abbiamo contato con successo ogni parola dal nostro file di input, ma non abbiamo ancora un report delle parole più frequenti. Certamente, l'ordinamento di una PCollection è un buon problema da risolvere come passaggio successivo.

Successivamente, potremo saperne di più su Finestre, Trigger, Metriche e Trasformazioni più sofisticate. La documentazione di Apache Beam fornisce informazioni approfondite e materiale di riferimento.

7. Conclusione

In questo tutorial, abbiamo imparato cos'è Apache Beam e perché è preferito rispetto alle alternative. Abbiamo anche dimostrato i concetti di base di Apache Beam con un esempio di conteggio delle parole.

Il codice per questo tutorial è disponibile su GitHub.