Skip to main content

Middleware Examples

Practical examples for building and using Whoosh-NG middleware.

1. Logging Middleware​

from whoosh.middleware.base import Middleware
from whoosh.middleware.context import MiddlewareContext

class LoggingMiddleware(Middleware):
def before_search(self, context: MiddlewareContext) -> MiddlewareContext:
print(f"[SEARCH] Query: {context.query}")
return context

def after_search(self, context: MiddlewareContext) -> MiddlewareContext:
if context.results is not None:
print(f"[RESULTS] Found {len(context.results)} hits")
return context

2. Metrics Middleware​

from whoosh.middleware.base import Middleware
from whoosh.middleware.context import MiddlewareContext

class MetricsMiddleware(Middleware):
def __init__(self) -> None:
self._metrics = {}

def after_index(self, context: MiddlewareContext) -> MiddlewareContext:
self._metrics["documents_indexed"] = self._metrics.get("documents_indexed", 0) + 1
return context

def after_search(self, context: MiddlewareContext) -> MiddlewareContext:
self._metrics["searches_executed"] = self._metrics.get("searches_executed", 0) + 1
return context

def get_metrics(self) -> dict:
return dict(self._metrics)

3. Cache Middleware​

from whoosh.middleware.base import Middleware
from whoosh.middleware.context import MiddlewareContext

class SearchCacheMiddleware(Middleware):
def __init__(self) -> None:
self._cache = {}

def before_search(self, context: MiddlewareContext) -> MiddlewareContext:
if context.query and str(context.query) in self._cache:
context.metadata["_cached_result"] = self._cache[str(context.query)]
return context

def after_search(self, context: MiddlewareContext) -> MiddlewareContext:
if context.query and context.results is not None:
self._cache[str(context.query)] = context.results
return context

4. Applying Middleware to an Index​

from whoosh.middleware.chain import MiddlewareChain
from whoosh.middleware.integration import apply_middleware_to_searcher

# Create middleware chain
chain = MiddlewareChain([
LoggingMiddleware(),
MetricsMiddleware(),
])

# Apply to a searcher
with ix.searcher() as base_searcher:
searcher = apply_middleware_to_searcher(base_searcher, chain.middlewares)
results = searcher.search(query)

5. Middleware Lifecycle​

class LifecycleMiddleware(Middleware):
def startup(self, context):
print("Middleware initialized")

def shutdown(self, context):
print("Middleware shutting down")

def on_error(self, context, exc):
print(f"Error: {exc}")
raise exc

Key Hooks​

HookPhaseContext
startupInitCalled once on middleware init
shutdownCleanupCalled once on teardown
before_indexIndexingBefore document added
after_indexIndexingAfter document added
before_deleteDeletionBefore document deleted
after_deleteDeletionAfter document deleted
before_searchSearchBefore query executed
after_searchSearchAfter results returned
on_errorErrorWhen exception occurs
on_commitCommitAfter writer.commit()