This guide shows you how to use the search functionality in BM25S Retriever, both through the web interface and via API calls.
http://localhost:9200 in your browserEnter Your Query
Configure Search Parameters
Perform Search
The search results table displays:
Temperature Experiments
Cutoff Adjustment
Zero-Relevance Filtering
curl -X POST http://localhost:9200/retrieve \
-H "Content-Type: application/json" \
-d '{
"query": "machine learning algorithms",
"temperature": 0.7,
"llm_tools_cutoff": 8.0,
"ignore_zero": true
}'
curl -X POST http://localhost:9200/retrieve \
-H "Content-Type: application/json" \
-d '{
"query": "python data science",
"temperature": 1.2,
"llm_tools_cutoff": 5.0,
"ignore_zero": false
}'
import requests
import json
class BM25SSearcher:
def __init__(self, base_url="http://localhost:9200"):
self.base_url = base_url
self.retrieve_url = f"{base_url}/retrieve"
def search(self, query, temperature=0.7, cutoff=8.0, ignore_zero=True):
"""Search documents with BM25S retriever."""
payload = {
"query": query,
"temperature": temperature,
"llm_tools_cutoff": cutoff,
"ignore_zero": ignore_zero
}
try:
response = requests.post(self.retrieve_url, json=payload)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
return {"success": False, "error": str(e)}
def search_and_format(self, query, **kwargs):
"""Search and return formatted results."""
result = self.search(query, **kwargs)
if not result.get("success"):
return f"Search failed: {result.get('error', 'Unknown error')}"
output = [
f"Found {len(result['documents'])} documents (from {result['total_retrieved']} total)",
f"Using temperature: {result['settings']['temperature']}",
f"Cutoff: {result['cutoff_percentage']}%",
""
]
for i, doc in enumerate(result["documents"], 1):
output.extend([
f"--- Document {i} ---",
f"ID: {doc['id']}",
f"Title: {doc['title']}",
f"Content: {doc['content'][:100]}{'...' if len(doc['content']) > 100 else ''}",
f"Keywords: {', '.join(doc.get('keywords', []))}",
f"BM25 Score: {doc['bm25_score']:.3f}",
f"Softmax Score: {doc['softmax_score']*100:.2f}%",
""
])
return "\n".join(output)
# Example usage
if __name__ == "__main__":
searcher = BM25SSearcher()
# Basic search
print("=== Basic Search ===")
print(searcher.search_and_format("machine learning"))
# Search with custom parameters
print("\n=== Advanced Search ===")
print(searcher.search_and_format(
"python programming",
temperature=1.5,
cutoff=10.0,
ignore_zero=False
))
# Compare temperatures
print("\n=== Temperature Comparison ===")
query = "data science"
print(f"Results for '{query}' with temperature 0.5:")
print(searcher.search_and_format(query, temperature=0.5))
print(f"\nResults for '{query}' with temperature 2.0:")
print(searcher.search_and_format(query, temperature=2.0))
def batch_search(queries, temperatures=[0.5, 1.0, 1.5]):
"""Perform multiple searches with different parameters."""
searcher = BM25SSearcher()
results = {}
for query in queries:
results[query] = {}
for temp in temperatures:
result = searcher.search(query, temperature=temp)
if result.get("success"):
results[query][f"temp_{temp}"] = {
"count": len(result["documents"]),
"top_doc": result["documents"][0]["id"] if result["documents"] else None,
"avg_score": sum(doc["softmax_score"] for doc in result["documents"]) / len(result["documents"]) if result["documents"] else 0
}
return results
# Example batch search
queries = ["machine learning", "python", "data science"]
batch_results = batch_search(queries)
for query, temps in batch_results.items():
print(f"\nQuery: {query}")
for temp_key, stats in temps.items():
print(f" {temp_key}: {stats['count']} docs, avg: {stats['avg_score']:.3f}")
The BM25S retriever indexes specific fields from your YAML documents to enable searching:
title - Document title, fully searchablecontent - Document content/description, fully searchablekeywords - Keyword list, each keyword prefixed with "keyword:" for searchid - Document identifier, stored for retrieval but not searchedparameters - Function parameters, stored in metadata onlymetadata - All metadata fields, stored but not indexedThe system combines indexed fields into a single searchable text:
# For each document, the search index contains:
title + " " + content + " keyword: keyword1 keyword: keyword2 ..."
Example:
- id: "create_order"
title: "Create New Order"
content: "Start a new purchase, buy a product, or place a customer order."
keywords: ["buy", "purchase", "place order", "checkout"]
This becomes searchable as:
"Create New Order Start a new purchase, buy a product, or place a customer order. keyword: buy keyword: purchase keyword: place order keyword: checkout"
id, parameters, or metadata fields- id: "unique_identifier" # Required: Document ID
title: "Document Title" # Required: Searchable title
content: "Description..." # Required: Searchable content
Keywords (Searchable):
keywords: ["buy", "purchase", "place order", "checkout", "start transaction"]
Metadata (Not Searchable):
metadata:
category: "orders"
provider: "internal"
updated: "2025-04-07"
version: "1.2"
documents:
- id: "create_order"
title: "Create New Order"
content: "Start a new purchase, buy a product, or place a customer order. Use this to initiate a checkout process for items."
keywords:
- "buy"
- "purchase"
- "place order"
- "checkout"
- "start transaction"
- "order item"
- "buy product"
- "new sale"
parameters:
customer_id: { type: "string" }
product_id: { type: "string" }
quantity: { type: "integer", minimum: 1 }
price: { type: "number" }
metadata:
source: "yaml"
category: "orders"
provider: "internal"
updated: "2025-04-07"
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
query |
string | required | - | Search query text |
temperature |
float | 0.7 | 0.1-10.0 | Softmax temperature control |
llm_tools_cutoff |
float | 8.0 | 0-100 | Minimum softmax percentage |
ignore_zero |
boolean | true | - | Filter zero BM25 scores |
Understanding Temperature Effects
Temperature controls how "sharp" or "flat" the softmax distribution is:
If you go above 1.0 (High Temp): You are "flattening" the distribution. You make it harder for the top choice to win. The probabilities get closer together (everything becomes more "random").
If you go below 1.0 (Low Temp): You are "sharpening" the distribution. You make the top choice stand out significantly more than the others.
Practical Temperature Ranges
{
"success": true,
"message": "Documents retrieved successfully",
"documents": [
{
"id": "doc1",
"title": "Document Title",
"content": "Full document content...",
"keywords": ["keyword1", "keyword2"],
"metadata": {},
"bm25_score": 2.456,
"softmax_score": 0.1234
}
],
"total_retrieved": 15,
"cutoff_percentage": 8.0,
"settings": {
"temperature": 0.7,
"ignore_zero": true,
"llm_tools_cutoff": 8.0
}
}
Use Specific Terms
Experiment with Temperature
Adjust Cutoff Appropriately
Compare Results
# Comprehensive search with low cutoff
searcher.search_and_format(
"machine learning algorithms",
temperature=1.0,
cutoff=2.0,
ignore_zero=False
)
# Focused search for best matches
searcher.search_and_format(
"python lists",
temperature=0.5,
cutoff=15.0,
ignore_zero=True
)
# Broad search with uniform scoring
searcher.search_and_format(
"data science",
temperature=3.0,
cutoff=5.0,
ignore_zero=True
)
No Results Found
Too Many Results
Unexpected Rankings
API Errors
For more advanced usage and integration examples, refer to the main documentation at http://localhost:9200/docs.