Flink: Support Lookup Join using full in-memory lookup cache - #18144
Guosmilesmile wants to merge 1 commit into
Conversation
|
For snapshot pinning, I was thinking we could resolve the snapshot at job submission time and pass the snapshot ID to every TaskManager, so that all caches use the same snapshot. But there is a problem with this approach. The problem is failover. Flink doesn't re-run the planner when a task restarts, so the pinned snapshot ID would remain unchanged. If that snapshot has expired by then, the cache load would fail with Cannot find snapshot with ID ... after the restart, and retries would keep failing until the job is resubmitted. Periodic refresh doesn't help here, because the failure happens during the initial cache load. We also don't have a way to persist and update the snapshot ID from the connector side, since a lookup join doesn't have checkpointed state. So while pinning the snapshot would ensure consistency across subtasks, it introduces a failover problem. Additionally, dimension tables do not change frequently. For this PR, I therefore use the latest snapshot at the moment and just added logging and a metric to report the snapshot ID being used.If you have a better idea, we'd be happy to take a look. |
6550de0 to
de77ef7
Compare
|
why not use ReadOptions and pass when creating the IcebergFullCachingLookupFunction, which will keep it consistent across task restarts or job restarts. At table creation time, CREATE TABLE dim_users (
user_id BIGINT,
name STRING,
city STRING
) WITH (
'connector' = 'iceberg',
'catalog-name' = 'iceberg_catalog',
'catalog-type' = 'hadoop',
'warehouse' = '/path/to/warehouse',
'catalog-database' = 'db',
'catalog-table' = 'users',
'lookup.full-cache.eager-load' = 'true',
'snapshot-id' = '121334'
);OR per query SELECT o.order_id, o.user_id, u.name, u.city
FROM orders AS o
LEFT JOIN iceberg_catalog.`db`.`users`
/*+ OPTIONS(
'lookup.full-cache.eager-load' = 'true',
'snapshot-id' = '121334'
) */
FOR SYSTEM_TIME AS OF o.proc_time AS u
ON o.user_id = u.user_id;There could be other strategies to simplify , instead of user specifying exact snapshot id also like latest or specific tag or as-of-timestamp |
|
@swapna267 Showing a specific snapshot ID is one approach, but it doesn't solve the problem of that snapshot expiring. On top of that, most users won't bother specifying a particular snapshot anyway. |
|
Yes it doesn't need to be particular snapshot Id. Instead it could be Latest_Snapshot or a particular Branch/Tag. I was referring to resolving it on Job Submission time instead of on TaskManagers. But i just realized you already mentioned that option. Instead of being inconsistent with lookup result across TaskManagers, prefer to have all TM's load from same Snapshot Id. And fail loudly, incase of an expired snapshot or a Tag. |
|
@swapna267 I agree that resolving the snapshot ID at Job Submission time works well when the cache is not refreshed, with an explicit failure if the snapshot has expired. However, with periodic refresh, a long-running job may encounter a failover after the original snapshot has expired. Resolving the snapshot ID at Job Submission would require manual intervention to restart the job, which doesn't seem ideal for the periodic refresh use case. I also noticed that other connectors supporting lookup joins generally establish their connections independently on each TaskManager. So I don't think resolving the snapshot ID at the Job Submission level is a good fit for this use case. This is also why I'm still leaning toward using the latest snapshot rather than pinning to a specific snapshot. |
de77ef7 to
81931fe
Compare
81931fe to
41914e4
Compare
|
@pvary @mxm @talatuyarer If you get a chance, please take a look and let me know what you think. I'd really appreciate it. |
|
Thanks @Guosmilesmile . Yes I agree, this wouldn't make sense for Periodic Refresh . As this PR's scope was limited to one time load with no periodic refresh, i was recommending that. |
This PR adds lookup join support for the Iceberg Flink table source, using a full in-memory lookup cache.
Part of #18142
The implementation enables Iceberg tables to be used as temporal lookup join dimensions in Flink SQL.
Supported Features
Lookup join against Iceberg table source
Pushed-down filter support
Full in-memory lookup cache
lookup.cache=FULLis accepted;NONEandPARTIALare rejected, because an Iceberg table cannot be point-looked-up effectively.Configurable load strategy
lookup.full-cache.eager-loadselects when the cache is loaded:false(default): on the first lookup. Simple, but that probe row is blocked for the duration of the load.true: inopen(), so no probe row is blocked, and a load that fails fails the job at startup instead of mid-stream.Metrics
icebergLookupCachegroup:cacheHitandcacheMisscounters, andsnapshotIdandcachedRowsgauges.How to Use
Basic lookup join
Load the cache when the lookup function opens
or
Options
lookup.cacheFULLis accepted.NONEandPARTIALare rejected, because an Iceberg table cannot be point-looked-up.lookup.full-cache.eager-loadtrueopen(), instead of on the first lookup.Both can be set per join with an
OPTIONShint, or in the table DDLWITHclause.Notes