本教程主要来自flink1.9教程
在本指南中,我们将从头开始,从设置Flink项目到在Flink集群上运行流分析程序。
Wikipedia提供了一个IRC频道,其中记录了对Wiki的所有编辑。我们将在Flink中读取此通道,并计算每个用户在给定时间窗口内编辑的字节数。这很容易使用Flink在几分钟内实现,但它将为您提供一个良好的基础,从而开始自己构建更复杂的分析程序。
我们将使用Flink Maven Archetype创建项目结构。更多详细信息,请查看 Java API Quickstart,出于我们的目的,运行命令:
$ mvn archetype:generate \
-DarchetypeGroupId=org.apache.flink \
-DarchetypeArtifactId=flink-quickstart-java \
-DarchetypeVersion=1.9.0 \
-DgroupId=wiki-edits \
-DartifactId=wiki-edits \
-Dversion=0.1 \
-Dpackage=wikiedits \
-DinteractiveMode=false
你可以编辑groupId
, artifactId
和 package,使用上面的参数,Maven将要创建以下的项目结构:
$ tree wiki-edits
wiki-edits/
├── pom.xml
└── src
└── main
├── java
│ └── wikiedits
│ ├── BatchJob.java
│ └── StreamingJob.java
└── resources
└── log4j.properties
我们的pom.xml文件已经在根目录中添加了Flink依赖项,并且在src/main/java下有几个flink项目实例。我们可以删除示例程序,因为我们将从头开始:
$ rm wiki-edits/src/main/java/wikiedits/*.java
最后,我们需要将Flink Wikipedia连接器添加为依赖关系,以便我们可以在我们的程序中使用它。编辑pom.xml的dependencies
部分,使它看起来像这样:
org.apache.flink
flink-java
${flink.version}
org.apache.flink
flink-streaming-java_2.11
${flink.version}
org.apache.flink
flink-clients_2.11
${flink.version}
org.apache.flink
flink-connector-wikiedits_2.11
${flink.version}
注意flink-connector-wikiedits_2.11依赖项被添加。(此示例和Wikipedia连接器的来自Apache Samza 的Hello Samza示例的启发。)
启动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如果您处理批处理job)。这可用于设置执行参数并创建从外部系统读取的源。所以让我们开始把它添加到main方法:
StreamExecutionEnvironment see = StreamExecutionEnvironment.getExecutionEnvironment();
接下来创建从Wikipedia IRC日志读取的source:
DataStream edits = see.addSource(new WikipediaEditsSource());
这创建了一个我们可以进一步处理WikipediaEditEvent的
数据流。出于本示例的目的,我们感兴趣的是确定每个用户在特定时间窗口中添加或删除的字节数,比如说五秒。为此,我们首先必须指定我们要在用户名上键入流,也就是说此流上的 算子操作应考虑用户名。在我们的例子中,窗口中编辑的字节的总和应该是每个唯一的用户。对于键入流,我们必须提供一个KeySelector
,如下所示:
KeyedStream keyedEdits = edits
.keyBy(new KeySelector() {
@Override
public String getKey(WikipediaEditEvent event) {
return event.getUser();
}
});
这为我们提供了一个流式WikipediaEditEvent
具有String
Key的用户名。我们现在可以指定我们希望在此流上加上窗口,并根据这些窗口中的数据元计算结果。窗口指定要在其上执行计算的Stream片。在无限的数据元流上计算聚合时需要Windows。在我们的例子中,我们想要每五秒聚合一次编辑的字节总和:
DataStream> result = keyedEdits
.timeWindow(Time.seconds(5))
.aggregate(new AggregateFunction, Tuple2>() {
@Override
public Tuple2 createAccumulator() {
return new Tuple2<>("", 0L);
}
@Override
public Tuple2 add(WikipediaEditEvent value, Tuple2 accumulator) {
accumulator.f0 = value.getUser();
accumulator.f1 += value.getByteDiff();
return accumulator;
}
@Override
public Tuple2 getResult(Tuple2 accumulator) {
return accumulator;
}
@Override
public Tuple2 merge(Tuple2 a, Tuple2 b) {
return new Tuple2<>(a.f0, a.f1 + b.f1);
}
});
第一个调用,.timeWindow()
指定我们想要有五秒钟的翻滚(非重叠)窗口。第二个调用为每个唯一键指定每个窗口切片的折叠变换。在我们的例子中,我们从一个初始值开始,("", 0L),
并在其中为用户添加该时间窗口中每个编辑的字节差异。生成的Stream现在包含Tuple2
每五秒钟发出一次的用户。
剩下要做的就是将流打印到控制台并开始执行:
result.print();
see.execute();
最后的调用是启动实际Flink作业所必需的。所有操作(例如创建源,转换和接收器仅构建内部算子操作的图形。只有在execute()
被调用时才会在集群上抛出或在本地计算机上执行此算子操作图。
到目前为止完整的代码是这样的:
package wikiedits;
import org.apache.flink.api.common.functions.AggregateFunction;
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 edits = see.addSource(new WikipediaEditsSource());
KeyedStream keyedEdits = edits
.keyBy(new KeySelector() {
@Override
public String getKey(WikipediaEditEvent event) {
return event.getUser();
}
});
DataStream> result = keyedEdits
.timeWindow(Time.seconds(5))
.aggregate(new AggregateFunction, Tuple2>() {
@Override
public Tuple2 createAccumulator() {
return new Tuple2<>("", 0L);
}
@Override
public Tuple2 add(WikipediaEditEvent value, Tuple2 accumulator) {
accumulator.f0 = value.getUser();
accumulator.f1 += value.getByteDiff();
return accumulator;
}
@Override
public Tuple2 getResult(Tuple2 accumulator) {
return accumulator;
}
@Override
public Tuple2 merge(Tuple2 a, Tuple2 b) {
return new Tuple2<>(a.f0, a.f1 + b.f1);
}
});
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,请坚持参加练习。