๐ markrel - Markov chain model for document relevance prediction
Project description
๐ markrel
Markov Chain Document Relevance โ School your documents with Markov chains!
๐ What is markrel? A fast, interpretable Python library that uses Markov chains to predict document relevance. Like a school of mackerel navigating the seas, markrel traces probabilistic paths through similarity space to find the most relevant documents.
๐๐๐
๐๐๐๐
๐๐๐๐๐ โ Your documents
๐๐๐๐ swimming through
๐๐๐ relevance space!
๐ Table of Contents
- ๐ Overview
- โก Quick Start
- ๐ Tutorial
- ๐ฏ Why markrel?
- ๐ Benchmarks
- ๐ง Installation
- ๐จ How It Works
- โ Advantages & Use Cases
- โ Limitations
- ๐ API Reference
- ๐ License
๐ Overview
markrel predicts whether a document is relevant to a query using Markov chains and similarity metrics. It's designed for:
- ๐ Semantic search re-ranking โ Filter top-k results with learned relevance
- ๐ง Document classification โ Sort documents by relevance to topics
- ๐ค Response selection โ Pick best answers from candidate pool
- โก High-throughput filtering โ Process 50K+ documents/second
Key Features
| Feature | Description |
|---|---|
| ๐ 8 Similarity Metrics | Cosine, Euclidean, Jaccard, Overlap, Dice, Manhattan, Chebyshev, Dot Product |
| ๐ง Markov Chain Learning | Learns P(relevance) from your data, not generic rules |
| ๐ฏ 3 Optimization Modes | Tune for F1, Recall, or Precision based on your needs |
| โก Fast Inference | 50K+ samples/second after training |
| ๐ง Embedding Agnostic | Works with BERT, OpenAI, sentence-transformers, or TF-IDF |
| ๐ Interpretable | See exactly why a document was flagged as relevant |
โก Quick Start (3 Minutes)
1. Install
pip install markrel
2. Train & Predict
from markrel import MarkovRelevanceModel
# Your data: queries, documents, and relevance labels
queries = ["machine learning tutorial", "baking recipes", "neural networks"]
documents = ["intro to ML", "best chocolate cake", "deep learning guide"]
labels = [1, 0, 1] # 1 = relevant, 0 = not relevant
# Create and train (using optimal config from benchmarks)
model = MarkovRelevanceModel(
metrics=["euclidean"], # Best single metric
n_bins=35, # Optimized for F1
bin_strategy="uniform"
)
model.fit(queries, documents, labels)
# Predict relevance
probs = model.predict_proba(
["deep learning", "pasta recipes"],
["neural networks", "italian cooking"]
)
print(probs) # [0.82, 0.15]
3. Use with Modern Embeddings
from sentence_transformers import SentenceTransformer
# Load BGE-M3 (best model per benchmarks)
encoder = SentenceTransformer('BAAI/bge-m3')
# Encode your texts
query_emb = encoder.encode(["what is ML?"])
doc_emb = encoder.encode(["machine learning is..."])
# Train with embeddings (disable TF-IDF)
model = MarkovRelevanceModel(
metrics=["euclidean"],
use_text_vectorizer=False # Use your embeddings
)
model.fit(query_emb, doc_emb, [1])
That's it! ๐ You now have a relevance model trained on your data.
๐ Tutorial: Complete Walkthrough
Step 1: Prepare Your Data
Markrel needs (query, document, label) triples:
# Example: Question-Answer Relevance Dataset
queries = [
"What is machine learning?",
"How does photosynthesis work?",
"Best pizza recipe?",
"Explain neural networks",
"Types of pasta?",
]
documents = [
"Machine learning is a subset of AI...",
"Photosynthesis converts sunlight into energy...",
"Authentic Neapolitan pizza requires...",
"Neural networks are computing systems...",
"Popular pasta types include spaghetti...",
]
# Labels: 1 = relevant, 0 = not relevant
labels = [1, 1, 0, 1, 0]
Step 2: Choose Your Configuration
Based on our benchmarks, here are recommended configs:
# Option A: Balanced (Best F1)
model = MarkovRelevanceModel(
metrics=["euclidean"],
n_bins=35,
bin_strategy="uniform"
)
# Option B: Catch Everything (Best Recall)
model = MarkovRelevanceModel(
metrics=["euclidean"],
n_bins=7,
bin_strategy="uniform"
)
# Option C: Strict Filtering (Best Precision)
model = MarkovRelevanceModel(
metrics=["cosine", "euclidean"],
n_bins=24,
bin_strategy="uniform"
)
Step 3: Train the Model
# Train on your data
model.fit(queries, documents, labels)
# Inspect what the model learned
print(model.summary())
Step 4: Make Predictions
# Get probability scores
probabilities = model.predict_proba(
new_queries,
new_documents
)
# Apply threshold (default 0.5, or optimized threshold from benchmarks)
threshold = 0.251 # F1-optimized threshold
predictions = probabilities >= threshold
# Or use built-in prediction with custom threshold
predictions = model.predict(
new_queries,
new_documents,
threshold=0.251
)
Step 5: Advanced Usage with Embeddings
For best results, use modern embeddings:
from sentence_transformers import SentenceTransformer
import numpy as np
# Load encoder (BGE-M3 recommended)
encoder = SentenceTransformer('BAAI/bge-m3')
# Large-scale training
train_queries = encoder.encode(train_query_texts)
train_docs = encoder.encode(train_doc_texts)
test_queries = encoder.encode(test_query_texts)
test_docs = encoder.encode(test_doc_texts)
# Train markrel
model = MarkovRelevanceModel(
metrics=["euclidean"],
n_bins=35,
use_text_vectorizer=False # Important!
)
model.fit(train_queries, train_docs, train_labels)
# Batch prediction (fast!)
probs = model.predict_proba(test_queries, test_docs)
Complete Example: Email Classifier
from markrel import MarkovRelevanceModel
from sentence_transformers import SentenceTransformer
# Load data
emails = ["Urgent: Project deadline moved up", "Weekly team newsletter", "Invoice #1234 payment required"]
queries = ["urgent project emails", "team updates", "billing notifications"]
labels = [1, 0, 1] # Which emails are relevant to which query
# Encode with BGE-M3
encoder = SentenceTransformer('BAAI/bge-m3')
email_emb = encoder.encode(emails)
query_emb = encoder.encode(queries)
# Train relevance classifier
model = MarkovRelevanceModel(
metrics=["euclidean"],
n_bins=35,
use_text_vectorizer=False
)
model.fit(query_emb, email_emb, labels)
# Classify new emails
new_emails = encoder.encode([
"RE: Project timeline discussion",
"Your Amazon order has shipped",
"URGENT: Server outage in production"
])
search_query = encoder.encode(["urgent project emails"])
relevance_scores = model.predict_proba(search_query, new_emails)
print(f"Email relevance scores: {relevance_scores}")
# Output: [0.78, 0.12, 0.91]
๐ฏ Why markrel?
The Problem
Traditional document relevance uses:
- Fixed thresholds: "Cosine > 0.7 = relevant" (ignores domain-specific patterns)
- Linear scoring: Assumes similarity linearly predicts relevance
- Black-box models: Can't explain why a document was selected
The Solution
Markrel uses Markov chains to learn non-linear relevance patterns:
Similarity Score โ Bin Mapping โ P(Relevance)
0.95 โโโ Bin 9 โโโ P(rel)=0.92 โ Highly relevant
0.75 โโโ Bin 7 โโโ P(rel)=0.68 โ Maybe relevant
0.45 โโโ Bin 4 โโโ P(rel)=0.23 โ Probably not
0.15 โโโ Bin 1 โโโ P(rel)=0.05 โ Not relevant
Each bin learns its own probability from your training data, capturing domain-specific patterns.
๐ Benchmarks
WikiQA Question-Answer Relevance
Results on 6,165 test samples (4.8% positive class):
| Optimization | F1 | Recall | Precision | Config | Use Case |
|---|---|---|---|---|---|
| Balanced | 0.370 | 0.362 | 0.379 | 35 bins, euclidean | General purpose |
| Recall | 0.091 | 1.000 | 0.048 | 7 bins, euclidean | Catch all relevant |
| Precision | 0.007 | 0.003 | 1.000 | 24 bins, cos+euc | Strict filtering |
Embedding Model Comparison
| Model | F1 | AUC | Speed |
|---|---|---|---|
| BGE-M3 โญ | 0.343 | 0.815 | 51K/s |
| RoBERTa-large | 0.323 | 0.828 | 54K/s |
| MiniLM-L6 | 0.322 | 0.799 | 61K/s |
Winner: BGE-M3 for accuracy, MiniLM for speed.
๐ง Installation
From PyPI (when published)
pip install markrel
From Source
git clone https://github.com/yourusername/markrel.git
cd markrel
pip install -e .
Development Install
pip install -e ".[dev]"
pytest tests/ -v
Dependencies
numpy >= 1.20.0
scikit-learn >= 1.0.0
Optional for embeddings:
sentence-transformers >= 2.0.0
๐จ How It Works
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๐ markrel Pipeline โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ฅ INPUT ๐ง PROCESSING
โโโโโโโโ โโโโโโโโโโโ
โโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ Query โโโโ โ Embed with โ
โ "What โ โ โ BGE-M3 โ
โ is ML?" โ โ โ (1024-dim) โ
โโโโโโโโโโโโ โ โโโโโโโโโโโโโโโ
โ โ
โโโโโโโโโโโโ โ โผ
โ Document โโโโ โโโโโโโโโโโโโโโ
โ "Machine โ โ Similarity โ
โ learning โ โ Computation โ
โโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโ
โ ๐ Markov โ
โ Chain โ
โ โ
โ Bin 0: 5% โ
โ Bin 4: 23% โ
โ Bin 7: 68% โ
โ Bin 9: 92% โ
โโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโ
โ P(Relevant) โ
โ 0.75 โ
โโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโ
โ โ
Relevantโ
โโโโโโโโโโโโโโโ
๐ค OUTPUT: Probability + Prediction
The Markov Chain
Unlike fixed thresholds, markrel learns a probability for each similarity bin:
Similarity: 0.0 โโโ 0.2 โโโ 0.4 โโโ 0.6 โโโ 0.8 โโโ 1.0
โ โ โ โ โ โ
โผ โผ โผ โผ โผ โผ
Bin: [Bin0] [Bin1] [Bin2] [Bin3] [Bin4] [Bin5]
โ โ โ โ โ โ
P(Relevant): 0.05 0.12 0.35 0.68 0.89 0.95
โ โ โ โ โ โ
๐ซ โ ๏ธ โ ๏ธ โ โ โ
Not Rel. Maybe Likely Highly
Relevant Relevant Relevant
โ Advantages & Use Cases
โ Advantages
| Feature | Benefit |
|---|---|
| ๐ฏ Domain Adaptable | Learns from YOUR data, not generic assumptions |
| ๐ Non-linear | Captures complex similarityโrelevance patterns |
| ๐ง Tunable | Optimize for F1, Recall, or Precision |
| โก Fast | 50K+ samples/second after training |
| ๐ Interpretable | See P(relevance) per bin; debug predictions |
| ๐งฉ Embedding Agnostic | Use BERT, OpenAI, or TF-IDF |
| ๐ฆ Lightweight | No GPU required; pure NumPy |
โ Best Use Cases
| Use Case | Why markrel Works |
|---|---|
| ๐ Semantic Search Re-ranking | Fast second-stage filtering of retrieved docs |
| ๐ง Email Classification | Learn relevance patterns from your mail |
| ๐ Document Similarity | Semantic matching beyond keywords |
| ๐ค Chatbot Responses | Select best response from candidates |
| โก Real-time Filtering | High-throughput with low latency |
โ Limitations
| Limitation | Solution |
|---|---|
| Requires labeled data | Use transfer learning or synthetic labels |
| Class imbalance | Use Recall-optimized config for rare positives |
| No native ranking | Pair with BM25 for initial retrieval |
| Single-pair only | Use cross-encoders for document sets |
๐ API Reference
MarkovRelevanceModel
from markrel import MarkovRelevanceModel
model = MarkovRelevanceModel(
metrics=["euclidean"], # Similarity metrics to use
n_bins=35, # Number of bins (10-50)
bin_strategy="uniform", # "uniform" or "quantile"
smoothing=1.0, # Laplace smoothing
combine_rule="bayesian", # "bayesian" or "mean"
use_text_vectorizer=True # Auto-vectorize text
)
Methods:
fit(queries, documents, labels)โ Train the modelpredict_proba(queries, documents)โ Get relevance probabilities [0-1]predict(queries, documents, threshold=0.5)โ Binary predictions {0, 1}summary()โ Model statisticsget_metric_probabilities(metric)โ Bin probabilities
๐ License
MIT License โ See LICENSE for details.
๐ About the Name
Markrel = Markov Chain + Relevance
Like a school of mackerel swimming through the ocean, markrel navigates the sea of documents, tracing probabilistic paths to find the most relevant matches. Each fish (document) follows the currents (similarity scores) toward their destination (relevance). ๐๐๐
Ready to school your documents? Get started with Quick Start โ
๐
๐๐๐
๐๐๐๐๐
๐๐๐
๐
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file markrel-0.1.0.tar.gz.
File metadata
- Download URL: markrel-0.1.0.tar.gz
- Upload date:
- Size: 1.8 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5601b392d2ae35bb502c1c156020b19a91f91be329b94fca6116b9f4dcc4e05
|
|
| MD5 |
86e7889f53151f0da72f84146837b924
|
|
| BLAKE2b-256 |
7af72d067520e914877fe31d1f23f8e83244cadd79c9560e69b2453be9b70260
|
Provenance
The following attestation bundles were made for markrel-0.1.0.tar.gz:
Publisher:
release.yml on petabyte/markrel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
markrel-0.1.0.tar.gz -
Subject digest:
c5601b392d2ae35bb502c1c156020b19a91f91be329b94fca6116b9f4dcc4e05 - Sigstore transparency entry: 1170339619
- Sigstore integration time:
-
Permalink:
petabyte/markrel@f9f84e2d47cefe04ac81081fe7cd1c2257c3dfd7 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/petabyte
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f9f84e2d47cefe04ac81081fe7cd1c2257c3dfd7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file markrel-0.1.0-py3-none-any.whl.
File metadata
- Download URL: markrel-0.1.0-py3-none-any.whl
- Upload date:
- Size: 35.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc757fe2147431326927fbe3ad8fad44e662954e6f229f4789c1f775ee701396
|
|
| MD5 |
fdb567a8e41702af03358848f7c6e21e
|
|
| BLAKE2b-256 |
f30bea5262f785cf778b420dc1f55809f138dccae263f04013c709c2aaa7dcad
|
Provenance
The following attestation bundles were made for markrel-0.1.0-py3-none-any.whl:
Publisher:
release.yml on petabyte/markrel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
markrel-0.1.0-py3-none-any.whl -
Subject digest:
dc757fe2147431326927fbe3ad8fad44e662954e6f229f4789c1f775ee701396 - Sigstore transparency entry: 1170339652
- Sigstore integration time:
-
Permalink:
petabyte/markrel@f9f84e2d47cefe04ac81081fe7cd1c2257c3dfd7 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/petabyte
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f9f84e2d47cefe04ac81081fe7cd1c2257c3dfd7 -
Trigger Event:
push
-
Statement type: