Apache Beam,批處理和流式處理的融合!

鍋外的大佬發表於2020-12-02

1. 概述

在本教程中,我們將介紹 Apache Beam 並探討其基本概念。
我們將首先演示使用 Apache Beam 的用例和好處,然後介紹基本概念和術語。之後,我們將通過一個簡單的例子來說明 Apache Beam 的所有重要方面。

2. Apache Beam是個啥?

Apache Beam(Batch+strEAM)是一個用於批處理和流式資料處理作業的統一程式設計模型。它提供了一個軟體開發工具包,用於定義和構建資料處理管道以及執行這些管道的執行程式。

Apache Beam旨在提供一個可移植的程式設計層。事實上,Beam管道執行程式將資料處理管道轉換為與使用者選擇的後端相容的API。目前,支援這些分散式處理後端有:

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

3. 為啥選擇 Apache Beam

Apache Beam 將批處理和流式資料處理融合在一起,而其他元件通常通過單獨的 API 來實現這一點。因此,很容易將流式處理更改為批處理,反之亦然,例如,隨著需求的變化。

Apache Beam 提高了可移植性和靈活性。我們關注的是邏輯,而不是底層的細節。此外,我們可以隨時更改資料處理後端。

Apache Beam 可以使用 Java、Python、Go和 Scala等SDK。事實上,團隊中的每個人都可以使用他們選擇的語言。

4. 基本概念

使用 Apache Beam,我們可以構建工作流圖(管道)並執行它們。程式設計模型中的關鍵概念是:

  • PCollection–表示可以是固定批處理或資料流的資料集

  • PTransform–一種資料處理操作,它接受一個或多個 PCollections 並輸出零個或多個 PCollections。

  • Pipeline–表示 PCollection 和 PTransform 的有向無環圖,因此封裝了整個資料處理作業。

  • PipelineRunner–在指定的分散式處理後端上執行管道。

簡單地說,PipelineRunner 執行一個管道,管道由 PCollection 和 PTransform 組成。

5. 字數統計示例

現在我們已經學習了 Apache Beam 的基本概念,讓我們設計並測試一個單詞計數任務。

5.1 建造樑式管道

設計工作流圖是每個 Apache Beam 作業的第一步,單詞計數任務的步驟定義如下:
1.從原文中讀課文。
2.把課文分成單詞表。
3.所有單詞都小寫。
4.刪去標點符號。
5.過濾停止語。
6.統計唯一單詞數量。
為了實現這一點,我們需要使用 PCollectionPTransform 抽象將上述步驟轉換為 管道

5.2. 依賴

在實現工作流圖之前,先新增 Apache Beam的依賴項 到我們的專案:

<dependency>
    <groupId>org.apache.beam</groupId>
    <artifactId>beam-sdks-java-core</artifactId>
    <version>${beam.version}</version>
</dependency>

Beam管道執行程式依賴於分散式處理後端來執行任務。我們新增 DirectRunner 作為執行時依賴項:

<dependency>
    <groupId>org.apache.beam</groupId>
    <artifactId>beam-runners-direct-java</artifactId>
    <version>${beam.version}</version>
    <scope>runtime</scope>
</dependency>

與其他管道執行程式不同,DirectRunner 不需要任何額外的設定,這對初學者來說是個不錯的選擇。

5.3. 實現

Apache Beam 使用 Map-Reduce 程式設計正規化 ( 類似 Java Stream)。講下面內容之前,最好 對 reduce(), filter(), count(), map(), 和 flatMap() 有個基礎概念和認識。

首先要做的事情就是 建立管道

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

六步單詞計數任務:

PCollection<KV<String, Long>> 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());

apply() 的第一個(可選)引數是一個String,它只是為了提高程式碼的可讀性。下面是上述程式碼中每個 apply() 的作用:

  1. 首先,我們使用 TextIO 逐行讀取輸入文字檔案。
  2. 將每一行按空格分開,把它對映到一個單詞表上。
  3. 單詞計數不區分大小寫,所以我們將所有單詞都小寫。
  4. 之前,我們用空格分隔行,但是像“word!“和”word?"這樣的,就需要刪除標點符號。
  5. 像“is”和“by”這樣的停止詞在幾乎每一篇英語文章中都很常見,所以我們將它們刪除。
  6. 最後,我們使用內建函式 Count.perElement() 計算唯一單詞數量。

如前所述,管道是在分散式後端處理的。不可能在記憶體中的PCollection上迭代,因為它分佈在多個後端。相反,我們將結果寫入外部資料庫或檔案。

首先,我們將PCollection轉換為String。然後,使用TextIO編寫輸出:

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

現在管道 已經定義好了,接下來做個簡單的測試。

5.4. 執行測試

到目前為止,我們已為單詞計數任務定義了管道,現在執行管道

p.run().waitUntilFinish();

在這行程式碼中,Apache Beam 將把我們的任務傳送到多個 DirectRunner 例項。因此,最後將生成幾個輸出檔案。它們將包含以下內容:

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

在 Apache Beam 中定義和執行分散式作業是如此地簡單。為了進行比較,單詞計數實現在 Apache Spark, Apache Flink 和 Hazelcast-Jet 上也有

6. 結語

在本教程中,我們瞭解了 Apache Beam 是什麼,以及它為什麼比其他選擇更受歡迎。我們還通過一個單詞計數示例演示了 Apache Beam 的基本概念。
如果你覺得文章還不錯,記得關注公眾號: 鍋外的大佬
鍋外的大佬部落格

相關文章