在本指南中,我们将从头开始,从设置Flink项目到在Flink集群上运行流分析程序。
Wikipedia提供了一个IRC频道,其中记录了对Wiki的所有编辑。我们将在Flink中读取此通道,并计算每个用户在给定时间窗口内编辑的字节数。这很容易使用Flink在几分钟内实现,但它将为您提供一个良好的基础,从而开始自己构建更复杂的分析程序。
设置Maven项目
Flink 提供了 flink-quickstart-java
和 flink-quickstart-scala
插件,允许使用 Maven 的开发者创建统一的项目模版,应用项目模板可以规避掉很多部署上的坑。
我们将使用Flink Maven Archetype来创建我们的项目结构。有关此内容的更多详细信息,请参阅Java API快速入门。出于我们的目的,运行命令是这样的:
$ mvn archetype:generate \
-DarchetypeGroupId=org.apache.flink \
-DarchetypeArtifactId=flink-quickstart-java \
-DarchetypeVersion=1.7-SNAPSHOT \
-DgroupId=wiki-edits \
-DartifactId=wiki-edits \
-Dversion=0.1 \
-Dpackage=wiki-edits \
-DinteractiveMode=false
注意:对于Maven 3.0或更高版本,不再可以通过命令行指定存储库(-DarchetypeCatalog=https://repository.apache.org/content/repositories/snapshots/
)。如果要使用SNAPSHOT存储库,则需要向settings.xml添加存储库条目。有关此更改的详细信息,请参阅Maven官方文档
您可以编辑groupId
,artifactId
而package
如果你喜欢。使用上面的参数,Maven将创建一个如下所示的项目结构:
$ tree wiki-edits
wiki-edits/
├── pom.xml
└── src
└── main
├── java
│ └── wikiedits
│ ├── BatchJob.java
│ ├── SocketTextStreamWordCount.java
│ ├── StreamingJob.java
│ └── WordCount.java
└── resources
└── log4j.properties
我们的pom.xml
文件已经在根目录中添加了Flink依赖项,并且有几个示例Flink程序src/main/java
。我们可以删除示例程序,因为我们将从头开始:
$ rm wiki-edits/src/main/java/wikiedits/*.java
作为最后一步,我们需要将Flink Wikipedia连接器添加为依赖关系,以便我们可以在我们的程序中使用它。编辑它的dependencies
部分pom.xml
,使它看起来像这样:
<dependencies>
<!-- Apache Flink dependencies -->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-scala_${scala.binary.version}</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-table_${scala.binary.version}</artifactId>
<version>${flink.version}</version>
</dependency>
</dependencies>
注意flink-connector-wikiedits_2.11
添加的依赖项。(此示例和Wikipedia连接器的灵感来自Apache Samza 的Hello Samza示例。)
编写Flink程序
这是编码时间。启动您喜欢的IDE并导入Maven项目或打开文本编辑器并创建文件src/main/java/wikiedits/WikipediaAnalysis.java
:
package wikiedits;
public class WikipediaAnalysis {
public static void main(String[] args) throws Exception {
}
}
该计划现在非常基础,但我们会尽力填写。请注意,我不会在此处提供import语句,因为IDE可以自动添加它们。在本节结束时,如果您只想跳过并在编辑器中输入,我将使用import语句显示完整的代码。
Flink程序的第一步是创建一个StreamExecutionEnvironment
(或者ExecutionEnvironment
如果您正在编写批处理作业)。这可用于设置执行参数并创建从外部系统读取的源。所以让我们继续把它添加到main方法:
StreamExecutionEnvironment see = StreamExecutionEnvironment.getExecutionEnvironment();
接下来,我们将创建一个从Wikipedia IRC日志中读取的源:
DataStream<WikipediaEditEvent> edits = see.addSource(new WikipediaEditsSource());
这创建了一个我们可以进一步处理DataStream
的WikipediaEditEvent
数据元。出于本示例的目的,我们感兴趣的是确定每个用户在特定时间窗口中添加或删除的字节数,比如说五秒。为此,我们首先必须指定我们要在用户名上键入流,也就是说此流上的 算子操作应考虑用户名。在我们的例子中,窗口中编辑的字节的总和应该是每个唯一的用户。对于键入流,我们必须提供一个KeySelector
,如下所示:
KeyedStream<WikipediaEditEvent, String> keyedEdits = edits
.keyBy(new KeySelector<WikipediaEditEvent, String>() {
@Override
public String getKey(WikipediaEditEvent event) {
return event.getUser();
}
});
这为我们提供了一个WikipediaEditEvent
具有String
Keys的用户名。我们现在可以指定我们希望在此流上加上窗口,并根据这些窗口中的数据元计算结果。窗口指定要在其上执行计算的Stream片。在无限的数据元流上计算聚合时需要Windows。在我们的例子中,我们将说我们想要每五秒聚合一次编辑的字节总和:
DataStream<Tuple2<String, Long>> result = keyedEdits
.timeWindow(Time.seconds(5))
.fold(new Tuple2<>("", 0L), new FoldFunction<WikipediaEditEvent, Tuple2<String, Long>>() {
@Override
public Tuple2<String, Long> fold(Tuple2<String, Long> acc, WikipediaEditEvent event) {
acc.f0 = event.getUser();
acc.f1 += event.getByteDiff();
return acc;
}
});
第一个调用,.timeWindow()
指定我们想要有五秒钟的翻滚(非重叠)窗口。第二个调用为每个唯一键指定每个窗口切片的折叠变换。在我们的例子中,我们从一个初始值开始,("", 0L)
并在其中为用户添加该时间窗口中每个编辑的字节差异。生成的Stream现在包含Tuple2<String, Long>
每五秒钟发出一次的用户。
剩下要做的就是将流打印到控制台并开始执行:
result.print();
see.execute();
最后一次调用是启动实际Flink作业所必需的。所有 算子操作(例如创建源,转换和接收器)仅构建内部 算子操作的图形。只有在execute()
被调用时 才会在集群上抛出或在本地计算机上执行此 算子操作图。
到目前为止完整的代码是这样的:
package wikiedits;
import org.apache.flink.api.common.functions.FoldFunction;
import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.KeyedStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.connectors.wikiedits.WikipediaEditEvent;
import org.apache.flink.streaming.connectors.wikiedits.WikipediaEditsSource;
public class WikipediaAnalysis {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment see = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream<WikipediaEditEvent> edits = see.addSource(new WikipediaEditsSource());
KeyedStream<WikipediaEditEvent, String> keyedEdits = edits
.keyBy(new KeySelector<WikipediaEditEvent, String>() {
@Override
public String getKey(WikipediaEditEvent event) {
return event.getUser();
}
});
DataStream<Tuple2<String, Long>> result = keyedEdits
.timeWindow(Time.seconds(5))
.fold(new Tuple2<>("", 0L), new FoldFunction<WikipediaEditEvent, Tuple2<String, Long>>() {
@Override
public Tuple2<String, Long> fold(Tuple2<String, Long> acc, WikipediaEditEvent event) {
acc.f0 = event.getUser();
acc.f1 += event.getByteDiff();
return acc;
}
});
result.print();
see.execute();
}
}
您可以使用Maven在IDE或命令行上运行此示例:
$ mvn clean package
$ mvn exec:java -Dexec.mainClass=wikiedits.WikipediaAnalysis
第一个命令构建我们的项目,第二个命令执行我们的主类。输出应该类似于:
1> (Fenix down,114)
6> (AnomieBOT,155)
8> (BD2412bot,-3690)
7> (IgnorantArmies,49)
3> (Ckh3111,69)
5> (Slade360,0)
7> (Narutolovehinata5,2195)
6> (Vuyisa2001,79)
4> (Ms Sarah Welch,269)
4> (KasparBot,-245)
每行前面的数字告诉您输出生成的打印接收器的哪个并行实例。
这应该让您开始编写自己的Flink程序。要了解更多信息,您可以查看我们的基本概念指南和 DataStream API。如果您想了解如何在自己的机器上设置Flink群集并将结果写入Kafka,请坚持参加奖励练习。