Visitar URL original
docs: Add blog posts for BatchFeatureView and Spark on Kubernetes by abhijeet-dhumal · Pull Request #6444 · feast-dev/feast · GitHub
Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
docs: Fix versioning ambiguity and model caching in blog posts
Signed-off-by: abhijeet-dhumal <abhijeetdhumal652@gmail.com>
  • Loading branch information
abhijeet-dhumal committed Jul 19, 2026
commit fc83c986ee55a07d81c3611ddacbff0488ca43af
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ This reads pre-computed parquet. No Spark job triggered. No raw data scan. Point

### Offline-Only Feature Views for Training Labels

> **Data Scientist** — *"My interaction table is 500GB and training-only — it will never live in Redis. I still want it versioned, retrievable, and point-in-time correct like any other feature."*
> **Data Scientist** — *"My interaction table is 500GB and training-only — it will never live in Redis. I still want its schema and transformation logic tracked in the registry, retrievable via the same API, and point-in-time correct like any other feature."*

`online=False, offline=True` is now a first-class `BatchFeatureView` configuration:

Expand Down Expand Up @@ -174,7 +174,7 @@ def interactions(df: DataFrame) -> DataFrame:
)
```

Training labels, interaction histories, and large join tables are now first-class Feast objects — with consistent lineage, versioning, and retrieval APIs alongside your serving features.
Training labels, interaction histories, and large join tables are now first-class Feast objects — with schema and transformation logic tracked in the registry (not data versioning), consistent lineage, and the same `get_historical_features()` retrieval API as your serving features.

---

Expand Down
8 changes: 6 additions & 2 deletions infra/website/docs/blog/spark-gpu-embeddings-rag.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,11 @@ def review_embeddings(df):
@F.pandas_udf(ArrayType(FloatType()))
def _embed_udf(texts: pd.Series) -> pd.Series:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer(EMBEDDING_MODEL)
embeddings = model.encode(
# Cache on the function object — loaded once per Python worker process,
# not once per Arrow batch. Avoids repeated 90MB weight loads.
if not hasattr(_embed_udf, "_model"):
_embed_udf._model = SentenceTransformer(EMBEDDING_MODEL)
embeddings = _embed_udf._model.encode(
texts.tolist(),
normalize_embeddings=True,
batch_size=64,
Expand All @@ -163,6 +166,7 @@ A few design decisions worth noting:
- **`normalize_embeddings=True`**: produces unit vectors, making cosine similarity equivalent to dot product — faster at query time in most vector databases.
- **`batch_size=64`**: controls how many texts the model processes per GPU forward pass. Tune based on GPU memory; larger batches improve throughput until you hit VRAM limits.
- **`substr(1, 511)`**: truncates embed_text to 511 characters before encoding — `all-MiniLM-L6-v2` has a 512-token limit; truncation here avoids silent tokenizer truncation downstream.
- **Model caching via `hasattr`**: `pandas_udf` is called once per Arrow batch, not once per partition. Without caching, the 90MB model weights would be loaded from disk on every batch call. Storing the model on the function object (`_embed_udf._model`) means it's loaded once per Python worker process and reused across all batches that worker handles.

---

Expand Down