perf(postgres): Optimizing feast offline Store for date-range multi-FV retrieval#6057
perf(postgres): Optimizing feast offline Store for date-range multi-FV retrieval#6057Vperiodt wants to merge 16 commits into
Conversation
|
@Vperiodt thanks for the PR. if it's not too much trouble, can you give a small example of result queries for say.. 2 fv scenario and highlight differences this PR introduces? there jinja templates are hard enough to read through even when one knows what the intent is 😄 |
Sorry, something went wrong.
sure ! will add it in the description itself |
Sorry, something went wrong.
YassinNouh21
left a comment
There was a problem hiding this comment.
The LOCF approach is a solid improvement over the LATERAL join path — O(L log L) window passes vs O(N×M) inequality joins is a real win for large date-range queries. The per-FV independent pipeline is clean and avoids cross-FV interference.
A few issues to address before merge — one pre-existing bug that this PR should fix since it's modifying the non-entity path, dead code in the template, and some test coverage gaps.
Sorry, something went wrong.
|
hey ! @YassinNouh21 Thanks for your review earlier, it would be great if you can review it again |
Sorry, something went wrong.
|
@Vperiodt Could you please rebase the PR for integration tests run ? |
Sorry, something went wrong.
Signed-off-by: Vanshika Vanshika <vvanshik@redhat.com> rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
Signed-off-by: Vanshika Vanshika <vvanshik@redhat.com> rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
Signed-off-by: Vanshika Vanshika <vvanshik@redhat.com> rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
Signed-off-by: Vanshika Vanshika <vvanshik@redhat.com> rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
Signed-off-by: Vanshika Vanshika <vvanshik@redhat.com> rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
Signed-off-by: Vanshika Vanshika <vvanshik@redhat.com> rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
Signed-off-by: Vanshika Vanshika <vvanshik@redhat.com> rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
Signed-off-by: Vanshika Vanshika <vvanshik@redhat.com> rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
jyejare
left a comment
There was a problem hiding this comment.
Review Summary
The LOCF (Last Observation Carried Forward) approach is a solid replacement for the LATERAL JOIN path — the per-FV independent forward-fill pipelines (__stacked → __grouped → __filled) correctly avoid cross-FV interference, and the edge cases are well handled (entityless FVs with PARTITION BY (SELECT NULL), different entity sets with NULL padding + IS NOT DISTINCT FROM, created_timestamp_column dedup via ROW_NUMBER). The make_interval(secs => ...) improvement applies to the existing entity_df path too, which is a nice bonus.
Test coverage is strong with 7 new test methods, all using sqlglot.parse validation.
However, CI is currently failing (lint-python and unit-test-python 3.10), so this is not merge-ready yet.
Blockers
- CI failures —
lint-pythonandunit-test-python (3.10, ubuntu-latest)are red on the latest run (Apr 13). Please investigate and fix. - Reuse
compute_non_entity_date_range— as @ntkathole flagged, the inlined date-range logic should use the existing utility. This also eliminates the duplicatemax_ttl_secondscomputation. See inline comment for the suggested pattern.
Minor Items
- Skip entity_df creation in LOCF path — the synthetic entity_df and dummy
left_table_query_stringare never used by the LOCF template. Consider skipping that overhead entirely. - The
IS NOT DISTINCT FROMfix for NULL entity comparisons is an improvement over the old LATERAL path — worth calling out in the PR description as a correctness fix.
Sorry, something went wrong.
Signed-off-by: Vanshika Vanshika <vvanshik@redhat.com> rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
What this PR does / why we need it:
Replaces the date-range multi-FV path in the Postgres offline store (previously base_entities + one LEFT JOIN LATERAL per feature view) with a set-based LOCF (Last Observation Carried Forward) implementation
Uses a single timeline: stack (UNION ALL of spine + feature rows), COUNT for group boundaries, FIRST_VALUE for forward-fill, then filter to spine and apply per-FV TTL.
Which issue(s) this PR fixes:
Fixes slow get_historical_features on the Postgres offline store for date-range retrieval with multiple feature views. The LATERAL/inequality joins had O(N×M) cost. This PR switches to a LOCF path: one stacked timeline of size L, sort O(L log L), and O(L) window passes, which makes total cost as O(L log L).
Misc
Scenario:
get_historical_features(features=[...], start_date=2023-01-01, end_date=2023-01-07)with no entity DataFrame and two feature views:driver_id, TTL 1 day, featurescorecustomer_id, TTL 0, featureamountInputs
start_dateend_dateentity_dfNone(non-entity mode)1. Feature data window (
__data_raw)Feature data is explicitly pulled from lookback to end_date so LOCF can carry the last observation before
start_date.Time window used for feature data
With
lookback_start_date = start_date - max_ttl(e.g. 2022-12-31 for 1-day TTL), driver_fv rows before 2023-01-01 are now included so LOCF can fill correctly.2. Spine: unified (entity, timestamp) grid
Spine is built from each FV’s
__data/__data_rawover[start_date, end_date]. When FVs have different entity sets, the template emitsNULL AS "entity"for the FV that doesn’t have that entity:Example spine shape (
Spine = distinct (event_timestamp, driver_id, customer_id) from both FVs; missing entity is NULL.
3. TTL in the final SELECT
Example final output shape
After LOCF and TTL: one row per (event_timestamp, driver_id, customer_id);
scoreis NULL when outside TTL.