Implement a Text-Embedding Recommender Training Pipeline
LinkedInMachine Learning Engineer · Technical ScreenLast updated
Tests the ability to structure an end-to-end, leakage-resistant training pipeline for a text-embedding recommender, covering profile flattening, embedding caching, temporal splits, binary classification, and artifact serialization.
Scenario
You are tasked with building a modular, local machine learning training pipeline for an engagement recommendation system on a professional social network. The goal is to predict whether a member will click (1) or skip (0) an item (e.g., an article or post) based on semantic text representations of their profile and the item's content.
Input Schemas
Your pipeline receives three in-memory collections of records:
members: List of dicts with fieldsmember_id(str),headline(str),skills(list of str),updated_at(int timestamp).items: List of dicts with fieldsitem_id(str),title(str),body(str),created_at(int timestamp).interactions: List of dicts with fieldsmember_id(str),item_id(str),timestamp(int), andclicked(int: 0 or 1).
Assume you are provided an external embedding utility function encoder.embed(texts: list[str]) -> np.ndarray which yields fixed-size vector representations (e.g., dimension D = 128).
Pipeline Requirements
Implement or pseudocode a class RecommenderTrainingPipeline that fulfills the following specifications:
- Text Serialization & Validation: Define a deterministic strategy to convert nested member profiles (headline + skills) and item records (title + body) into clean, single text strings per entity. Validate and handle missing fields gracefully.
- Embedding Cache: Many interactions share the same members and items. Implement an in-memory caching mechanism so that unique text strings are embedded at most once.
- Temporal Splitting: Prevent temporal data leakage. Split interactions chronologically using a cut-off timestamp (e.g., 80% train, 20% validation) rather than a uniform random split.
- Feature Assembly & Modeling: For each interaction, construct feature vectors from the member and item embeddings (e.g., concatenation, element-wise difference, and Hadamard product:
[u, v, |u - v|, u * v]). Train a binary classification model (e.g., Logistic Regression or a lightweight MLP). - Evaluation & Artifact Export: Compute validation metrics (ROC-AUC and Log Loss). Package the trained model, feature configuration, and encoder metadata into an exportable dictionary/bundle suitable for downstream inference.
Expected Interface
class RecommenderTrainingPipeline:
def __init__(self, encoder, train_ratio: float = 0.8):
self.encoder = encoder
self.train_ratio = train_ratio
self.cache = {}
def prepare_data(
self, members: list[dict], items: list[dict], interactions: list[dict]
) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
"""Validates, caches embeddings, generates feature vectors, and returns temporal train/val splits: (X_train, y_train, X_val, y_val)."""
pass
def train(self, X_train: np.ndarray, y_train: np.ndarray):
"""Trains the binary classification model."""
pass
def evaluate(self, X_val: np.ndarray, y_val: np.ndarray) -> dict[str, float]:
"""Computes AUC-ROC and Log Loss on validation data."""
pass
def export_artifact(self, filepath: str) -> None:
"""Serializes model parameters and preprocessing metadata for inference."""
pass
Hints
Hint 1
To avoid future data leaking into the past, sort the interactions strictly by timestamp and split by a threshold timestamp rather than shuffling indices.
Hint 2
Hash or normalize the flattened string representations of members and items to use as cache keys so duplicate text across entities is embedded only once.
Hint 3
Combining member and item embeddings via element-wise difference and Hadamard product alongside concatenation captures interaction signals that simple vector concatenation might miss in linear models.
Follow-up questions
- How would you ensure point-in-time correctness if members update their profiles frequently over the course of the interaction log?
- If the item inventory scales to tens of millions of records, how would you transition this architecture from a late-fusion classifier to a dual-tower model for low-latency retrieval?
- How would you handle cold-start members or items where text fields are empty or poorly populated?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.