Flink 熱詞統計(1): 基礎功能實現

大資料開發發表於2019-05-01

前言

本系列文章將從熱詞統計需求講起,講解flink在實際專案中的應用、部署、容錯。專案中的程式碼為scala所編寫,沒有用java的原因是scala語言看起來更加簡練,同時與java語言的相容性較好,可以直接引用java中的類。

定義資料格式

本篇文章會講述熱詞統計最核心的一個功能實現,即訊息傳遞過來的是搜尋的單詞,程式中進行統計。基於此我們定義傳遞的資料格式為${timestamp},${word},之所以有timestamp是為了標註搜尋時間,用於修正flink中的watermask

離線資料模擬

定義好了資料格式之後,我們可以將其轉換為scala中的Tuple,這裡我們先利用fromElements api 建立離線資料用於除錯

val currentTimeStamp = System.currentTimeMillis()
val dataStream = env.fromElements(
  (currentTimeStamp,"word1"),
  (currentTimeStamp+1,"word2"),
  (currentTimeStamp+2,"word1"),
  (currentTimeStamp+3,"word3"),
)
複製程式碼

具體計算

我們要實現統計的功能,即求和,需要flink中的sum這個operator,通過[flink-1.8文件/操作符]發現,只有keyedStream這個物件才有sum方法,所以在執行sum之前得先呼叫keyBy方法將dataStream轉換為keyedStream。接下來是這兩個方法具體的傳參,我們有兩個欄位,時間戳和單詞,要對單詞進行keyBy操作需傳入1(下標從0開始),但是sum方法要傳什麼呢?這個時候我們發現我們的物件中沒有可以用來求和的,所以我們需要將資料結構從${timestamp},${word}轉換為${timestamp},${word},${count},這就得使用map方法了,其中count為1。經過如上分析,有如下程式碼

dataStream
      .map(x => (x._1, x._2, 1))
      .keyBy(1)
      .sum(2)
      .print()
複製程式碼

為便於除錯,最後的結果輸出為到控制檯即為

6> (1556680015646,word2,1)

12> (1556680015648,word3,1)

10> (1556680015647,word1,1)

10> (1556680015647,word1,2)

輸出結果中開頭的數字即為執行緒的標示,這裡我們看出,word2和word3分別是不同的執行緒,而word1則為同一個執行緒

疑問解答

  1. 為什麼這裡關於word1的統計有兩次輸出呢? 因為這裡是實時流式計算,來一條資料,各個operator就會為它計算一次,所以最後都有一次對應的輸出
  2. 那什麼時候輸出的個數會變少呢? 在使用window的時候,多個資料會按照一定的規則(根據個數或者根據時間段)聚集在一個window中,然後每一個window就只有一個輸出結果

小技巧

  1. 這裡我們使用的scala語言來編寫flink專案,需要注意的是要在pom.xml檔案中加上如下程式碼,使其能夠支援scala編譯
<plugins>
    <plugin>
        <groupId>net.alchim31.maven</groupId>
        <artifactId>scala-maven-plugin</artifactId>
        <executions>
            <!-- Run scala compiler in the process-resources phase, so that dependencies on
                scala classes can be resolved later in the (Java) compile phase -->
            <execution>
                <id>scala-compile-first</id>
                <phase>process-resources</phase>
                <goals>
                    <goal>compile</goal>
                </goals>
            </execution>
            <!-- Run scala compiler in the process-test-resources phase, so that dependencies on
                 scala classes can be resolved later in the (Java) test-compile phase -->
            <execution>
                <id>scala-test-compile</id>
                <phase>process-test-resources</phase>
                <goals>
                    <goal>testCompile</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <jvmArgs>
                <jvmArg>-Xms128m</jvmArg>
                <jvmArg>-Xmx512m</jvmArg>
            </jvmArgs>
        </configuration>
    </plugin>
</plugins>
複製程式碼
  1. 在專案的引用中,需要引用scala字尾的,如
<properties>
    <scala.binary.version>2.11</scala.binary.version>
    <flink.version>1.8.0</flink.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-streaming-scala_${scala.binary.version}</artifactId>
        <version>${flink.version}</version>
    </dependency>
</dependencies>
複製程式碼
  1. 檔案中的引用,在你輸入StreamExecutionEnvironment的時候,Intellij會提示你引入org.apache.flink.streaming.api.scala. StreamExecutionEnvironment,但是當你呼叫env.fromElements()方法的時候你會編譯器會有型別錯誤的提示

Flink 熱詞統計(1): 基礎功能實現
這個時候你只需要把檔案頭部的引用改為import org.apache.flink.streaming.api.scala._就可以了

結尾

本篇文章所講的實際內容並不多,但是為了照顧對flink、scala不瞭解的同學,我會把一些編寫程式碼的細節、思路講清楚,可能會有些囉嗦,可能有些語言組織不當,敬請諒解,如果有什麼建議,歡迎在評論區裡與我交流,這是我更新下去的動力

啊對了,差點忘了貼程式碼[github.com/Wing-Lo/fli…]

相關文章