@@ -26,6 +26,7 @@ Feast supports the following data types: |
26 | 26 | | `UnixTimestamp` | `datetime` | Unix timestamp (nullable) | |
27 | 27 | | `Uuid` | `uuid.UUID` | UUID (any version) | |
28 | 28 | | `TimeUuid` | `uuid.UUID` | Time-based UUID (version 1) | |
| 29 | +| `Decimal` | `decimal.Decimal` | Arbitrary-precision decimal number | |
29 | 30 |
|
30 | 31 | ### Domain-Specific Primitive Types |
31 | 32 |
|
@@ -56,6 +57,7 @@ All primitive types have corresponding array (list) types: |
56 | 57 | | `Array(UnixTimestamp)` | `List[datetime]` | List of timestamps | |
57 | 58 | | `Array(Uuid)` | `List[uuid.UUID]` | List of UUIDs | |
58 | 59 | | `Array(TimeUuid)` | `List[uuid.UUID]` | List of time-based UUIDs | |
| 60 | +| `Array(Decimal)` | `List[decimal.Decimal]` | List of arbitrary-precision decimals | |
59 | 61 |
|
60 | 62 | ### Set Types |
61 | 63 |
|
@@ -73,6 +75,7 @@ All primitive types (except `Map` and `Json`) have corresponding set types for s |
73 | 75 | | `Set(UnixTimestamp)` | `Set[datetime]` | Set of unique timestamps | |
74 | 76 | | `Set(Uuid)` | `Set[uuid.UUID]` | Set of unique UUIDs | |
75 | 77 | | `Set(TimeUuid)` | `Set[uuid.UUID]` | Set of unique time-based UUIDs | |
| 78 | +| `Set(Decimal)` | `Set[decimal.Decimal]` | Set of unique arbitrary-precision decimals | |
76 | 79 |
|
77 | 80 | **Note:** Set types automatically remove duplicate values. When converting from lists or other iterables to sets, duplicates are eliminated. |
78 | 81 |
|
@@ -194,7 +197,7 @@ from datetime import timedelta |
194 | 197 | from feast import Entity, FeatureView, Field, FileSource |
195 | 198 | from feast.types import ( |
196 | 199 | Int32, Int64, Float32, Float64, String, Bytes, Bool, UnixTimestamp, |
197 | | - Uuid, TimeUuid, Array, Set, Map, Json, Struct |
| 200 | + Uuid, TimeUuid, Decimal, Array, Set, Map, Json, Struct |
198 | 201 | ) |
199 | 202 |
|
200 | 203 | # Define a data source |
@@ -226,6 +229,7 @@ user_features = FeatureView( |
226 | 229 | Field(name="last_login", dtype=UnixTimestamp), |
227 | 230 | Field(name="session_id", dtype=Uuid), |
228 | 231 | Field(name="event_id", dtype=TimeUuid), |
| 232 | + Field(name="price", dtype=Decimal), |
229 | 233 |
|
230 | 234 | # Array types |
231 | 235 | Field(name="daily_steps", dtype=Array(Int32)), |
@@ -238,6 +242,7 @@ user_features = FeatureView( |
238 | 242 | Field(name="login_timestamps", dtype=Array(UnixTimestamp)), |
239 | 243 | Field(name="related_session_ids", dtype=Array(Uuid)), |
240 | 244 | Field(name="event_chain", dtype=Array(TimeUuid)), |
| 245 | + Field(name="historical_prices", dtype=Array(Decimal)), |
241 | 246 |
|
242 | 247 | # Set types (unique values only — see backend caveats above) |
243 | 248 | Field(name="visited_pages", dtype=Set(String)), |
@@ -246,6 +251,7 @@ user_features = FeatureView( |
246 | 251 | Field(name="preferred_languages", dtype=Set(String)), |
247 | 252 | Field(name="unique_device_ids", dtype=Set(Uuid)), |
248 | 253 | Field(name="unique_event_ids", dtype=Set(TimeUuid)), |
| 254 | + Field(name="unique_prices", dtype=Set(Decimal)), |
249 | 255 |
|
250 | 256 | # Map types |
251 | 257 | Field(name="user_preferences", dtype=Map), |
@@ -313,9 +319,44 @@ related_sessions = [uuid.uuid4(), uuid.uuid4(), uuid.uuid4()] |
313 | 319 | unique_devices = {uuid.uuid4(), uuid.uuid4()} |
314 | 320 | ``` |
315 | 321 |
|
316 | | -### Nested Collection Type Usage Examples |
| 322 | +### Decimal Type Usage Examples |
| 323 | + |
| 324 | +The `Decimal` type stores arbitrary-precision decimal numbers using Python's `decimal.Decimal`. |
| 325 | +Values are stored as strings in the proto to preserve full precision — no floating-point rounding occurs. |
| 326 | + |
| 327 | +```python |
| 328 | +import decimal |
| 329 | + |
| 330 | +# Scalar decimal — e.g., a financial price |
| 331 | +price = decimal.Decimal("19.99") |
| 332 | + |
| 333 | +# High-precision value — all digits preserved |
| 334 | +tax_rate = decimal.Decimal("0.08750000000000000000") |
| 335 | + |
| 336 | +# Decimal values are returned as decimal.Decimal objects from get_online_features() |
| 337 | +response = store.get_online_features( |
| 338 | + features=["product_features:price"], |
| 339 | + entity_rows=[{"product_id": 42}], |
| 340 | +) |
| 341 | +result = response.to_dict() |
| 342 | +# result["price"][0] is a decimal.Decimal object |
| 343 | + |
| 344 | +# Decimal lists — e.g., a history of prices |
| 345 | +historical_prices = [ |
| 346 | + decimal.Decimal("18.50"), |
| 347 | + decimal.Decimal("19.00"), |
| 348 | + decimal.Decimal("19.99"), |
| 349 | +] |
| 350 | + |
| 351 | +# Decimal sets — unique price points seen |
| 352 | +unique_prices = {decimal.Decimal("9.99"), decimal.Decimal("19.99"), decimal.Decimal("29.99")} |
| 353 | +``` |
317 | 354 |
|
318 | | -Nested collections allow storing multi-dimensional data with unlimited depth: |
| 355 | +{% hint style="warning" %} |
| 356 | +`Decimal` is **not** inferred from any backend schema. You must declare it explicitly in your feature view schema. The pandas dtype for `Decimal` columns is `object` (holding `decimal.Decimal` instances), not a numeric dtype. |
| 357 | +{% endhint %} |
| 358 | + |
| 359 | +### Nested Collection Type Usage Examples |
319 | 360 |
|
320 | 361 | ```python |
321 | 362 | # List of lists — e.g., weekly score history per user |
@@ -420,7 +461,7 @@ Each of these columns must be associated with a Feast type, which requires conve |
420 | 461 | * `source_datatype_to_feast_value_type` calls the appropriate method in `type_map.py`. For example, if a `SnowflakeSource` is being examined, `snowflake_python_type_to_feast_value_type` from `type_map.py` will be called. |
421 | 462 |
|
422 | 463 | {% hint style="info" %} |
423 | | -**Types that cannot be inferred:** `Set`, `Json`, `Struct`, `PdfBytes`, and `ImageBytes` types are never inferred from backend schemas. If you use these types, you must declare them explicitly in your feature view schema. |
| 464 | +**Types that cannot be inferred:** `Set`, `Json`, `Struct`, `Decimal`, `PdfBytes`, and `ImageBytes` types are never inferred from backend schemas. If you use these types, you must declare them explicitly in your feature view schema. |
424 | 465 | {% endhint %} |
425 | 466 |
|
426 | 467 | ### Materialization |
|