GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — feat(cli): Add recommendation template for feast init by doc-johnson · Pull Request #6078 · feast-dev/feast

feat(cli): Add recommendation template for feast init #6078

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Sign up for GitHub

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
doc-johnson wants to merge 14 commits into feast-dev:master
base: master
Loading
Loading
from doc-johnson:feat/recommendation-template

Uh oh!

There was an error while loading. Please reload this page.

Open

feat(cli): Add recommendation template for feast init #6078

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
7478002
feat(cli): Add recommendation template for feast init (#5478)
doc-johnson Mar 8, 2026
34996fa
Merge branch 'master' into feat/recommendation-template
franciscojavierarceo Jul 8, 2026
9e52058
Merge remote-tracking branch 'upstream/master' into feat/recommendati…
doc-johnson Jul 14, 2026
7335fac
test: Add recommendation template artifacts test
doc-johnson Jul 14, 2026
edbff11
Merge remote-tracking branch 'upstream/master' into feat/recommendati…
doc-johnson Jul 15, 2026
8be3517
Merge branch 'master' into feat/recommendation-template
doc-johnson Jul 21, 2026
dce09f2
Merge branch 'master' into feat/recommendation-template
doc-johnson Aug 12, 2026
bdd4089
Merge branch 'master' into feat/recommendation-template
doc-johnson Aug 14, 2026
8462228
Merge remote-tracking branch 'upstream/master' into feat/recommendati…
doc-johnson Aug 17, 2026
4911874
fix(cli): Make recommendation template initialization self-contained
doc-johnson Aug 18, 2026
2ff60bc
Merge remote-tracking branch 'upstream/master' into feat/recommendati…
doc-johnson Aug 18, 2026
ea79119
Merge branch 'master' into feat/recommendation-template
doc-johnson Aug 18, 2026
db99b69
Merge branch 'master' into feat/recommendation-template
doc-johnson Aug 19, 2026
82e4bcb
fix: Refresh secret scan baseline
doc-johnson Sep 11, 2026
File filter
Filter by extension

Clear filters
Conversations
Failed to load comments.
Loading

Uh oh!

There was an error while loading. Please reload this page.

Jump to
Jump to file
Failed to load files.
Loading

Uh oh!

There was an error while loading. Please reload this page.

Diff view
Diff view

Some comments aren't visible on the classic Files Changed page.

There are no files selected for viewing

2 changes: 1 addition & 1 deletion 2 .secrets.baseline
Show comments
View file
Open in desktop

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Oops, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

1 change: 1 addition & 0 deletions 1 sdk/python/feast/cli/cli.py
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ def materialize_incremental_command(
"ray_rag",
"rag",
"pytorch_nlp",
"recommendation",
],
case_sensitive=False,
),
Expand Down
Empty file added 0 sdk/python/feast/templates/recommendation/__init__.py
Show comments
View file
Open in desktop
Empty file.
149 changes: 149 additions & 0 deletions 149 sdk/python/feast/templates/recommendation/bootstrap.py
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
from feast.file_utils import replace_str_in_file


def bootstrap() -> None:
import pathlib
from datetime import datetime, timedelta

import numpy as np
import pandas as pd

repo_path = pathlib.Path(__file__).parent.absolute() / "feature_repo"
project_name = pathlib.Path(__file__).parent.absolute().name
data_path = repo_path / "data"
data_path.mkdir(exist_ok=True)

