15. Deploy and Serve a Feature List
Deploy and Serve a Feature List for Model Predictions¶
Once you have a feature list ready, it's essential to serve these features effectively to make real-time or batch predictions using your machine learning model.
In this section, we'll take the feature list we previously crafted and explore two primary ways to serve its values:
REST API: Ideal for real-time predictions where you need instantaneous results. For instance, in applications where user interactions require immediate feedback based on model predictions.
Batch Processing: Best suited for scenarios where you have a bulk of data and don't require instant results.
Important Note for FeatureByte Enterprise Users¶
In Catalogs with Approval Flow enabled, moving features to production-ready status involves a comprehensive approval process.
This includes several evaluations, such as checking the feature's compliance with default cleaning operations and the feature job setting of its source tables. It also involves confirming the status of these tables and backtesting the feature job setting to prevent future training-serving inconsistencies. Additionally, essential details of the feature, particularly its feature definition file, are shared and subjected to a thorough review.
Activate Catalog¶
import featurebyte as fb
from datetime import datetime
# Set your profile to the tutorial environment
fb.use_profile("tutorial")
catalog_name = "Credit Default Dataset SDK Tutorial"
catalog = fb.Catalog.activate(catalog_name)
17:09:46 | INFO | SDK version: 3.2.0.dev66 INFO :featurebyte:SDK version: 3.2.0.dev66 17:09:46 | INFO | No catalog activated. INFO :featurebyte:No catalog activated. 17:09:46 | INFO | Using profile: staging INFO :featurebyte:Using profile: staging 17:09:46 | INFO | Using configuration file at: /Users/gxav/.featurebyte/config.yaml INFO :featurebyte:Using configuration file at: /Users/gxav/.featurebyte/config.yaml 17:09:46 | INFO | Active profile: staging (https://staging.featurebyte.com/api/v1) INFO :featurebyte:Active profile: staging (https://staging.featurebyte.com/api/v1) 17:09:46 | INFO | SDK version: 3.2.0.dev66 INFO :featurebyte:SDK version: 3.2.0.dev66 17:09:46 | INFO | No catalog activated. INFO :featurebyte:No catalog activated. 17:09:47 | INFO | Catalog activated: Credit Default Dataset SDK Tutorial INFO :featurebyte.api.catalog:Catalog activated: Credit Default Dataset SDK Tutorial 16:13:11 | WARNING | Remote SDK version (1.1.0.dev7) is different from local (1.1.0.dev1). Update local SDK to avoid unexpected behavior. 16:13:11 | INFO | No catalog activated. 16:13:11 | INFO | Catalog activated: Grocery Dataset Tutorial
List feature lists in Catalog¶
catalog.list_feature_lists()
| id | name | num_feature | status | deployed | readiness_frac | online_frac | tables | entities | primary_entity | created_at | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 68ef63333e2dac375b630de7 | 40 features for Credit Default | 40 | DRAFT | False | 0.0 | 0.0 | [NEW_APPLICATION, CLIENT_PROFILE, BUREAU, INST... | [New Application, Client] | [New Application] | 2025-10-15T09:02:51.346000 |
Get a feature list from Catalog¶
feature_list_name = "40 features for Credit Default"
simple_feature_list = catalog.get_feature_list(feature_list_name)
Loading Feature(s) |████████████████████████████████████████| 40/40 [100%] in 0.
Deploy feature list¶
deployment_name = "Loan Application: simple feature list with 40 features"
# Create a deployment
deployment = simple_feature_list.deploy(
deployment_name=deployment_name,
make_production_ready=True,
use_case_name="Loan Default by client",
)
Done! |████████████████████████████████████████| 100% in 9.1s (0.11%/s) Done! |████████████████████████████████████████| 100% in 6.1s (0.17%/s) Done! |████████████████████████████████████████| 100% in 6.1s (0.17%/s) Done! |████████████████████████████████████████| 100% in 6.1s (0.17%/s)
# Enable deployment
deployment.enable()
Done! |████████████████████████████████████████| 100% in 4:03.5 (0.00%/s) Done! |████████████████████████████████████████| 100% in 1:49.2 (0.01%/s)
# Check that the deployment is enabled
catalog.list_deployments()
| id | name | feature_list_name | feature_list_version | num_feature | enabled | |
|---|---|---|---|---|---|---|
| 0 | 68ef64e5c712940cada35ec3 | Loan Application: simple feature list with 40 ... | 40 features for Credit Default | V251015 | 40 | True |
# Check status of the feature list
print("simple_feature_list.status:", simple_feature_list.status)
simple_feature_list.status: DEPLOYED
Create view of recent applications¶
Let's create a view of the last 24 hours applications.
# Get view of new applications
application_view = catalog.get_view("NEW_APPLICATION")
from datetime import datetime, timedelta, timezone
import pandas as pd
date_time_now_utc = datetime.now(timezone.utc).replace(tzinfo=None)
now_less_24h = date_time_now_utc - timedelta(hours=24)
cond = application_view.application_time > pd.Timestamp(now_less_24h)
recent_application_view = application_view[cond]
recent_application_view.preview()
| SK_ID_CURR | ClientID | CONTRACT_TYPE | AMT_INCOME_TOTAL | AMT_CREDIT | AMT_ANNUITY | AMT_GOODS_PRICE | TYPE_SUITE | REGION_POPULATION_RELATIVE | application_time | ... | FLAG_DOCUMENT_18 | FLAG_DOCUMENT_19 | FLAG_DOCUMENT_20 | FLAG_DOCUMENT_21 | AMT_REQ_CREDIT_BUREAU_HOUR | AMT_REQ_CREDIT_BUREAU_DAY | AMT_REQ_CREDIT_BUREAU_WEEK | AMT_REQ_CREDIT_BUREAU_MON | AMT_REQ_CREDIT_BUREAU_QRT | AMT_REQ_CREDIT_BUREAU_YEAR | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 100168 | 100168 | Cash loans | 157500.0 | 266652.0 | 16443.0 | 202500.0 | Unaccompanied | 0.011657 | 2025-10-14 20:45:39 | ... | 0 | 0 | 0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 4.0 |
| 1 | 104058 | 104058 | Cash loans | 157500.0 | 521568.0 | 22054.5 | 360000.0 | Unaccompanied | 0.020246 | 2025-10-15 04:21:09 | ... | 0 | 0 | 0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | 2.0 | 0.0 |
| 2 | 110958 | 110958 | Cash loans | 90000.0 | 183784.5 | 16983.0 | 148500.0 | Family | 0.020246 | 2025-10-15 02:45:32 | ... | 0 | 0 | 0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
| 3 | 114842 | 114842 | Cash loans | 67500.0 | 119893.5 | 12586.5 | 103500.0 | Unaccompanied | 0.008230 | 2025-10-14 23:25:12 | ... | 0 | 0 | 0 | 0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 4 | 115933 | 115933 | Cash loans | 112500.0 | 364896.0 | 28957.5 | 315000.0 | Unaccompanied | 0.009549 | 2025-10-15 08:53:52 | ... | 0 | 0 | 0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 5 | 121321 | 121321 | Cash loans | 135000.0 | 601470.0 | 26622.0 | 450000.0 | Spouse, partner | 0.007120 | 2025-10-14 15:07:07 | ... | 0 | 0 | 0 | 0 | NaN | NaN | NaN | NaN | NaN | NaN |
| 6 | 122609 | 122609 | Cash loans | 112500.0 | 260640.0 | 26838.0 | 225000.0 | Unaccompanied | 0.009549 | 2025-10-15 03:58:16 | ... | 0 | 0 | 0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 2.0 |
| 7 | 128760 | 128760 | Cash loans | 67500.0 | 254799.0 | 20259.0 | 193500.0 | Unaccompanied | 0.006305 | 2025-10-14 10:35:34 | ... | 0 | 0 | 0 | 0 | NaN | NaN | NaN | NaN | NaN | NaN |
| 8 | 129135 | 129135 | Cash loans | 225000.0 | 746280.0 | 42970.5 | 675000.0 | Unaccompanied | 0.008575 | 2025-10-14 21:03:11 | ... | 0 | 0 | 0 | 0 | NaN | NaN | NaN | NaN | NaN | NaN |
| 9 | 134654 | 134654 | Cash loans | 76500.0 | 74628.0 | 8167.5 | 67500.0 | Unaccompanied | 0.030755 | 2025-10-14 12:34:18 | ... | 0 | 0 | 0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 2.0 |
10 rows × 111 columns
# Check primary entity of the deployed feature list to obtain its serving name
simple_feature_list.primary_entity
[<featurebyte.api.entity.Entity at 0x3008442c0>
{
'name': 'New Application',
'created_at': '2025-10-15T08:58:25.635000',
'updated_at': '2025-10-15T08:58:27.217000',
'description': None,
'serving_names': [
'SK_ID_CURR'
],
'catalog_name': 'Credit Default Dataset SDK Tutorial'
}]
Compute batch feature table¶
# Get deployment
deployment = catalog.get_deployment(deployment_name)
# Compute batch features
batch_features = deployment.compute_batch_feature_table(
batch_request_table=recent_application_view[["SK_ID_CURR"]],
batch_feature_table_name =
f"{feature_list_name} with Latest Applications latest 24 hours at "
+ date_time_now_utc.strftime("%Y%m%d:%H%M"),
point_in_time=date_time_now_utc,
)
Done! |████████████████████████████████████████| 100% in 1:31.4 (0.01%/s) Done! |████████████████████████████████████████| 100% in 12.1s (0.08%/s)
# List observation tables
catalog.list_batch_feature_tables()
| id | name | feature_store_name | batch_request_table_name | shape | created_at | |
|---|---|---|---|---|---|---|
| 0 | 68ef65e5c712940cada35ec4 | 40 features for Credit Default with Latest App... | playground | None | [114, 41] | 2025-10-15T09:15:42.879000 |
# Convert to pandas
batch_features.to_pandas()
Downloading table |████████████████████████████████████████| 114/114 [100%] in 0
| SK_ID_CURR | NEW_APPLICATION_EXT_SOURCE_2 | NEW_APPLICATION_EXT_SOURCE_3 | NEW_APPLICATION_EXT_SOURCE_1 | NEW_APPLICATION_Credit-Goods_Difference | NEW_APPLICATION_AMT_ANNUITY_To_AMT_CREDIT | NEW_APPLICATION_DAYS_EMPLOYED | CLIENT_GENDER | CLIENT_Max_of_Active_Cr_active_BureauReportedCredits_AMT_CREDIT_SUM_DEBT_To_AMT_CREDIT_SUMs_104w | CLIENT_EDUCATION_TYPE | ... | CLIENT_Installments_AMT_PAYMENTs_by_PriorApplication_PAYMENT_TYPE_24cMo | CLIENT_Time_To_Latest_Approved_Contract_status_PriorApplication_last_due_1st_version_timestamp_104w | NEW_APPLICATION_FLAG_DOCUMENT_3 | NEW_APPLICATION_FLOORSMAX_MODE | CLIENT_Max_of_Installments_Days_Difference_Actual_vs_Scheduleds_24cMo | CLIENT_Max_of_Installments_PriorApplication_AMT_ANNUITY_To_AMT_CREDITs_6cMo | CLIENT_Std_of_Credit_card_monthly_balance_records_CNT_DRAWINGS_ATM_CURRENTs_24cMo | CLIENT_PriorApplications_AMT_CREDITs_by_PriorApplication_NFLAG_INSURED_ON_APPROVAL_52w | CLIENT_Std_of_BureauReportedCredits_Available_Credits_26w | CLIENT_Max_of_Consumer_credit_Cr_type_BureauReportedCredits_AMT_CREDIT_SUM_DEBT_To_AMT_CREDIT_SUMs_52w | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 100168 | 0.708939 | 0.746300 | NaN | 64152.0 | 0.061665 | -13294.0 | F | NaN | Higher education | ... | {'Cash through the bank': 2649137.94} | -675.480218 | 1 | 0.2083 | -2.0 | 0.037060 | NaN | None | NaN | NaN |
| 1 | 104058 | 0.498816 | 0.535276 | 0.626733 | 161568.0 | 0.042285 | NaN | F | NaN | Secondary / secondary special | ... | {'Cash through the bank': 40839.795} | 216.203462 | 0 | NaN | -9.0 | NaN | NaN | None | 0.0000 | 0.000000 |
| 2 | 110958 | 0.049740 | NaN | 0.226673 | 35284.5 | 0.092407 | -778.0 | F | 0.750972 | Higher education | ... | {'Cash through the bank': 90639.36} | 338.269863 | 1 | NaN | -10.0 | NaN | NaN | None | 0.0000 | 0.750972 |
| 3 | 114842 | 0.495776 | 0.236611 | 0.472694 | 16393.5 | 0.104981 | -824.0 | F | 0.000000 | Secondary / secondary special | ... | {'Cash through the bank': 81448.42499999999} | 131.408983 | 1 | NaN | -8.0 | 0.103480 | NaN | None | 33750.0000 | 0.000000 |
| 4 | 115933 | 0.731233 | 0.728141 | 0.518943 | 49896.0 | 0.079358 | -1817.0 | F | NaN | Secondary / secondary special | ... | {'Cash through the bank': 82994.67} | -8.985924 | 1 | NaN | -7.0 | 0.099134 | NaN | {'1': 76108.5} | NaN | NaN |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 109 | 439334 | 0.491310 | 0.821443 | 0.385260 | 0.0 | 0.056085 | -2390.0 | M | NaN | Secondary / secondary special | ... | None | NaN | 1 | NaN | NaN | NaN | NaN | None | NaN | NaN |
| 110 | 439448 | 0.599798 | 0.466864 | 0.694343 | 38493.0 | 0.052120 | -291.0 | M | 1.000000 | Secondary / secondary special | ... | {'Cash through the bank': 109877.85} | -232.870878 | 1 | 0.1667 | 3.0 | 0.107731 | NaN | {'1': 47970.0, '__MISSING__': 0.0} | 25390.0125 | 0.925269 |
| 111 | 443090 | 0.700517 | 0.280790 | NaN | 0.0 | 0.079300 | -1311.0 | M | 0.858035 | Secondary / secondary special | ... | {'Cash through the bank': 422228.52} | NaN | 0 | NaN | -1.0 | NaN | NaN | None | 56787.9975 | 0.858035 |
| 112 | 447504 | 0.614169 | 0.616122 | 0.769972 | 0.0 | 0.048100 | NaN | F | 0.380025 | Secondary / secondary special | ... | {'XNA': 122001.75} | -27.126306 | 0 | NaN | -16.0 | 0.095977 | NaN | {'1': 127116.0} | 39820.5000 | 0.291717 |
| 113 | 453837 | 0.601172 | 0.754406 | NaN | 30411.0 | 0.061923 | NaN | F | NaN | Secondary / secondary special | ... | {'Cash through the bank': 797126.3999999999} | 130.112444 | 1 | 0.0417 | 0.0 | 0.038090 | NaN | {'__MISSING__': 0.0} | NaN | NaN |
114 rows × 41 columns
Downloading table |████████████████████████████████████████| 500/500 [100%] in 0
| GROCERYCUSTOMERGUID | PRODUCTGROUP | CUSTOMER_Age_band | CUSTOMER_Latest_invoice_Amount | CUSTOMER_Count_of_invoice_14d | CUSTOMER_Avg_of_invoice_Amount_14d | CUSTOMER_Std_of_invoice_Amount_14d | CUSTOMER_Latest_invoice_Amount_Z_Score_to_invoice_Amount_28d | CUSTOMER_vs_OVERALL_item_TotalCost_across_product_ProductGroups_26w | CUSTOMER_x_PRODUCTGROUP_Sum_of_item_TotalCost_14d | CUSTOMER_x_PRODUCTGROUP_Time_Since_Latest_Timestamp | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 14f94723-4cae-4041-a11a-a044df1a5a5f | Fromages | 60-64 | 14.28 | NaN | NaN | NaN | 1.000000 | 0.373275 | NaN | 1527.861052 |
| 1 | d4559f7d-eb28-42c6-b47d-847de24952c2 | Fromages | 65-69 | 20.04 | NaN | NaN | NaN | NaN | 0.370545 | NaN | 2177.017718 |
| 2 | 1d363f8c-88f4-49eb-a107-4f1e2fbe6722 | Fromages | 25-29 | 73.16 | NaN | NaN | NaN | NaN | 0.781391 | NaN | 1118.766885 |
| 3 | 768e57df-7513-412b-a466-effd270ad6a6 | Fromages | 65-69 | 7.16 | 3.0 | 8.246667 | 4.395121 | -0.644055 | 0.650126 | NaN | 1357.819107 |
| 4 | 48f6e550-ce63-457e-ad14-d511ee934661 | Fromages | 40-44 | 24.62 | 1.0 | 24.620000 | 0.000000 | -0.219845 | 0.753619 | NaN | 475.681329 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 495 | c1b3224a-5dbb-427d-87d3-3882c6bb1278 | Fromages | 50-54 | 6.69 | NaN | NaN | NaN | NaN | 0.104953 | NaN | NaN |
| 496 | 261d2979-0568-4544-8be0-32355049e565 | Fromages | 65-69 | 2.00 | NaN | NaN | NaN | NaN | 0.317982 | NaN | NaN |
| 497 | 825ee709-2f85-49e2-bec7-27bea06efe3a | Fromages | 45-49 | 3.00 | 2.0 | 5.995000 | 2.995000 | -0.990561 | 0.375129 | NaN | NaN |
| 498 | ea68ce6b-b3c3-4ba5-a471-f11b1c5bd892 | Fromages | 45-49 | 4.50 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 499 | b8b00613-2e48-4eed-8971-61718990a994 | Fromages | 45-49 | 10.00 | 2.0 | 6.000000 | 4.000000 | 1.264961 | 0.579119 | NaN | NaN |
500 rows × 11 columns
# download parquet file
batch_features.download()
Downloading table |████████████████████████████████████████| 114/114 [100%] in 0
PosixPath('BATCH_FEATURE_TABLE_68ef65eb498f1c7d8ca81659.parquet')
PosixPath('BATCH_FEATURE_TABLE_666959284c98806ac301afa0.parquet')
# delete if not needed any more
batch_features.delete()
Done! |████████████████████████████████████████| 100% in 9.2s (0.11%/s) Done! |████████████████████████████████████████| 100% in 6.1s (0.17%/s) Done! |████████████████████████████████████████| 100% in 6.1s (0.17%/s)
Disable Deployment¶
deployment = catalog.get_deployment(deployment_name)
# Disable deployment
deployment.disable()
Done! |████████████████████████████████████████| 100% in 24.3s (0.04%/s) Done! |████████████████████████████████████████| 100% in 12.1s (0.08%/s)
# The deployment is still part of the catalog but disabled
catalog.list_deployments()
| id | name | feature_list_name | feature_list_version | num_feature | enabled | |
|---|---|---|---|---|---|---|
| 0 | 68ef64e5c712940cada35ec3 | Loan Application: simple feature list with 40 ... | 40 features for Credit Default | V251015 | 40 | False |