-
Notifications
You must be signed in to change notification settings - Fork 2
systems query router
Active contributors: Magnus Hedemark
Lightweight query classifier that routes search queries to the most relevant engine subset based on topic keyword matching. Reduces latency, conserves API quota, and produces less noisy results for agent consumers by dispatching only to engines likely to return relevant results.
No ML, no LLM calls, no remote API — purely keyword-based classification with a first-match-wins strategy.
| Type | File | Description |
|---|---|---|
QueryRouter |
slopsearx/router.py |
Lightweight query classifier. Initialized from config or defaults, exposes route() method. |
_DEFAULT_TOPICS |
slopsearx/router.py |
Six default topic signatures: code, science, news, social, reference, historical. Each has a list of trigger keywords and a list of target engine names. |
_DEFAULT_FALLBACK |
slopsearx/router.py |
Default fallback engine set (["brave", "wikipedia"]) used when no topic matches. |
RoutingConfig |
slopsearx/config.py |
Configuration dataclass with enabled (bool), topics (optional dict), and fallback (optional list of engine names). |
route() |
slopsearx/router.py |
Core method — takes query string and optional category list, returns engine name list or None. |
The router uses a first-match-wins keyword matching strategy. It does not use ML, LLMs, or any remote API:
-
Check enabled. If routing is disabled (
routing.enabled: false),route()immediately returnsNone. -
Check categories. If the caller already provided an explicit category filter (non-empty
categorieslist), routing is skipped — category-based engine selection takes precedence. - Normalize query. The query is lowercased and stripped.
-
Scan topics. Topics are scanned in order (
code→science→news→social→reference→historical). For each topic, its keyword list is scanned. The first keyword that appears as a substring of the normalized query selects that topic's engine set as the return value. -
Fallback. If no keyword matches any topic,
route()returns a caller-defined fallback engine set (defaults to["brave", "wikipedia"]via thefallbackparameter).
Example: a query containing "python" matches the code topic's keyword list, returning ["brave", "github", "stackexchange", "duckduckgo", "wikipedia"]. A query containing "news" matches the news topic, returning ["brave", "hackernews", "duckduckgo"].
| Topic | Example keywords | Target engines |
|---|---|---|
code |
python, javascript, rust, typescript, golang, react, api, code, github, docker, kubernetes, sql, npm, pip, cargo | brave, github, stackexchange, duckduckgo, wikipedia |
science |
quantum, physics, biology, chemistry, neural network, machine learning, deep learning, paper, doi, theorem, algorithm, mathematics, statistics | brave, arxiv, semanticscholar, openalex, duckduckgo, wikipedia |
news |
news, today, breaking, latest, update, announced, released, headline | brave, hackernews, duckduckgo |
social |
reddit, hacker news, show hn, ask hn, discussion, forum | brave, hackernews, reddit, duckduckgo |
reference |
documentation, docs, tutorial, guide, how to, reference, wiki, manual, definition | brave, wikipedia, stackexchange, duckduckgo |
historical |
archive, wayback, historical, history, old, vintage, retro | brave, wikipedia, internetarchive, duckduckgo |
All routing parameters are configurable via the routing section in config.yaml:
routing:
enabled: true
topics:
code:
keywords: [python, javascript, rust, api, code, github]
engines: [brave, github, stackexchange, wikipedia]
science:
keywords: [quantum, physics, biology, chemistry]
engines: [brave, arxiv, semanticscholar, openalex, wikipedia]
fallback:
- brave
- wikipediaOperators can override topic definitions, add new topics, or change the fallback set. Topics defined in config replace defaults entirely.
-
Server startup:
startup()inserver.pycreates aQueryRouterfromcfg.routing(aRoutingConfigdataclass converted to dict viadataclasses.asdict()) -
Search handler: The
search()endpoint inserver.pycalls_router.route(q)when there is no category filter. If the router returns a non-None engine list, those engines replace the default engine set for the request -
Config system:
RoutingConfigis a dataclass inconfig.pywithenabled,topics, andfallbackfields. Loaded from YAML config, overridable via env vars -
Global state: The
_routermodule-level variable inserver.pyholds the singleton instance
- Adding or removing topic signatures: edit
_DEFAULT_TOPICSinrouter.py, or override viarouting.topicsinconfig.yaml - Changing the fallback engine set: edit
_DEFAULT_FALLBACKinrouter.py, or set viarouting.fallbackinconfig.yaml - Changing routing logic: modify
route()method — keyword match strategy, case normalization, or category interaction - Adding new config fields: update
RoutingConfigdataclass inconfig.pyand_apply_config()inrouter.py
| File | Description |
|---|---|
slopsearx/router.py |
QueryRouter class, _DEFAULT_TOPICS, _DEFAULT_FALLBACK, all routing logic |
slopsearx/config.py |
RoutingConfig dataclass, YAML + env var loading for routing section |
slopsearx/server.py |
Router initialization at startup, invocation in search handler |