products = [
(
"P001",
"Wireless Noise-Cancelling Headphones",
"Premium over-ear headphones with active noise cancellation and 30-hour battery life.",
"Electronics",
299.99,
4.7,
),
(
"P002",
"Bluetooth Portable Speaker",
"Waterproof portable speaker with deep bass and 12-hour playtime.",
"Electronics",
79.99,
4.5,
),
(
"P003",
"Mechanical Gaming Keyboard",
"RGB mechanical keyboard with Cherry MX switches and programmable keys.",
"Electronics",
149.99,
4.6,
),
(
"P004",
"Ergonomic Wireless Mouse",
"Vertical ergonomic mouse designed to reduce wrist strain.",
"Electronics",
49.99,
4.3,
),
(
"P005",
"Python Machine Learning Cookbook",
"Practical recipes for building ML models with scikit-learn and TensorFlow.",
"Books",
39.99,
4.4,
),
(
"P006",
"Data Engineering Fundamentals",
"Comprehensive guide to building modern data pipelines and architectures.",
"Books",
44.99,
4.6,
),
(
"P007",
"Introduction to Deep Learning",
"Beginner-friendly deep learning textbook with hands-on PyTorch examples.",
"Books",
54.99,
4.7,
),
(
"P008",
"Trail Running Shoes",
"Lightweight trail running shoes with superior grip and cushioning.",
"Sports",
129.99,
4.6,
),
(
"P009",
"Premium Yoga Mat",
"Non-slip extra-thick yoga mat with carrying strap.",
"Sports",
34.99,
4.4,
),
(
"P010",
"Resistance Bands Set",
"Set of 5 resistance bands with varying tension levels for home workouts.",
"Sports",
24.99,
4.3,
),
(
"P011",
"Robot Vacuum Cleaner",
"Self-navigating robot vacuum with app control and auto-charging.",
"Home",
349.99,
4.5,
),
(
"P012",
"Air Purifier with HEPA Filter",
"Room air purifier with true HEPA filter and air quality sensor.",
"Home",
199.99,
4.6,
),
]

embedding_dim = 384
embeddings = np.zeros((len(products), embedding_dim), dtype=np.float32)
embeddings[np.arange(len(products)), np.arange(len(products))] = 1.0

end_date = datetime.now().replace(microsecond=0, second=0, minute=0)
start_date = end_date - timedelta(days=15)
timestamps = [start_date + timedelta(hours=i) for i in range(len(products))]

columns = [
"product_id",
"product_name",
"description",
"category",
"price",
"rating",
]
df = pd.DataFrame(products, columns=columns)
df["price"] = df["price"].astype(np.float32)
df["rating"] = df["rating"].astype(np.float32)
df["embedding"] = [embedding.tolist() for embedding in embeddings]
df["event_timestamp"] = timestamps
df["created"] = end_date

products_path = data_path / "products.parquet"
df.to_parquet(path=str(products_path), allow_truncated_timestamps=True)

example_py_file = repo_path / "feature_definitions.py"
replace_str_in_file(example_py_file, "%PROJECT_NAME%", str(project_name))
replace_str_in_file(
example_py_file, "%PARQUET_PATH%", str(products_path.relative_to(repo_path))
)


if __name__ == "__main__":
bootstrap()
Empty file added 0 sdk/python/feast/templates/recommendation/feature_repo/__init__.py
Show comments
View file
Open in desktop
Empty file.
43 changes: 43 additions & 0 deletions 43 sdk/python/feast/templates/recommendation/feature_repo/feature_definitions.py
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from datetime import timedelta

from feast import Entity, FeatureService, FeatureView, Field, FileSource, Project
from feast.types import Array, Float32, String

project = Project(
name="%PROJECT_NAME%",
description="A project for product recommendations using vector similarity search",
)

product = Entity(name="product", join_keys=["product_id"])

products_source = FileSource(
name="products_source",
path="%PARQUET_PATH%",
timestamp_field="event_timestamp",
created_timestamp_column="created",
)

# test_workflow.py writes model embeddings before materialization.
product_embeddings = FeatureView(
name="product_embeddings",
entities=[product],
ttl=timedelta(days=365),
schema=[
Field(
name="embedding", dtype=Array(Float32), vector_index=True, vector_length=384
),
Field(name="product_name", dtype=String),
Field(name="description", dtype=String),
Field(name="category", dtype=String),
Field(name="price", dtype=Float32),
Field(name="rating", dtype=Float32),
],
online=True,
source=products_source,
tags={"team": "recommendations"},
)

recommendation_service = FeatureService(
name="recommendation_service",
features=[product_embeddings],
)
13 changes: 13 additions & 0 deletions 13 sdk/python/feast/templates/recommendation/feature_repo/feature_store.yaml
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
project: my_project
# By default, the registry is a file (but can be turned into a more scalable SQL-backed registry)
registry: data/registry.db
# The provider primarily specifies default offline / online stores & storing the registry in a given cloud
provider: local
online_store:
type: sqlite
path: data/online_store.db
vector_enabled: true
entity_key_serialization_version: 3
# By default, no_auth for authentication and authorization, other possible values kubernetes and oidc. Refer the documentation for more details.
auth:
type: no_auth
70 changes: 70 additions & 0 deletions 70 sdk/python/feast/templates/recommendation/feature_repo/test_workflow.py
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import subprocess
import sys
from datetime import datetime
from pathlib import Path

