├── .gitignore
├── README.md
├── src
└── main
│ ├── java
│ └── io
│ │ └── github
│ │ └── streamingwithflink
│ │ ├── chapter5
│ │ ├── util
│ │ │ ├── SmokeLevel.java
│ │ │ ├── Alert.java
│ │ │ └── SmokeLevelSource.java
│ │ ├── RollingSum.java
│ │ ├── KeyedTransformations.java
│ │ ├── MultiStreamTransformations.java
│ │ └── BasicTransformations.java
│ │ ├── util
│ │ ├── SensorReading.java
│ │ ├── SensorTimeAssigner.java
│ │ └── SensorSource.java
│ │ ├── chapter1
│ │ └── AverageSensorReadings.java
│ │ └── chapter6
│ │ ├── CoProcessFunctionTimers.java
│ │ └── CustomWindow.java
│ └── resources
│ └── log4j.properties
├── pom.xml
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | dependency-reduced-pom.xml
3 | *iml
4 | .idea
5 | derby.log
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Java Examples for Stream Processing with Apache Flink
2 |
3 | This repository hosts Java code examples for ["Stream Processing with Apache Flink"](http://shop.oreilly.com/product/0636920057321.do) by [Fabian Hueske](https://twitter.com/fhueske) and [Vasia Kalavri](https://twitter.com/vkalavri).
4 |
5 | **Note:** The Java examples are not comlete yet.
6 | The [Scala examples](https://github.com/streaming-with-flink/examples-scala) are complete and we are working on translating them to Java.
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/main/java/io/github/streamingwithflink/chapter5/util/SmokeLevel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Fabian Hueske / Vasia Kalavri
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.github.streamingwithflink.chapter5.util;
17 |
18 | public enum SmokeLevel {
19 | LOW,
20 | HIGH
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | # Licensed to the Apache Software Foundation (ASF) under one
3 | # or more contributor license agreements. See the NOTICE file
4 | # distributed with this work for additional information
5 | # regarding copyright ownership. The ASF licenses this file
6 | # to you under the Apache License, Version 2.0 (the
7 | # "License"); you may not use this file except in compliance
8 | # with the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | ################################################################################
18 |
19 | log4j.rootLogger=INFO, console
20 |
21 | log4j.appender.console=org.apache.log4j.ConsoleAppender
22 | log4j.appender.console.layout=org.apache.log4j.PatternLayout
23 | log4j.appender.console.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p %-60c %x - %m%n
24 |
--------------------------------------------------------------------------------
/src/main/java/io/github/streamingwithflink/chapter5/util/Alert.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Fabian Hueske / Vasia Kalavri
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.github.streamingwithflink.chapter5.util;
17 |
18 | /**
19 | * POJO representing an alert.
20 | */
21 | public class Alert {
22 |
23 | public String message;
24 | public long timestamp;
25 |
26 | /**
27 | * Empty default constructor to comply with Flink's POJO requirements.
28 | */
29 | public Alert() { }
30 |
31 | public Alert(String message, long timestamp) {
32 | this.message = message;
33 | this.timestamp = timestamp;
34 | }
35 |
36 | public String toString() {
37 | return "(" + message + ", " + timestamp + ")";
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/io/github/streamingwithflink/util/SensorReading.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Fabian Hueske / Vasia Kalavri
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.github.streamingwithflink.util;
17 |
18 | /**
19 | * POJO to hold sensor reading data.
20 | */
21 | public class SensorReading {
22 |
23 | // id of the sensor
24 | public String id;
25 | // timestamp of the reading
26 | public long timestamp;
27 | // temperature value of the reading
28 | public double temperature;
29 |
30 | /**
31 | * Empty default constructor to satify Flink's POJO requirements.
32 | */
33 | public SensorReading() { }
34 |
35 | public SensorReading(String id, long timestamp, double temperature) {
36 | this.id = id;
37 | this.timestamp = timestamp;
38 | this.temperature = temperature;
39 | }
40 |
41 | public String toString() {
42 | return "(" + this.id + ", " + this.timestamp + ", " + this.temperature + ")";
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/io/github/streamingwithflink/util/SensorTimeAssigner.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Fabian Hueske / Vasia Kalavri
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.github.streamingwithflink.util;
17 |
18 | import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor;
19 | import org.apache.flink.streaming.api.windowing.time.Time;
20 |
21 | /**
22 | * Assigns timestamps to SensorReadings based on their internal timestamp and
23 | * emits watermarks with five seconds slack.
24 | */
25 | public class SensorTimeAssigner extends BoundedOutOfOrdernessTimestampExtractor {
26 |
27 | /**
28 | * Configures the extractor with 5 seconds out-of-order interval.
29 | */
30 | public SensorTimeAssigner() {
31 | super(Time.seconds(5));
32 | }
33 |
34 | /**
35 | * Extracts timestamp from SensorReading.
36 | *
37 | * @param r sensor reading
38 | * @return the timestamp of the sensor reading.
39 | */
40 | @Override
41 | public long extractTimestamp(SensorReading r) {
42 | return r.timestamp;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/io/github/streamingwithflink/chapter5/RollingSum.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Fabian Hueske / Vasia Kalavri
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.github.streamingwithflink.chapter5;
17 |
18 | import org.apache.flink.api.java.tuple.Tuple3;
19 | import org.apache.flink.streaming.api.datastream.DataStream;
20 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
21 |
22 | /**
23 | * Program demonstrating a rolling sum.
24 | */
25 | public class RollingSum {
26 |
27 | public static void main(String[] args) throws Exception {
28 |
29 | // set up the streaming execution environment
30 | StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
31 |
32 | DataStream> inputStream = env.fromElements(
33 | Tuple3.of(1, 2, 2), Tuple3.of(2, 3, 1), Tuple3.of(2, 2, 4), Tuple3.of(1, 5, 3));
34 |
35 | DataStream> resultStream = inputStream
36 | .keyBy(0) // key on first field of tuples
37 | .sum(1); // sum the second field of the tuple
38 |
39 | resultStream.print();
40 |
41 | // execute the application
42 | env.execute();
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/io/github/streamingwithflink/chapter5/util/SmokeLevelSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Fabian Hueske / Vasia Kalavri
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.github.streamingwithflink.chapter5.util;
17 |
18 | import org.apache.flink.streaming.api.functions.source.SourceFunction;
19 |
20 | import java.util.Random;
21 |
22 | /**
23 | * Flink SourceFunction to generate random SmokeLevel events.
24 | */
25 | public class SmokeLevelSource implements SourceFunction {
26 |
27 | // flag indicating whether source is still running
28 | private boolean running = true;
29 |
30 | /**
31 | * Continuously emit one smoke level event per second.
32 | */
33 | @Override
34 | public void run(SourceContext srcCtx) throws Exception {
35 |
36 | // initialize random number generator
37 | Random rand = new Random();
38 |
39 | // emit data until being canceled
40 | while (running) {
41 |
42 | if (rand.nextGaussian() > 0.8) {
43 | // emit a high SmokeLevel
44 | srcCtx.collect(SmokeLevel.HIGH);
45 | } else {
46 | srcCtx.collect(SmokeLevel.LOW);
47 | }
48 |
49 | // wait for 1 second
50 | Thread.sleep(1000);
51 | }
52 | }
53 |
54 | /**
55 | * Cancel the emission of smoke level events.
56 | */
57 | @Override
58 | public void cancel() {
59 | this.running = false;
60 |
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/io/github/streamingwithflink/chapter5/KeyedTransformations.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Fabian Hueske / Vasia Kalavri
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.github.streamingwithflink.chapter5;
17 |
18 | import io.github.streamingwithflink.util.SensorReading;
19 | import io.github.streamingwithflink.util.SensorSource;
20 | import io.github.streamingwithflink.util.SensorTimeAssigner;
21 | import org.apache.flink.streaming.api.TimeCharacteristic;
22 | import org.apache.flink.streaming.api.datastream.DataStream;
23 | import org.apache.flink.streaming.api.datastream.KeyedStream;
24 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
25 |
26 | /**
27 | * Example program to demonstrate keyed transformation functions: keyBy, reduce.
28 | */
29 | public class KeyedTransformations {
30 |
31 | public static void main(String[] args) throws Exception {
32 |
33 | // set up the streaming execution environment
34 | StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
35 |
36 | // use event time for the application
37 | env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
38 | // configure watermark interval
39 | env.getConfig().setAutoWatermarkInterval(1000L);
40 |
41 | // ingest sensor stream
42 | DataStream readings = env
43 | // SensorSource generates random temperature readings
44 | .addSource(new SensorSource())
45 | // assign timestamps and watermarks which are required for event time
46 | .assignTimestampsAndWatermarks(new SensorTimeAssigner());
47 |
48 | // group sensor readings by sensor id
49 | KeyedStream keyed = readings
50 | .keyBy(r -> r.id);
51 |
52 | // a rolling reduce that computes the highest temperature of each sensor and
53 | // the corresponding timestamp
54 | DataStream maxTempPerSensor = keyed
55 | .reduce((r1, r2) -> {
56 | if (r1.temperature > r2.temperature) {
57 | return r1;
58 | } else {
59 | return r2;
60 | }
61 | });
62 |
63 | maxTempPerSensor.print();
64 |
65 | // execute application
66 | env.execute("Keyed Transformations Example");
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/io/github/streamingwithflink/util/SensorSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Fabian Hueske / Vasia Kalavri
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.github.streamingwithflink.util;
17 |
18 | import org.apache.flink.streaming.api.functions.source.RichParallelSourceFunction;
19 |
20 | import java.util.Calendar;
21 | import java.util.Random;
22 |
23 | /**
24 | * Flink SourceFunction to generate SensorReadings with random temperature values.
25 | *
26 | * Each parallel instance of the source simulates 10 sensors which emit one sensor reading every 100 ms.
27 | *
28 | * Note: This is a simple data-generating source function that does not checkpoint its state.
29 | * In case of a failure, the source does not replay any data.
30 | */
31 | public class SensorSource extends RichParallelSourceFunction {
32 |
33 | // flag indicating whether source is still running
34 | private boolean running = true;
35 |
36 | /** run() continuously emits SensorReadings by emitting them through the SourceContext. */
37 | @Override
38 | public void run(SourceContext srcCtx) throws Exception {
39 |
40 | // initialize random number generator
41 | Random rand = new Random();
42 | // look up index of this parallel task
43 | int taskIdx = this.getRuntimeContext().getIndexOfThisSubtask();
44 |
45 | // initialize sensor ids and temperatures
46 | String[] sensorIds = new String[10];
47 | double[] curFTemp = new double[10];
48 | for (int i = 0; i < 10; i++) {
49 | sensorIds[i] = "sensor_" + (taskIdx * 10 + i);
50 | curFTemp[i] = 65 + (rand.nextGaussian() * 20);
51 | }
52 |
53 | while (running) {
54 |
55 | // get current time
56 | long curTime = Calendar.getInstance().getTimeInMillis();
57 |
58 | // emit SensorReadings
59 | for (int i = 0; i < 10; i++) {
60 | // update current temperature
61 | curFTemp[i] += rand.nextGaussian() * 0.5;
62 | // emit reading
63 | srcCtx.collect(new SensorReading(sensorIds[i], curTime, curFTemp[i]));
64 | }
65 |
66 | // wait for 100 ms
67 | Thread.sleep(100);
68 | }
69 | }
70 |
71 | /** Cancels this SourceFunction. */
72 | @Override
73 | public void cancel() {
74 | this.running = false;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/io/github/streamingwithflink/chapter1/AverageSensorReadings.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Fabian Hueske / Vasia Kalavri
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.github.streamingwithflink.chapter1;
17 |
18 | import io.github.streamingwithflink.util.SensorReading;
19 | import io.github.streamingwithflink.util.SensorSource;
20 | import io.github.streamingwithflink.util.SensorTimeAssigner;
21 | import org.apache.flink.streaming.api.TimeCharacteristic;
22 | import org.apache.flink.streaming.api.datastream.DataStream;
23 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
24 | import org.apache.flink.streaming.api.functions.windowing.WindowFunction;
25 | import org.apache.flink.streaming.api.windowing.time.Time;
26 | import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
27 | import org.apache.flink.util.Collector;
28 |
29 | public class AverageSensorReadings {
30 |
31 | /**
32 | * main() defines and executes the DataStream program.
33 | *
34 | * @param args program arguments
35 | * @throws Exception
36 | */
37 | public static void main(String[] args) throws Exception {
38 |
39 | // set up the streaming execution environment
40 | StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
41 |
42 | // use event time for the application
43 | env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
44 | // configure watermark interval
45 | env.getConfig().setAutoWatermarkInterval(1000L);
46 |
47 | // ingest sensor stream
48 | DataStream sensorData = env
49 | // SensorSource generates random temperature readings
50 | .addSource(new SensorSource())
51 | // assign timestamps and watermarks which are required for event time
52 | .assignTimestampsAndWatermarks(new SensorTimeAssigner());
53 |
54 | DataStream avgTemp = sensorData
55 | // convert Fahrenheit to Celsius using and inlined map function
56 | .map( r -> new SensorReading(r.id, r.timestamp, (r.temperature - 32) * (5.0 / 9.0)))
57 | // organize stream by sensor
58 | .keyBy(r -> r.id)
59 | // group readings in 1 second windows
60 | .timeWindow(Time.seconds(1))
61 | // compute average temperature using a user-defined function
62 | .apply(new TemperatureAverager());
63 |
64 | // print result stream to standard out
65 | avgTemp.print();
66 |
67 | // execute application
68 | env.execute("Compute average sensor temperature");
69 | }
70 |
71 | /**
72 | * User-defined WindowFunction to compute the average temperature of SensorReadings
73 | */
74 | public static class TemperatureAverager implements WindowFunction {
75 |
76 | /**
77 | * apply() is invoked once for each window.
78 | *
79 | * @param sensorId the key (sensorId) of the window
80 | * @param window meta data for the window
81 | * @param input an iterable over the collected sensor readings that were assigned to the window
82 | * @param out a collector to emit results from the function
83 | */
84 | @Override
85 | public void apply(String sensorId, TimeWindow window, Iterable input, Collector out) {
86 |
87 | // compute the average temperature
88 | int cnt = 0;
89 | double sum = 0.0;
90 | for (SensorReading r : input) {
91 | cnt++;
92 | sum += r.temperature;
93 | }
94 | double avgTemp = sum / cnt;
95 |
96 | // emit a SensorReading with the average temperature
97 | out.collect(new SensorReading(sensorId, window.getEnd(), avgTemp));
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/main/java/io/github/streamingwithflink/chapter5/MultiStreamTransformations.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Fabian Hueske / Vasia Kalavri
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.github.streamingwithflink.chapter5;
17 |
18 | import io.github.streamingwithflink.chapter5.util.Alert;
19 | import io.github.streamingwithflink.chapter5.util.SmokeLevel;
20 | import io.github.streamingwithflink.chapter5.util.SmokeLevelSource;
21 | import io.github.streamingwithflink.util.SensorReading;
22 | import io.github.streamingwithflink.util.SensorSource;
23 | import io.github.streamingwithflink.util.SensorTimeAssigner;
24 | import org.apache.flink.streaming.api.TimeCharacteristic;
25 | import org.apache.flink.streaming.api.datastream.DataStream;
26 | import org.apache.flink.streaming.api.datastream.KeyedStream;
27 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
28 | import org.apache.flink.streaming.api.functions.co.CoFlatMapFunction;
29 | import org.apache.flink.util.Collector;
30 |
31 | /**
32 | * A simple application that outputs an alert whenever there is a high risk of fire.
33 | * The application receives the stream of temperature sensor readings and a stream of smoke level measurements.
34 | * When the temperature is over a given threshold and the smoke level is high, we emit a fire alert.
35 | */
36 | public class MultiStreamTransformations {
37 |
38 | public static void main(String[] args) throws Exception {
39 |
40 | // set up the streaming execution environment
41 | StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
42 |
43 | // use event time for the application
44 | env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
45 | // configure watermark interval
46 | env.getConfig().setAutoWatermarkInterval(1000L);
47 |
48 | // ingest sensor stream
49 | DataStream tempReadings = env
50 | // SensorSource generates random temperature readings
51 | .addSource(new SensorSource())
52 | // assign timestamps and watermarks which are required for event time
53 | .assignTimestampsAndWatermarks(new SensorTimeAssigner());
54 |
55 | // ingest smoke level stream
56 | DataStream smokeReadings = env
57 | .addSource(new SmokeLevelSource())
58 | .setParallelism(1);
59 |
60 | // group sensor readings by sensor id
61 | KeyedStream keyedTempReadings = tempReadings
62 | .keyBy(r -> r.id);
63 |
64 | // connect the two streams and raise an alert if the temperature and
65 | // smoke levels are high
66 | DataStream alerts = keyedTempReadings
67 | .connect(smokeReadings.broadcast())
68 | .flatMap(new RaiseAlertFlatMap());
69 |
70 | alerts.print();
71 |
72 | // execute the application
73 | env.execute("Multi-Stream Transformations Example");
74 | }
75 |
76 | /**
77 | * A CoFlatMapFunction that processes a stream of temperature readings ans a control stream
78 | * of smoke level events. The control stream updates a shared variable with the current smoke level.
79 | * For every event in the sensor stream, if the temperature reading is above 100 degrees
80 | * and the smoke level is high, a "Risk of fire" alert is generated.
81 | */
82 | public static class RaiseAlertFlatMap implements CoFlatMapFunction {
83 |
84 | private SmokeLevel smokeLevel = SmokeLevel.LOW;
85 |
86 | @Override
87 | public void flatMap1(SensorReading tempReading, Collector out) throws Exception {
88 | // high chance of fire => true
89 | if (this.smokeLevel == SmokeLevel.HIGH && tempReading.temperature > 100) {
90 | out.collect(new Alert("Risk of fire! " + tempReading, tempReading.timestamp));
91 | }
92 | }
93 |
94 | @Override
95 | public void flatMap2(SmokeLevel smokeLevel, Collector out) {
96 | // update smoke level
97 | this.smokeLevel = smokeLevel;
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/main/java/io/github/streamingwithflink/chapter5/BasicTransformations.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Fabian Hueske / Vasia Kalavri
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.github.streamingwithflink.chapter5;
17 |
18 | import io.github.streamingwithflink.util.SensorReading;
19 | import io.github.streamingwithflink.util.SensorSource;
20 | import io.github.streamingwithflink.util.SensorTimeAssigner;
21 | import org.apache.flink.api.common.functions.FilterFunction;
22 | import org.apache.flink.api.common.functions.FlatMapFunction;
23 | import org.apache.flink.api.common.functions.MapFunction;
24 | import org.apache.flink.api.common.typeinfo.Types;
25 | import org.apache.flink.streaming.api.TimeCharacteristic;
26 | import org.apache.flink.streaming.api.datastream.DataStream;
27 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
28 | import org.apache.flink.util.Collector;
29 |
30 | /**
31 | * Example program to demonstrate simple transformation functions: filter, map, and flatMap.
32 | */
33 | public class BasicTransformations {
34 |
35 | public static void main(String[] args) throws Exception {
36 |
37 | // set up the streaming execution environment
38 | StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
39 |
40 | // use event time for the application
41 | env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
42 | // configure watermark interval
43 | env.getConfig().setAutoWatermarkInterval(1000L);
44 |
45 | // ingest sensor stream
46 | DataStream readings = env
47 | // SensorSource generates random temperature readings
48 | .addSource(new SensorSource())
49 | // assign timestamps and watermarks which are required for event time
50 | .assignTimestampsAndWatermarks(new SensorTimeAssigner());
51 |
52 | // filter out sensor measurements with temperature below 25 degrees
53 | DataStream filteredReadings = readings
54 | .filter(r -> r.temperature >= 25);
55 |
56 | // the above filter transformation using a FilterFunction instead of a lambda function
57 | // DataStream filteredReadings = readings
58 | // .filter(new TemperatureFilter(25));
59 |
60 | // project the reading to the id of the sensor
61 | DataStream sensorIds = filteredReadings
62 | .map(r -> r.id);
63 |
64 | // the above map transformation using a MapFunction instead of a lambda function
65 | // DataStream sensorIds = filteredReadings
66 | // .map(new IdExtractor());
67 |
68 | // split the String id of each sensor to the prefix "sensor" and sensor number
69 | DataStream splitIds = sensorIds
70 | .flatMap((FlatMapFunction)
71 | (id, out) -> { for (String s: id.split("_")) { out.collect(s);}})
72 | // provide result type because Java cannot infer return type of lambda function
73 | .returns(Types.STRING);
74 |
75 | // the above flatMap transformation using a FlatMapFunction instead of a lambda function
76 | // DataStream splitIds = sensorIds
77 | // .flatMap(new IdSplitter());
78 |
79 | // print result stream to standard out
80 | splitIds.print();
81 |
82 | // execute application
83 | env.execute("Basic Transformations Example");
84 | }
85 |
86 | /**
87 | * User-defined FilterFunction to filter out SensorReading with temperature below the threshold.
88 | */
89 | public static class TemperatureFilter implements FilterFunction {
90 |
91 | private final double threshold;
92 |
93 | public TemperatureFilter(double threshold) {
94 | this.threshold = threshold;
95 | }
96 |
97 | @Override
98 | public boolean filter(SensorReading r) {
99 | return r.temperature >= threshold;
100 | }
101 | }
102 |
103 | /**
104 | * User-defined MapFunction to extract a reading's sensor id.
105 | */
106 | public static class IdExtractor implements MapFunction {
107 |
108 | @Override
109 | public String map(SensorReading r) throws Exception {
110 | return r.id;
111 | }
112 | }
113 |
114 | /**
115 | * User-defined FlatMapFunction that splits a sensor's id String into a prefix and a number.
116 | */
117 | public static class IdSplitter implements FlatMapFunction {
118 |
119 | @Override
120 | public void flatMap(String id, Collector out) {
121 |
122 | String[] splits = id.split("_");
123 |
124 | for (String split : splits) {
125 | out.collect(split);
126 | }
127 | }
128 | }
129 |
130 | }
131 |
--------------------------------------------------------------------------------
/src/main/java/io/github/streamingwithflink/chapter6/CoProcessFunctionTimers.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Fabian Hueske / Vasia Kalavri
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.github.streamingwithflink.chapter6;
17 |
18 | import io.github.streamingwithflink.util.SensorReading;
19 | import io.github.streamingwithflink.util.SensorSource;
20 | import org.apache.flink.api.common.state.ValueState;
21 | import org.apache.flink.api.common.state.ValueStateDescriptor;
22 | import org.apache.flink.api.common.typeinfo.Types;
23 | import org.apache.flink.api.java.tuple.Tuple2;
24 | import org.apache.flink.configuration.Configuration;
25 | import org.apache.flink.streaming.api.TimeCharacteristic;
26 | import org.apache.flink.streaming.api.datastream.DataStream;
27 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
28 | import org.apache.flink.streaming.api.functions.co.CoProcessFunction;
29 | import org.apache.flink.util.Collector;
30 |
31 | /**
32 | * This example shows how to use a CoProcessFunction and Timers.
33 | */
34 | public class CoProcessFunctionTimers {
35 |
36 | public static void main(String[] args) throws Exception {
37 |
38 | // set up the streaming execution environment
39 | StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
40 |
41 | // use event time for the application
42 | env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime);
43 |
44 | // switch messages disable filtering of sensor readings for a specific amount of time
45 | DataStream> filterSwitches = env
46 | .fromElements(
47 | // forward readings of sensor_2 for 10 seconds
48 | Tuple2.of("sensor_2", 10_000L),
49 | // forward readings of sensor_7 for 1 minute
50 | Tuple2.of("sensor_7", 60_000L));
51 |
52 | // ingest sensor stream
53 | DataStream readings = env
54 | // SensorSource generates random temperature readings
55 | .addSource(new SensorSource());
56 |
57 | DataStream forwardedReadings = readings
58 | // connect readings and switches
59 | .connect(filterSwitches)
60 | // key by sensor ids
61 | .keyBy(r -> r.id, s -> s.f0)
62 | // apply filtering CoProcessFunction
63 | .process(new ReadingFilter());
64 |
65 | forwardedReadings.print();
66 |
67 | env.execute("Filter sensor readings");
68 | }
69 |
70 | public static class ReadingFilter extends CoProcessFunction, SensorReading> {
71 |
72 | // switch to enable forwarding
73 | private ValueState forwardingEnabled;
74 | // timestamp to disable the currently active timer
75 | private ValueState disableTimer;
76 |
77 | @Override
78 | public void open(Configuration parameters) throws Exception {
79 | forwardingEnabled = getRuntimeContext().getState(
80 | new ValueStateDescriptor<>("filterSwitch", Types.BOOLEAN));
81 | disableTimer = getRuntimeContext().getState(
82 | new ValueStateDescriptor("timer", Types.LONG));
83 | }
84 |
85 | @Override
86 | public void processElement1(SensorReading r, Context ctx, Collector out) throws Exception {
87 | // check if we need to forward the reading
88 | Boolean forward = forwardingEnabled.value();
89 | if (forward != null && forward) {
90 | out.collect(r);
91 | }
92 | }
93 |
94 | @Override
95 | public void processElement2(Tuple2 s, Context ctx, Collector out) throws Exception {
96 | // enable forwarding of readings
97 | forwardingEnabled.update(true);
98 | // set timer to disable switch
99 | long timerTimestamp = ctx.timerService().currentProcessingTime() + s.f1;
100 | Long curTimerTimestamp = disableTimer.value();
101 | if (curTimerTimestamp == null || timerTimestamp > curTimerTimestamp) {
102 | // remove current timer
103 | if (curTimerTimestamp != null) {
104 | ctx.timerService().deleteProcessingTimeTimer(curTimerTimestamp);
105 | }
106 | // register new timer
107 | ctx.timerService().registerProcessingTimeTimer(timerTimestamp);
108 | disableTimer.update(timerTimestamp);
109 | }
110 | }
111 |
112 | @Override
113 | public void onTimer(long ts, OnTimerContext ctx, Collector out) throws Exception {
114 | // remove all state
115 | forwardingEnabled.clear();
116 | disableTimer.clear();
117 | }
118 | }
119 | }
120 |
121 |
122 |
--------------------------------------------------------------------------------
/src/main/java/io/github/streamingwithflink/chapter6/CustomWindow.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Fabian Hueske / Vasia Kalavri
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.github.streamingwithflink.chapter6;
17 |
18 | import io.github.streamingwithflink.util.SensorReading;
19 | import io.github.streamingwithflink.util.SensorSource;
20 | import io.github.streamingwithflink.util.SensorTimeAssigner;
21 | import org.apache.flink.api.common.ExecutionConfig;
22 | import org.apache.flink.api.common.state.ValueState;
23 | import org.apache.flink.api.common.state.ValueStateDescriptor;
24 | import org.apache.flink.api.common.typeinfo.Types;
25 | import org.apache.flink.api.common.typeutils.TypeSerializer;
26 | import org.apache.flink.api.java.tuple.Tuple4;
27 | import org.apache.flink.streaming.api.TimeCharacteristic;
28 | import org.apache.flink.streaming.api.datastream.DataStream;
29 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
30 | import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction;
31 | import org.apache.flink.streaming.api.windowing.assigners.WindowAssigner;
32 | import org.apache.flink.streaming.api.windowing.triggers.EventTimeTrigger;
33 | import org.apache.flink.streaming.api.windowing.triggers.Trigger;
34 | import org.apache.flink.streaming.api.windowing.triggers.TriggerResult;
35 | import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
36 | import org.apache.flink.util.Collector;
37 |
38 | import java.util.Collection;
39 | import java.util.Collections;
40 |
41 | public class CustomWindow {
42 |
43 | public static void main(String[] args) throws Exception {
44 |
45 | // set up the streaming execution environment
46 | StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
47 |
48 | // checkpoint every 10 seconds
49 | env.getCheckpointConfig().setCheckpointInterval(10_000);
50 |
51 | // use event time for the application
52 | env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
53 | // configure watermark interval
54 | env.getConfig().setAutoWatermarkInterval(1000L);
55 |
56 | // ingest sensor stream
57 | DataStream sensorData = env
58 | // SensorSource generates random temperature readings
59 | .addSource(new SensorSource())
60 | // assign timestamps and watermarks which are required for event time
61 | .assignTimestampsAndWatermarks(new SensorTimeAssigner());
62 |
63 | DataStream> countsPerThirtySecs = sensorData
64 | .keyBy(r -> r.id)
65 | // a custom window assigner for 30 seconds tumbling windows
66 | .window(new ThirtySecondsWindows())
67 | // a custom trigger that fires early (at most) every second
68 | .trigger(new OneSecondIntervalTrigger())
69 | // count readings per window
70 | .process(new CountFunction());
71 |
72 | countsPerThirtySecs.print();
73 |
74 | env.execute("Run custom window example");
75 | }
76 |
77 | /**
78 | * A custom window that groups events in to 30 second tumbling windows.
79 | */
80 | public static class ThirtySecondsWindows extends WindowAssigner