feast-dev / feast-dev/feast

Support typed default values for missing features

Open
#6,715 1 comment 0 reactions 0 assignees View on GitHub
kind/feature
Dominant language
Python
Stars
7.3k
Forks
1.4k
Avg merge
1d 21h
Merged PRs (30d)
15

Description

**Is your feature request related to a problem? Please describe.**

Feast returns null for features that are missing or explicitly null, so every consumer has to decide how to impute them independently. We've personally experienced this where a Go serving client might turn a missing transaction count into -1 while the training pipeline transforms to 0. As consumers grow ensuring consistency will become harder. That is training/serving skew created by the absence of a shared convention, and adding a new client means rediscovering each feature's missing-value semantics.

Noticed `OnlineResponse.to_tensor(default_value=...)` and `RetrievalJob.to_tensor(default_value=...)` do conversion-time replacement for tensors only. I haven't used these myself but think a similar approach could be implemented for to_dict() and to_df().

Feast owns the schema, registry, retrieval paths, statuses, and the ODFV execution boundary, so it's the only layer that can apply a default consistently *before* transformations in both the online and historical paths.

**Describe the solution you'd like**
Declare a typed default on the field:

```python
Field(name="transaction_count", dtype=Int64, default_value=0)
```

Stored in FeatureSpecV2 as a feast.types.Value on field number 8 (currently free; Value.proto is already imported). Message presence distinguishes "no default" from a valid zero-like default such as 0, 0.0, false, or "".

Applied:

* after the historical point-in-time join
* during online retrieval in Python and Go serving
* before ODFV transformations execute

Could be applied here too but can already be done in the transformer code:
* to null ODFV outputs whose field declares a default
* optionally to missing/null RequestSource fields

**Describe alternatives you've considered**
1. Client-side imputation: today's workaround duplicates semantics per client and permits skew.
2. fillna() inside each ODFV: every transformation repeats it, and it doesn't help direct feature retrieval.
3. A default_values={...} argument on retrieval calls: supports consumer-specific behaviour but establishes no reusable feature semantic, and training and serving can still diverge. Could be layered on later as an override above the schema default.
4. Defaults in feature tags: avoids the proto change but is stringly typed and makes every runtime reinterpret metadata.

**Additional context**
Strictly opt-in. A field without default_value behaves exactly as it does today, and old registries without field 8 load unchanged.

Contributor guide

Open the contributing guide

Research direction

Start by tracing OnlineResponse.to_tensor(), RetrievalJob.to_tensor(), and the corresponding to_dict() and to_df() paths. Read FeatureSpecV2 and the imported Value.proto definition, then follow the online, historical, and ODFV boundaries. Done means typed defaults are opt-in, applied consistently before transformations, and old registries without field 8 still load unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, python
Domain
backend-api-design, data-engineering, machine-learning
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.