import numpy as np
import pandas as pd

from feast import FeatureStore


def run_demo() -> None:
try:
from sentence_transformers import SentenceTransformer
except ImportError:
print("sentence-transformers is required: pip install sentence-transformers")
sys.exit(1)

model = SentenceTransformer("all-MiniLM-L6-v2")
products_path = Path("data/products.parquet")
products = pd.read_parquet(products_path)
descriptions = (products["product_name"] + ". " + products["description"]).tolist()
embeddings = model.encode(descriptions, normalize_embeddings=True)
products["embedding"] = [
embedding.astype(np.float32).tolist() for embedding in embeddings
]
products.to_parquet(products_path, allow_truncated_timestamps=True)

print("\nApplying feature definitions")
subprocess.run(["feast", "apply"], check=True)

print("\nLoading features into the online store")
store = FeatureStore(repo_path=".")
store.materialize_incremental(end_date=datetime.now())

query = "gaming laptop accessories"
print(f"\nSearching for: {query}")
query_embedding = model.encode([query], normalize_embeddings=True)[0].tolist()

results = store.retrieve_online_documents_v2(
features=[
"product_embeddings:embedding",
"product_embeddings:product_id",
"product_embeddings:product_name",
"product_embeddings:category",
"product_embeddings:price",
"product_embeddings:rating",
],
query=query_embedding,
top_k=5,
).to_dict()

if results and len(results.get("product_id", [])) > 0:
num_results = len(results["product_id"])
print(f" Top {num_results} recommendations:")
for i in range(num_results):
name = results["product_name"][i]
category = results["category"][i]
price = results["price"][i]
rating = results["rating"][i]
print(f" {i + 1}. {name} [{category}] - ${price:.2f} (rating: {rating})")
else:
print(" No results found.")

print("\nTearing down the feature store")
subprocess.run(["feast", "teardown"], check=True)


if __name__ == "__main__":
run_demo()
32 changes: 32 additions & 0 deletions 32 sdk/python/tests/unit/local_feast_tests/test_init.py
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
from pathlib import Path
from textwrap import dedent

import pandas as pd

from feast.repo_operations import init_repo
from feast.utils import _utc_now
from tests.utils.cli_repo_creator import CliRunner

Expand Down Expand Up @@ -81,3 +84,32 @@ def test_postgres_template_registry_path_is_parameterized() -> None:
contents = template_fs_yaml.read_text(encoding="utf-8")
expected = "path: postgresql://DB_USERNAME:DB_PASSWORD@DB_HOST:DB_PORT/DB_NAME"
assert expected in contents


def test_recommendation_template_init(tmp_path: Path) -> None:
repo_path = tmp_path / "recommendation_project"

init_repo(
"recommendation_project",
template="recommendation",
repo_path=str(repo_path),
)

feature_repo = repo_path / "feature_repo"
config = (feature_repo / "feature_store.yaml").read_text(encoding="utf-8")
assert "project: recommendation_project" in config
assert "type: sqlite" in config
assert "vector_enabled: true" in config

definitions = (feature_repo / "feature_definitions.py").read_text(encoding="utf-8")
assert "vector_index=True" in definitions
assert "vector_length=384" in definitions
assert 'name="recommendation_project"' in definitions
assert 'path="data/products.parquet"' in definitions

products_path = feature_repo / "data" / "products.parquet"
assert products_path.is_file()
products = pd.read_parquet(products_path)
assert len(products) == 12
assert all(len(embedding) == 384 for embedding in products["embedding"])
assert not (repo_path / "bootstrap.py").exists()
Add this suggestion to a batch that can be applied as a single commit. This suggestion is invalid because no changes were made to the code. Suggestions cannot be applied while the pull request is closed. Suggestions cannot be applied while viewing a subset of changes. Only one suggestion per line can be applied in a batch. Add this suggestion to a batch that can be applied as a single commit. Applying suggestions on deleted lines is not supported. You must change the existing code in this line in order to create a valid suggestion. Outdated suggestions cannot be applied. This suggestion has been applied or marked resolved. Suggestions cannot be applied from pending reviews. Suggestions cannot be applied on multi-line comments. Suggestions cannot be applied while the pull request is queued to merge. Suggestion cannot be applied right now. Please check back later.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.