GET /query
Samples a random user and query from the loaded dataset.
Response:
{
"user_id": "8a2f5b18-1a23-4c72-8de1-9c7d4a89ff01",
"query_id": "7b9f3a12-6d15-4c9f-92da-348ab2a83b10",
"query_text": "economic recovery 2025"
}Usage:
curl http://localhost:3000/queryPOST /ranklist
Simulates user actions for a ranked list of articles given a query ID and user ID. There are 200 different users in the simulation.
Request Body:
{
"query_id": "7b9f3a12-6d15-4c9f-92da-348ab2a83b10",
"user_id": "8a2f5b18-1a23-4c72-8de1-9c7d4a89ff01",
"ranked_article_ids": [
"550e8400-e29b-41d4-a716-446655440000",
"550e8400-e29b-41d4-a716-446655440001",
"550e8400-e29b-41d4-a716-446655440002"
]
}Response:
{
"actions": [
[
"Click",
{"Dwell": {"secs": 45, "nanos": 123000000}},
"Like"
],
[],
[
"Click",
{"Dwell": {"secs": 20, "nanos": 456000000}}
]
]
}Response Format:
actions: Array of action sequences, one for each article in the ranked list- Empty array
[]indicates the user skipped that article - Non-empty arrays contain ordered user actions:
"Click": User clicked on the article{"Dwell": {...}}: Time spent reading (follows Click)"Like": User liked the article (optional)"Share": User shared the article (optional)"Bookmark": User bookmarked the article (optional)
Files: code/logistic_regression/
Config: configs/logistic_regression_config.yaml
A pointwise Learning-to-Rank system that predicts click probability for user-article pairs using logistic regression.
Data Preparation:
- Processes historical interaction logs from
baseline_logs_path - Creates binary labels:
1for clicked articles,0for skipped articles - Combines article features with user profile vectors
- Outputs structured dataset with features
Xand labelsy
Model Training:
- Splits data into 80% training and 20% testing sets
- Applies
StandardScalernormalization for feature scaling - Trains
LogisticRegressionwithclass_weight="balanced"to handle click imbalance - Saves trained model and scaler using
joblib
Setup:
- Loads pre-trained model and scaler
- Connects to Elasticsearch for candidate retrieval
Ranking Process:
- Retrieves top N candidates from Elasticsearch based on query text
- Handles cold start users by falling back to Elasticsearch ranking
- Constructs feature vectors:
[Article_Features + User_Features] - Applies scaling and predicts click probabilities
- Ranks articles by predicted probability (highest first)
Simulation Loop:
- Fetches user queries and generates personalized rankings
- Posts rankings to simulator and logs user interactions
- Creates feedback loop for model retraining
Files: code/reinforcement_learning/
Config: configs/rl_config.yaml
An online Learning-to-Rank system using contextual bandits with epsilon-greedy exploration strategy.
RLAgent Class:
curr_version: Model iteration numberexplore_rate: Epsilon value for exploration probabilitymodel: Random Forest classifier for decision making
Mathematical Framework:
State Representation:
Feature vector construction for user u and document d:
V_u is user preference vector, V_d is document attributes, and ⊙ is element-wise multiplication.
Epsilon-Greedy Policy: $$\text{Action} = \begin{cases} \text{Random Shuffle} & \text{with probability } \epsilon \ \text{Argmax } P(\text{click}|x) & \text{with probability } 1 - \epsilon \end{cases}$$
Scoring:
Iterative Learning Process:
- Bootstrap (v₀ → v₁): Train initial model on baseline logs
-
Iterative Collection: For each version k:
- Load model vₖ
- Interact with simulator using epsilon-greedy policy
- Log interactions to intermediate logs
- Aggregated Training: Train vₖ₊₁ on combined data: $$\mathcal{D}{train} = \mathcal{D}{baseline} \cup \mathcal{D}{iter_1} \cup \ldots \cup \mathcal{D}{iter_k}$$
Binary Classification:
- Target
y=1: User clicked the article - Target
y=0: Article shown but not clicked
Pure Exploitation Mode:
- Disables exploration (ε=0) for final evaluation
- Loads specific model version and feature definitions
- Handles cold start users with Elasticsearch fallback
- Ranks by predicted click probability
- Logs results for offline analysis
Files: code/rank_net/
Config: configs/rank_net_config.yaml
Paper: RankNet: A Ranking Approach to Learning
A pairwise Learning-to-Rank model using neural networks to minimize probabilistic ranking loss.
Neural Network Configuration:
input_dim: Feature dimension (dynamic + static + user features)hidden_dims: List of hidden layer sizesactivation: Activation function (tanh, relu, sigmoid, gelu)
Mathematical Foundation:
Pairwise Probability:
For documents i and j with scores sᵢ and sⱼ:
Cost Function (RankNet Loss):
Relevance Scoring:
Combines explicit feedback with dwell time:
Action Weights:
- Click: +1.0
- Like: +2.0
- Bookmark: +3.0
Pair Construction:
relevance(doc_a) > relevance(doc_b)→target_p = 1.0relevance(doc_a) == relevance(doc_b)→target_p = 0.5
Inference Process:
- Load PyTorch model, scalers, and feature stores
- Retrieve candidate documents from Elasticsearch
- Construct feature vectors (dynamic + static + user)
- Predict scalar scores for each document
- Rank documents by predicted scores (descending)
Files: code/lambda_mart/
Config: configs/lambda_mart_config.yaml
Paper: From RankNet to LambdaRank to LambdaMART
A boosted tree implementation of LambdaRank that optimizes information retrieval metrics directly.
LambdaMART Parameters:
n_trees: Number of boosting roundslearning_rate: Scaling factor for tree predictionsmax_leaf_nodes: Maximum leaves per treesigma: Sigmoid parameter for probability curve
Mathematical Framework:
Lambda Gradients:
Hessian Calculation:
Newton Step (Leaf Values):
Query Group Processing:
- Maps string Query IDs to integer
qids for grouping - Constructs feature vectors:
[Dynamic, Article, User Features] - Uses relevance scores to compute ideal NDCG
- Iteratively adds trees to minimize listwise cost
Ensemble Prediction:
Inference Steps:
- Load ensemble model and feature stores
- Retrieve Elasticsearch candidates
- Construct feature matrices with consistent ordering
- Predict scores using tree ensemble
- Rank documents by ensemble scores
Evaluates personalized ranking models against baseline Elasticsearch using controlled experiments.
Process Flow:
- Fetch
(user_id, query_text)from simulator - Assign user to experiment group via GrowthBook
- Generate rankings:
- Control: Elasticsearch baseline
- Variant: ML model inference
- Send rankings to simulator and collect user actions
- Log interactions with dynamic features
- Update click-through rate and dwell time statistics
GrowthBookManager Class:
- Implements deterministic user assignment using consistent hashing
- Maintains 50-50 weighted split between control and variant
- Ensures stable assignment across user sessions
- Tracks experiment metrics for statistical analysis
Feature Configuration:
- Feature:
"personalized-ranking" - Variations:
False(control),True(variant) - Hash attribute: User ID
- Salt: Prevents experiment collision
Tracked Metrics:
{
"control": {"impressions": 0, "clicks": 0, "dwell_time": 0.0},
"variant": {"impressions": 0, "clicks": 0, "dwell_time": 0.0}
}- Multi-language support: Configurable language detection and processing
- Custom stopwords: Language-specific stopword removal
- Feature extraction: BM25 score, title length, text length
- Cold start handling: Fallback to Elasticsearch for new users
- Feature caching: Efficient storage and retrieval of computed features
- Batch processing: Optimized handling of multiple queries
- Click-through Rate (CTR): Percentage of clicked results
- Dwell Time: Time spent reading articles
- NDCG: Normalized Discounted Cumulative Gain
- Statistical Significance: A/B test result validation