Untuk setiap data streaming, Anda dapat menggabungkannya dengan sumber data tabel dimensi eksternal. Realtime Compute for Apache Flink menggunakan kemampuan ini untuk memperkaya aliran dengan data dimensi.
Ikhtisar JOIN tabel dimensi
JOIN tabel dimensi (juga disebut Lookup Join) melakukan kueri terhadap tabel dimensi eksternal pada waktu pemrosesan untuk setiap data aliran dan memperkaya aliran utama dengan kolom dimensi. JOIN ini umumnya digunakan untuk menambahkan informasi kamus atau dimensi ke aliran event.
Aspek utama JOIN tabel dimensi:
-
Sintaksis: Gunakan
FOR SYSTEM_TIME AS OF PROCTIME()untuk menunjukkan bahwa setiap baris aliran utama melakukan kueri terhadap data terkini dari tabel dimensi pada waktu pemrosesan, bukan snapshot. -
Strategi cache: Cache data dimensi di lapisan konektor untuk mengurangi tekanan pada sistem eksternal.
-
Perilaku lookup: Gunakan petunjuk LOOKUP untuk mengonfigurasi mode sinkron/asinkron, kapasitas buffer, strategi pengulangan, dan sebagainya.
-
Strategi join fisik: Gunakan petunjuk seperti SHUFFLE_HASH untuk mengontrol perilaku shuffle dan mengurangi kesenjangan data.
-
Konfigurasi tingkat pekerjaan: Gunakan perintah SET untuk menyesuaikan parameter global dalam family
table.exec.*.
Sintaksis JOIN tabel dimensi
SELECT column-names
FROM table1 [AS <alias1>]
[LEFT] JOIN table2 FOR SYSTEM_TIME AS OF PROCTIME() [AS <alias2>]
ON table1.column-name1 = table2.key-name1;
-
FOR SYSTEM_TIME AS OF PROCTIME()wajib digunakan. Petunjuk ini menginstruksikan engine untuk menggabungkan setiap baris aliran utama dengan snapshot tabel dimensi berdasarkan waktu pemrosesan saat ini. -
Klausa ON harus berisi kondisi kesetaraan pada kolom yang dapat dilookup secara acak oleh tabel dimensi.
-
Dalam klausa ON, Anda dapat menerapkan fungsi konversi tipe seperti CAST pada kolom tabel sumber. Jika tipe kolom sumber dan dimensi tidak sesuai, ubah tipe kolom sumber agar sesuai dengan tipe kolom dimensi.
Batasan dan pertimbangan
-
JOIN tabel dimensi hanya mendukung penggabungan terhadap snapshot terkini dari tabel dimensi.
-
Tabel dimensi hanya mendukung INNER JOIN dan LEFT JOIN. RIGHT JOIN dan FULL JOIN tidak didukung.
-
Untuk join satu-ke-satu, pastikan kondisi join berisi predikat kesetaraan pada kolom yang unik dalam tabel dimensi.
-
Untuk setiap data streaming, join hanya melihat versi terbaru dari tabel dimensi pada waktu pemrosesan. Setelah join dilakukan, perubahan berikutnya (penyisipan, pembaruan, atau penghapusan) pada data dimensi tidak akan diteruskan ke baris yang telah digabungkan. Untuk perilaku spesifik per konektor, lihat dokumentasi konektor yang sesuai.
Strategi cache tabel dimensi
Sebagian besar konektor mendukung strategi cache untuk JOIN tabel dimensi. Dukungan sedikit berbeda antar-konektor—lihat dokumentasi konektor yang sesuai untuk detailnya. Strategi cache umum adalah:
|
Strategi |
Perilaku |
|
None (default) |
Tidak ada caching. |
|
LRU |
Menyimpan sebagian data tabel dimensi dalam cache. Setiap baris dari aliran sumber terlebih dahulu mencari di cache; jika terjadi cache miss, engine melakukan kueri ke tabel dimensi fisik. |
|
ALL |
Menyimpan seluruh tabel dimensi dalam cache. Sebelum pekerjaan dimulai, engine memuat semua baris ke dalam cache; setiap lookup berikutnya dilayani dari cache, dan cache miss berarti kunci tersebut tidak ada. Opsi spesifik konektor mengontrol pemuatan ulang berkala atau terjadwal dari tabel dimensi. Strategi ini cocok untuk tabel dimensi kecil yang tidak memerlukan pembaruan sering dan membutuhkan throughput maksimum. |
-
Pilih antara kesegaran dan performa berdasarkan kebutuhan bisnis Anda. Jika kesegaran sangat penting, Anda dapat menonaktifkan caching dan membaca langsung dari tabel dimensi.
-
Jika caching diaktifkan, kombinasikan LRU dengan TTL untuk menjaga kesegaran data cache. TTL dapat diatur ke nilai pendek—misalnya beberapa detik hingga puluhan detik—sehingga cache diperbarui secara berkala dari sumber.
-
Saat menggunakan strategi ALL, pantau penggunaan memori node secara hati-hati untuk menghindari OOM.
-
Dengan strategi ALL, engine memuat data dimensi secara asinkron, sehingga Anda harus meningkatkan memori node JOIN dimensi. Sebagai aturan praktis, naikkan hingga dua kali ukuran data tabel dimensi remote.
Penyetelan JOIN tabel dimensi
Kategori parameter penyetelan dan cara meneruskannya
Penyetelan JOIN tabel dimensi melibatkan tiga kategori parameter. Setiap kategori memiliki cara tersendiri untuk diteruskan, dan menggunakan mekanisme yang salah menyebabkan petunjuk diabaikan tanpa peringatan.
|
Kategori |
Parameter umum |
Cara lulus |
Lingkup |
|
Konektor dengan Opsi |
|
Atur dalam klausa |
Tabel tunggal |
|
Opsi petunjuk LOOKUP |
|
|
Operasi join tunggal |
|
TableConfig Tingkat Pekerjaan Flink |
Konfigurasi global yang kuncinya diawali dengan |
Jalankan |
Seluruh pekerjaan |
-
Petunjuk
OPTIONS()hanya menimpa opsi yang diterima konektor dalam klausa WITH. Petunjuk ini tidak menerima kunci TableConfigtable.exec.*—kunci yang tidak valid akan diabaikan tanpa peringatan. -
Petunjuk
LOOKUP()hanya mengenali kunci tetap yang tercantum dalam tabel di atas. Petunjuk ini tidak menerima kunci konfigurasi Flink lengkap. Misalnya, untuk menyesuaikan buffer lookup asinkron, Anda harus menulis'capacity'='100'; menulis'table.exec.async-lookup.buffer-capacity'='100'tidak berpengaruh. -
Untuk mengubah parameter global yang tidak tersedia melalui petunjuk apa pun, gunakan
SET 'xxx' = 'yyy';.
Timpa opsi konektor dengan petunjuk OPTIONS
Petunjuk OPTIONS() memungkinkan Anda menimpa opsi WITH suatu tabel langsung dalam kueri, tanpa mengubah pernyataan CREATE TABLE. Petunjuk ini umumnya digunakan untuk menyetel perilaku cache.
SELECT t.id, t.name, w.phoneNumber
FROM kafka_input AS t
LEFT JOIN phoneNumber /*+ OPTIONS(
'lookup.cache' = 'PARTIAL',
'lookup.partial-cache.max-rows' = '1000'
) */ FOR SYSTEM_TIME AS OF PROCTIME() AS w
ON t.name = w.name;
Setiap kunci di dalam OPTIONS harus merupakan opsi WITH yang benar-benar didukung oleh konektor.
Opsi lookup.cache dan lookup.partial-cache.max-rows yang ditunjukkan di atas termasuk dalam antarmuka LookupCache generik Flink (FLIP-221), dan hanya berlaku untuk konektor baru yang mengimplementasikan antarmuka ini (seperti Fluss dan JDBC). Strategi None/LRU/ALL yang dijelaskan dalam bagian "Strategi cache tabel dimensi" sesuai dengan konektor lama, yang mengekspos perilaku cache mereka melalui opsi WITH yang berbeda. Lihat dokumentasi konektor target untuk memastikan opsi dan strategi cache mana yang didukung, serta hindari penggunaan parameter yang tidak dikenali oleh konektor.
Konfigurasi perilaku lookup dengan petunjuk LOOKUP
Petunjuk LOOKUP berperilaku konsisten dengan versi komunitas Apache Flink. Petunjuk ini mengonfigurasi mode sinkron/asinkron, pengulangan, dan perilaku shuffle untuk operasi join tunggal. Untuk detailnya, lihat Apache Flink Lookup Hint.
-
Petunjuk LOOKUP hanya tersedia di VVR 8.0 dan versi lebih baru.
-
Opsi
'shuffle' = 'true'hanya tersedia di VVR 8.0.8 dan versi lebih baru. -
Alias didukung di VVR 8.0 dan versi lebih baru. Jika tabel dimensi dirujuk dengan alias, petunjuk harus menggunakan alias tersebut.
Opsi yang didukung
|
Opsi |
Makna |
Nilai |
|
|
Nama atau alias tabel dimensi tempat petunjuk ini berlaku. |
String nama tabel atau alias. |
|
|
Apakah lookup asinkron diaktifkan. |
|
|
|
Urutan output lookup asinkron. |
|
|
|
Kapasitas antrian buffer untuk lookup asinkron. |
Bilangan bulat. |
|
|
Timeout untuk lookup asinkron. |
Durasi (misalnya, |
|
|
Kondisi yang memicu pengulangan. |
Hanya |
|
|
Strategi pengulangan. |
Hanya |
|
|
Interval tetap antar pengulangan. |
Durasi (misalnya, |
|
|
Jumlah maksimum upaya pengulangan. |
Bilangan bulat. |
|
|
Apakah shuffle dilakukan sebelum join tabel dimensi. |
|
Perilaku opsi shuffle
Opsi shuffle memengaruhi strategi shuffle pada join tabel dimensi. Perilaku efektif dalam setiap skenario adalah sebagai berikut.
|
Skenario |
Strategi join |
|
|
Strategi shuffle default engine digunakan. |
|
|
Strategi shuffle default engine digunakan. |
|
|
SHUFFLE_HASH digunakan secara default. Untuk detailnya, lihat bagian SHUFFLE_HASH di bawah. |
|
|
Strategi shuffle kustom yang disediakan oleh konektor digunakan. |
Saat ini hanya konektor Streaming Lakehouse Paimon yang menyediakan strategi shuffle kustom. Saat kolom join mencakup semua kolom bucket, shuffle dilakukan berdasarkan bucket.
Contoh kode
-- Terapkan strategi shuffle hanya ke tabel dimensi dim1.
SELECT /*+ LOOKUP('table'='dim1', 'shuffle' = 'true') */ ...
FROM src AS T
LEFT JOIN dim1 FOR SYSTEM_TIME AS OF PROCTIME() ON T.a = dim1.a
LEFT JOIN dim2 FOR SYSTEM_TIME AS OF PROCTIME() ON T.b = dim2.b;
-- Terapkan strategi shuffle ke kedua dim1 dan dim2.
SELECT /*+ LOOKUP('table'='dim1', 'shuffle' = 'true'), LOOKUP('table'='dim2', 'shuffle' = 'true') */ ...
FROM src AS T
LEFT JOIN dim1 FOR SYSTEM_TIME AS OF PROCTIME() ON T.a = dim1.a
LEFT JOIN dim2 FOR SYSTEM_TIME AS OF PROCTIME() ON T.b = dim2.b;
-- Saat dim1 dirujuk dengan alias D1, petunjuk harus menggunakan alias tersebut.
SELECT /*+ LOOKUP('table'='D1', 'shuffle' = 'true') */ ...
FROM src AS T
LEFT JOIN dim1 FOR SYSTEM_TIME AS OF PROCTIME() AS D1 ON T.a = D1.a
LEFT JOIN dim2 FOR SYSTEM_TIME AS OF PROCTIME() AS D2 ON T.b = D2.b;
-- Terapkan strategi shuffle ke kedua dim1 dan dim2 menggunakan alias mereka.
SELECT /*+ LOOKUP('table'='D1', 'shuffle' = 'true'), LOOKUP('table'='D2', 'shuffle' = 'true') */ ...
FROM src AS T
LEFT JOIN dim1 FOR SYSTEM_TIME AS OF PROCTIME() AS D1 ON T.a = D1.a
LEFT JOIN dim2 FOR SYSTEM_TIME AS OF PROCTIME() AS D2 ON T.b = D2.b;
Atur TableConfig tingkat pekerjaan dengan SET
Kunci TableConfig seperti table.exec.* adalah pengaturan global tingkat pekerjaan. Kunci-kunci ini harus diteruskan melalui SET; baik petunjuk LOOKUP maupun OPTIONS tidak menerimanya.
Kunci TableConfig umum untuk JOIN tabel dimensi:
|
Kunci |
Makna |
Default |
|
|
Kapasitas antrian buffer untuk lookup asinkron (default tingkat pekerjaan). |
100 |
|
|
Timeout untuk lookup asinkron (default tingkat pekerjaan). |
3 min |
|
|
Urutan output lookup asinkron (default tingkat pekerjaan). |
|
-- Atur default tingkat pekerjaan di awal pekerjaan.
SET 'table.exec.async-lookup.buffer-capacity' = '3072';
SET 'table.exec.async-lookup.timeout' = '180s';
INSERT INTO sink_table
SELECT ...
FROM src_table
LEFT JOIN dim_table FOR SYSTEM_TIME AS OF PROCTIME() AS d
ON src_table.key = d.key;
Jika SET dan petunjuk LOOKUP mengatur parameter yang sama, petunjuk LOOKUP pada join individual memiliki prioritas lebih tinggi.
Kontrol shuffle dengan petunjuk strategi join
Petunjuk strategi join mengontrol perilaku shuffle untuk join tabel dimensi. Petunjuk yang tersedia adalah SHUFFLE_HASH, REPLICATED_SHUFFLE_HASH, dan SKEW. Tabel berikut menunjukkan strategi join mana yang cocok untuk setiap strategi cache.
|
Strategi cache |
SHUFFLE_HASH |
REPLICATED_SHUFFLE_HASH (setara dengan SKEW) |
|
None |
Strategi ini tidak direkomendasikan; aliran utama mengalami overhead jaringan tambahan. |
Strategi ini tidak direkomendasikan; aliran utama mengalami overhead jaringan tambahan. |
|
LRU |
Pertimbangkan strategi ini ketika IO lookup dimensi menjadi bottleneck. Jika aliran utama memiliki lokalitas temporal pada kunci gabungan, strategi ini meningkatkan tingkat hit cache, mengurangi permintaan IO, dan meningkatkan throughput keseluruhan. Penting
Aliran utama mengalami overhead jaringan tambahan. Jika aliran utama mengalami kesenjangan data pada kunci gabungan dan Anda mengalami bottleneck performa, pertimbangkan REPLICATED_SHUFFLE_HASH sebagai gantinya. |
Pertimbangkan strategi ini ketika IO lookup dimensi menjadi bottleneck dan aliran utama mengalami kesenjangan data pada kunci gabungan. Jika aliran utama memiliki lokalitas temporal pada kunci gabungan, strategi ini meningkatkan tingkat hit cache, mengurangi permintaan IO, dan meningkatkan throughput keseluruhan. |
|
ALL |
Direkomendasikan ketika memori tabel dimensi menjadi bottleneck. Penggunaan memori dapat turun menjadi 1 / paralelisme. Penting
Aliran utama mengalami overhead jaringan tambahan. Jika aliran utama mengalami kesenjangan data pada kunci gabungan dan Anda mengalami bottleneck performa, pertimbangkan REPLICATED_SHUFFLE_HASH sebagai gantinya. |
Direkomendasikan ketika memori tabel dimensi menjadi bottleneck dan aliran utama mengalami kesenjangan data pada kunci gabungan. Penggunaan memori turun menjadi jumlah bucket / paralelisme. |
-
Opsi
shufflepada petunjuk LOOKUP sudah mencakup fungsi SHUFFLE_HASH. Jika keduanya ada, opsishufflepada petunjuk LOOKUP yang berlaku. -
Opsi
shufflepada petunjuk LOOKUP belum menangani kesenjangan data. Ketika dikombinasikan dengan REPLICATED_SHUFFLE_HASH atau SKEW, strategi yang ditentukan oleh REPLICATED_SHUFFLE_HASH atau SKEW memiliki prioritas lebih tinggi.
SHUFFLE_HASH
Efek: Menggunakan strategi shuffle-hash dalam JOIN tabel dimensi melakukan shuffle aliran utama berdasarkan kunci gabungan sebelum join. Dikombinasikan dengan strategi cache LRU, strategi ini meningkatkan tingkat hit cache dan mengurangi permintaan IO; dikombinasikan dengan strategi cache ALL, strategi ini mengurangi penggunaan memori. Satu petunjuk SHUFFLE_HASH dapat menentukan beberapa tabel dimensi.
Batasan: SHUFFLE_HASH mengurangi penggunaan memori, tetapi data hulu harus di-shuffle berdasarkan kunci gabungan, yang menimbulkan overhead jaringan tambahan. Hindari dalam dua kasus berikut:
-
Aliran utama sangat mengalami kesenjangan data pada kunci gabungan. Menggunakan SHUFFLE_HASH akan menjadikan node join sebagai bottleneck, menyebabkan tekanan balik parah untuk pekerjaan streaming atau tail panjang untuk pekerjaan batch. Gunakan REPLICATED_SHUFFLE_HASH sebagai gantinya.
-
Tabel dimensi kecil dan strategi cache ALL tidak mengalami bottleneck memori. Dalam kasus ini, penghematan memori yang diperoleh dari SHUFFLE_HASH tidak sebanding dengan overhead jaringan tambahan.
Contoh kode:
-- Aktifkan SHUFFLE_HASH hanya untuk dim1.
SELECT /*+ SHUFFLE_HASH(dim1) */ ...
-- Aktifkan SHUFFLE_HASH untuk kedua dim1 dan dim2.
SELECT /*+ SHUFFLE_HASH(dim1, dim2) */ ...
-- Saat dim1 dirujuk dengan alias D1, petunjuk harus menggunakan alias tersebut.
SELECT /*+ SHUFFLE_HASH(D1) */ ...
REPLICATED_SHUFFLE_HASH
Efek: REPLICATED_SHUFFLE_HASH pada dasarnya berperilaku sama dengan SHUFFLE_HASH, kecuali bahwa strategi ini mendistribusikan secara acak baris aliran utama dengan kunci yang sama ke N instance paralel. Hal ini mengatasi bottleneck performa yang disebabkan oleh kesenjangan data. Satu petunjuk REPLICATED_SHUFFLE_HASH dapat menentukan beberapa tabel dimensi.
Batasan:
-
Konfigurasikan jumlah bucket untuk data yang mengalami kesenjangan dengan
table.exec.skew-join.replicate-num(default: 16). Nilainya tidak boleh melebihi paralelisme node join dimensi. Untuk detailnya, lihat Penyetelan SQL tingkat pekerjaan. -
Aliran pembaruan tidak didukung. Menggunakan petunjuk ini ketika aliran utama adalah aliran pembaruan akan menimbulkan error.
Contoh kode:
SELECT /*+ REPLICATED_SHUFFLE_HASH(dim1) */ ...
SKEW
Efek: Ketika tabel yang ditentukan diketahui mengalami kesenjangan data, pengoptimal menerapkan strategi replicated-shuffle-hash. SKEW adalah syntactic sugar—secara internal diimplementasikan dengan replicated shuffle hash.
Batasan:
-
Setiap petunjuk SKEW hanya dapat menentukan satu tabel.
-
Nama tabel harus merujuk ke tabel utama yang mengalami kesenjangan data, bukan tabel dimensi.
-
Aliran pembaruan tidak didukung. Menggunakan petunjuk ini ketika aliran utama adalah aliran pembaruan akan menimbulkan error.
Contoh kode:
SELECT /*+ SKEW(src) */ ...
Contoh
Contoh 1: JOIN tabel dimensi dasar
Bentuk paling dasar: memperkaya aliran Kafka dengan tabel dimensi MySQL. Tidak ada petunjuk penyetelan yang digunakan.
CREATE TEMPORARY TABLE kafka_input (
id BIGINT,
name VARCHAR,
age BIGINT
) WITH (
'connector' = 'kafka',
'topic' = '<yourTopic>',
'properties.bootstrap.servers' = '<yourKafkaBrokers>',
'properties.group.id' = '<yourKafkaConsumerGroupId>',
'format' = 'csv'
);
CREATE TEMPORARY TABLE phoneNumber (
name VARCHAR,
phoneNumber BIGINT,
PRIMARY KEY (name) NOT ENFORCED
) WITH (
'connector' = 'mysql',
'hostname' = '<yourHostname>',
'port' = '3306',
'username' = '<yourUsername>',
'password' = '<yourPassword>',
'database-name' = '<yourDatabaseName>',
'table-name' = '<yourTableName>'
);
CREATE TEMPORARY TABLE result_infor (
id BIGINT,
phoneNumber BIGINT,
name VARCHAR
) WITH (
'connector' = 'blackhole'
);
INSERT INTO result_infor
SELECT
t.id,
w.phoneNumber,
t.name
FROM kafka_input AS t
JOIN phoneNumber FOR SYSTEM_TIME AS OF PROCTIME() AS w
ON t.name = w.name;
Contoh 2: Aktifkan cache dengan petunjuk OPTIONS dan konfigurasi lookup asinkron dengan petunjuk LOOKUP
Skenario penyetelan: QPS tabel dimensi tidak mencukupi. Anda ingin mengaktifkan cache parsial pada tabel dimensi dan mengaktifkan lookup asinkron dengan antrian buffer yang lebih besar.
INSERT INTO user_behavior_wide
SELECT /*+ LOOKUP('table' = 't2', 'async' = 'true', 'capacity' = '3072') */
t1.member_id AS member_id,
t2.tag AS tag
FROM user_behavior_datagen AS t1
LEFT JOIN fluss.fluss.user_active_info /*+ OPTIONS(
'lookup.cache' = 'PARTIAL',
'lookup.partial-cache.max-rows' = '1000'
) */
FOR SYSTEM_TIME AS OF PROCTIME() AS t2
ON t1.member_id = t2.member_id;
-
Opsi konektor (
lookup.cache,lookup.partial-cache.max-rows) diteruskan melalui petunjukOPTIONS()yang ditempatkan tepat setelah referensi tabel dimensi; ini menimpa opsi WITH yang sesuai saat kueri. -
Perilaku lookup (
async,capacity) dikonfigurasi melalui petunjukLOOKUP()yang ditempatkan setelah SELECT. OPTIONS dan LOOKUP adalah dua jenis petunjuk yang berbeda dan harus ditulis secara terpisah; menggabungkannya akan diam-diam menonaktifkan petunjuk tersebut.
Contoh 3: Setel buffer lookup asinkron tingkat pekerjaan dengan SET
Skenario penyetelan: beberapa JOIN tabel dimensi dalam pekerjaan yang sama memerlukan buffer lookup asinkron yang lebih besar. Anda ingin perubahan ini berlaku secara global, dan mengaktifkan mode asinkron melalui petunjuk LOOKUP.
SET 'table.exec.async-lookup.buffer-capacity' = '3072';
SET 'table.exec.async-lookup.timeout' = '180s';
INSERT INTO user_behavior_wide
SELECT /*+ LOOKUP('table' = 't2', 'async' = 'true') */
t1.member_id,
t2.tag
FROM user_behavior_datagen AS t1
LEFT JOIN fluss.fluss.user_active_info
FOR SYSTEM_TIME AS OF PROCTIME() AS t2
ON t1.member_id = t2.member_id;
-
Parameter seperti
table.exec.async-lookup.buffer-capacityadalah kunci TableConfig tingkat pekerjaan dan hanya dapat diatur dengan SET. Menempatkannya di dalam OPTIONS atau LOOKUP tidak berpengaruh. -
Jika petunjuk LOOKUP tidak menentukan
capacity, nilai global dari SET yang digunakan. Jika keduanya ditentukan, petunjuk LOOKUP memiliki prioritas lebih tinggi pada join individual tersebut.