Belajar Apache Flink - Advanced Streaming Patterns
Episode 17 of 23

Belajar Apache Flink - Advanced Streaming Patterns

Episode ini membahas pola-pola streaming lanjutan: stateful joins, stream-stream joins, dan temporal joins, hopping windows dan sessionization, iterative streaming dengan feedback loops, serta hybrid batch dan stream processing.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Episode-episode sebelumnya membangun kemampuan dasar yang kuat. Episode 17 ini menggabungkannya menjadi pola-pola tingkat lanjut yang muncul berulang kali di dunia nyata: menggabungkan dua stream, membangun sesi pengguna, memproses data secara iteratif, dan menyatukan batch dengan stream dalam satu pipeline.

Kita akan membahas stateful joins dalam tiga bentuk — window join, interval join, dan temporal join — lalu hopping windows dan sessionization, iterative streaming dengan feedback loops, serta hybrid batch dan stream processing. Ini episode yang membuat kalian "naik kelas" sebagai stream engineer.

Stream Joins

Window Join

Window join mencocokkan elemen dari dua stream yang berada dalam window yang sama:

Window join antara dua stream
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
 
orders.join(payments)
    .where(Order::getOrderId)
    .equalTo(Payment::getOrderId)
    .window(TumblingEventTimeWindows.of(Time.minutes(5)))
    .apply((order, payment) -> Tuple2.of(order, payment))
    .print();

.where(...).equalTo(...) menetapkan key join, dan .window membatasi kecocokan pada window yang sama. Ini pola paling sederhana untuk menggabungkan event dari dua sumber.

Interval Join

Interval join mencocokkan elemen berdasarkan waktu relatif, tanpa window yang kaku:

Interval join 30 menit sebelum-sesudah
import org.apache.flink.streaming.api.functions.co.ProcessJoinFunction;
import org.apache.flink.streaming.api.windowing.time.Time;
 
orders.keyBy(Order::getUserId)
    .intervalJoin(actions.keyBy(Action::getUserId))
    .between(Time.minutes(-30), Time.minutes(30))
    .process(new ProcessJoinFunction<Order, Action, JoinedRow>() {
        @Override
        public void processElement(
                Order order, Action action, Context ctx, Collector<JoinedRow> out) {
            out.collect(new JoinedRow(order, action));
        }
    });

.between membatasi kecocokan pada jendela waktu relatif terhadap event. Interval join menyimpan state kedua stream selama rentang waktu — pahami biaya state-nya saat stream ber-join sangat besar.

Temporal Join

Temporal join mencocokkan event stream dengan tabel dimensi yang berubah seiring waktu:

Temporal join di Flink SQL
SELECT o.order_id, o.amount, c.country
FROM orders o
JOIN customer_catalog FOR SYSTEM_TIME AS OF o.event_ts AS c
ON o.customer_id = c.id;

FOR SYSTEM_TIME AS OF o.event_ts mengambil versi dimensi yang valid pada saat event terjadi — bukan versi terbaru. Ini jawaban akurat untuk memperkaya event dengan data yang berubah.

Hopping Windows dan Sessionization

Hopping Window di SQL

Hopping window (sliding) diekspresikan dengan fungsi HOP:

Hopping window 10 menit dengan slide 5 menit
SELECT user_id, SUM(amount) AS total
FROM orders
GROUP BY user_id, HOP(event_ts, INTERVAL '5' MINUTE, INTERVAL '10' MINUTE);

HOP(event_ts, INTERVAL '5' MINUTE, INTERVAL '10' MINUTE) membuka window 10 menit setiap 5 menit — setiap event masuk ke dua window sekaligus.

Sessionization

Sessionization mengelompokkan aktivitas pengguna menjadi sesi berdasarkan gap waktu:

Sessionisasi aktivitas pengguna
SELECT user_id,
       SESSION_START(event_ts, INTERVAL '30' MINUTE) AS mulai,
       SESSION_END(event_ts, INTERVAL '30' MINUTE) AS selesai,
       COUNT(*) AS aktivitas
FROM clicks
GROUP BY user_id, SESSION(event_ts, INTERVAL '30' MINUTE);

SESSION_START dan SESSION_END memberi batas tiap sesi. Pola ini sangat umum untuk analitik produk: berapa lama pengguna bertahan, berapa aktivitas per sesi, dan kapan sesi paling sering terjadi.

Iterative Streaming dan Feedback Loops

Iterate untuk Komputasi Berulang

Beberapa algoritma membutuhkan pengulangan sampai konvergen — misalnya penghitungan PageRank. Flink menyediakan operator iterate:

Feedback loop dengan iterate
import org.apache.flink.streaming.api.datastream.IterativeStream;
 
IterativeStream<Long> iteration = numbers.iterate();
DataStream<Long> proses = iteration.map(step);
DataStream<Long> selesai = proses.filter(konvergen);
iteration.closeWith(proses.filter(belumKonvergen));
selesai.print();

iteration.closeWith mengirim hasil yang belum konvergen kembali ke awal iterasi, sedangkan filter konvergen mengeluarkan hasil akhir. Ingat: setiap putaran menambah latency, jadi gunakan hanya untuk komputasi yang benar-benar butuh umpan balik.

Batasan Feedback Loop

Feedback loop menghambat checkpoint dan membuat penjadwalan lebih rumit. Pertimbangkan alternatif: stateful processing dengan MapState, atau loop di luar Flink. Pahami bahwa kesederhanaan pipeline sering lebih berharga daripada kesempurnaan algoritma.

Hybrid Batch + Stream

Satu Model untuk Dua Jenis Data

Flink menawarkan pemrosesan batch dan stream dalam satu model pemrograman. DataSet API lama kini didepresiasi — arahnya adalah Table API yang berjalan baik untuk data bounded maupun unbounded.

Mode batch di Table API
import org.apache.flink.table.api.EnvironmentSettings;
import org.apache.flink.table.api.TableEnvironment;
 
EnvironmentSettings settings = EnvironmentSettings.inBatchMode();
TableEnvironment tableEnv = TableEnvironment.create(settings);
 
tableEnv.executeSql("SELECT user_id, SUM(amount) FROM orders_hist GROUP BY user_id").print();

inBatchMode() menjalankan query dengan semantik batch (hasil penuh saat query selesai). Kode yang sama bisa dijalankan dalam mode streaming — hanya context-nya yang berubah. Inilah kekuatan penyatuan model batch dan stream di Flink.

Penutup

Episode 17 memperluas repertoar kalian: window join, interval join, dan temporal join untuk menggabungkan data; hopping window dan sessionization untuk analitik berbasis waktu; iterative streaming untuk komputasi berulang; serta hybrid batch dan stream lewat Table API.

Inti yang harus dibawa pulang:

  • Window join membatasi kecocokan pada window; interval join pada jendela waktu relatif.
  • Temporal join mengambil versi dimensi yang valid saat event terjadi.
  • SESSION menggabungkan aktivitas pengguna menjadi sesi berdasarkan gap waktu.
  • Feedback loop memungkinkan komputasi iteratif dengan biaya latency dan kompleksitas.
  • Table API menjalankan kode yang sama untuk batch dan stream.

Di episode 18 selanjutnya kita akan membahas custom connectors & extensions — membuat custom source dan sink, memperluas Flink dengan serializer dan codec kustom, memahami operator lifecycle dan checkpoint hooks, hingga berkontribusi ke ekosistem connector. Kalian akan belajar membangun jembatan Flink ke sistem yang belum ada connector resminya.

Belajar Apache Flink - Advanced Streaming Patterns | Belajar Apache Flink