A3S Search
Overview
A3S Search is an embeddable meta search engine library inspired by SearXNG. It aggregates search results from multiple search engines, deduplicates them, and ranks them using a consensus-based scoring algorithm.
Basic Usage
use ;
async
Features
- Multi-Engine Search: Aggregate results from multiple search engines in parallel
- Result Deduplication: Merge duplicate results based on normalized URLs
- Consensus Ranking: Results found by multiple engines rank higher
- Configurable Weights: Adjust engine influence on final rankings
- Async-First: Built on Tokio for high-performance concurrent searches
- Timeout Handling: Per-engine timeout with graceful degradation
- Extensible: Easy to add custom search engines via the
Enginetrait
Supported Search Engines
International Engines
| Engine | Shortcut | Description |
|---|---|---|
| DuckDuckGo | ddg |
Privacy-focused search |
| Brave | brave |
Brave Search |
g |
Google Search | |
| Wikipedia | wiki |
Wikipedia API |
Chinese Engines (中国搜索引擎)
| Engine | Shortcut | Description |
|---|---|---|
| Baidu | baidu |
百度搜索 |
| Sogou | sogou |
搜狗搜索 |
| BingChina | bing_cn |
必应中国 |
| So360 | 360 |
360搜索 |
Quality Metrics
Test Coverage
127 unit tests + 22 integration tests with comprehensive coverage:
| Module | Lines | Coverage | Functions | Coverage |
|---|---|---|---|---|
| aggregator.rs | 239 | 99.16% | 25 | 100.00% |
| engine.rs | 119 | 100.00% | 18 | 100.00% |
| error.rs | 29 | 100.00% | 7 | 100.00% |
| query.rs | 113 | 100.00% | 20 | 100.00% |
| result.rs | 193 | 100.00% | 36 | 100.00% |
| search.rs | 285 | 99.30% | 52 | 100.00% |
| duckduckgo.rs | 138 | 80.43% | 20 | 70.00% |
| wikipedia.rs | 114 | 87.72% | 20 | 85.00% |
| baidu.rs | 99 | 71.72% | 15 | 66.67% |
| sogou.rs | 95 | 70.53% | 15 | 66.67% |
| bing_china.rs | 95 | 70.53% | 15 | 66.67% |
| so360.rs | 95 | 70.53% | 15 | 66.67% |
| brave.rs | 108 | 62.96% | 18 | 55.56% |
| google.rs | 109 | 63.30% | 18 | 55.56% |
| Total | 1831 | 87.06% | 294 | 84.69% |
Note: Engine implementations require HTTP requests for full coverage. Integration tests (in tests/integration.rs) verify real HTTP functionality but are #[ignore] by default.
Run coverage report:
Running Tests
# Run unit tests
# Run with output
# Run integration tests (requires network)
Architecture
Ranking Algorithm
The scoring algorithm is based on SearXNG's approach:
score = Σ (weight / position) for each engine
weight = engine_weight × num_engines_found
Key factors:
- Engine Weight: Configurable per-engine multiplier (default: 1.0)
- Consensus: Results found by multiple engines score higher
- Position: Earlier positions in individual engines score higher
Components
┌─────────────────────────────────────────────────────┐
│ Search │
│ ┌───────────────────────────────────────────────┐ │
│ │ Engine Registry │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │DuckDuck │ │ Brave │ │Wikipedia│ ... │ │
│ │ │ Go │ │ │ │ │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ │ │
│ └───────────────────────────────────────────────┘ │
│ ↓ parallel search │
│ ┌───────────────────────────────────────────────┐ │
│ │ Aggregator │ │
│ │ • Deduplicate by normalized URL │ │
│ │ • Merge results from multiple engines │ │
│ │ • Calculate consensus-based scores │ │
│ │ • Sort by score (descending) │ │
│ └───────────────────────────────────────────────┘ │
│ ↓ │
│ SearchResults │
└─────────────────────────────────────────────────────┘
Quick Start
Installation
Add to your Cargo.toml:
[]
= "0.1"
= { = "1", = ["full"] }
Basic Search
use ;
let mut search = new;
search.add_engine;
let query = new;
let results = search.search.await?;
println!;
Chinese Search (中文搜索)
use ;
let mut search = new;
search.add_engine; // 百度
search.add_engine; // 搜狗
search.add_engine; // 必应中国
search.add_engine; // 360搜索
let query = new;
let results = search.search.await?;
Query Options
use ;
let query = new
.with_categories
.with_language
.with_safesearch
.with_page
.with_time_range;
Custom Engine Weights
use ;
// Wikipedia results will have 1.5x weight
let wiki = new.with_config;
let mut search = new;
search.add_engine;
Implementing Custom Engines
use ;
use async_trait;
API Reference
Search
| Method | Description |
|---|---|
new() |
Create a new search instance |
add_engine(engine) |
Add a search engine |
set_timeout(duration) |
Set default search timeout |
engine_count() |
Get number of configured engines |
search(query) |
Perform a search |
SearchQuery
| Method | Description |
|---|---|
new(query) |
Create a new query |
with_categories(cats) |
Set target categories |
with_language(lang) |
Set language/locale |
with_safesearch(level) |
Set safe search level |
with_page(page) |
Set page number |
with_time_range(range) |
Set time range filter |
with_engines(engines) |
Limit to specific engines |
SearchResult
| Field | Type | Description |
|---|---|---|
url |
String |
Result URL |
title |
String |
Result title |
content |
String |
Result snippet |
result_type |
ResultType |
Type of result |
engines |
HashSet<String> |
Engines that found this |
positions |
Vec<u32> |
Positions in each engine |
score |
f64 |
Calculated ranking score |
thumbnail |
Option<String> |
Thumbnail URL |
published_date |
Option<String> |
Publication date |
SearchResults
| Method | Description |
|---|---|
items() |
Get result slice |
suggestions() |
Get query suggestions |
answers() |
Get direct answers |
count |
Number of results |
duration_ms |
Search duration in ms |
Engine Trait
EngineConfig
| Field | Type | Default | Description |
|---|---|---|---|
name |
String |
- | Display name |
shortcut |
String |
- | Short identifier |
categories |
Vec<EngineCategory> |
[General] |
Categories |
weight |
f64 |
1.0 |
Ranking weight |
timeout |
u64 |
5 |
Timeout in seconds |
enabled |
bool |
true |
Is enabled |
paging |
bool |
false |
Supports pagination |
safesearch |
bool |
false |
Supports safe search |
Development
Dependencies
| Dependency | Install | Purpose |
|---|---|---|
cargo-llvm-cov |
cargo install cargo-llvm-cov |
Code coverage |
Build Commands
# Build
# Test
# Test with output
# Coverage
# Run examples
Project Structure
search/
├── Cargo.toml
├── README.md
├── examples/
│ ├── basic_search.rs # Basic usage example
│ └── chinese_search.rs # Chinese engines example
├── tests/
│ └── integration.rs # Integration tests (network-dependent)
└── src/
├── lib.rs # Library entry point
├── engine.rs # Engine trait and config
├── error.rs # Error types
├── query.rs # SearchQuery
├── result.rs # SearchResult, SearchResults
├── aggregator.rs # Result aggregation and ranking
├── search.rs # Search orchestrator
└── engines/
├── mod.rs # Engine exports
├── duckduckgo.rs # DuckDuckGo
├── brave.rs # Brave Search
├── google.rs # Google
├── wikipedia.rs # Wikipedia
├── baidu.rs # Baidu (百度)
├── sogou.rs # Sogou (搜狗)
├── bing_china.rs # Bing China (必应中国)
└── so360.rs # 360 Search (360搜索)
A3S Ecosystem
A3S Search is a utility component of the A3S ecosystem.
┌──────────────────────────────────────────────────────┐
│ A3S Ecosystem │
│ │
│ Infrastructure: a3s-box (MicroVM sandbox) │
│ │ │
│ Application: a3s-code (AI coding agent) │
│ / \ │
│ Utilities: a3s-lane a3s-context a3s-search │
│ (queue) (memory) (search) │
│ ▲ │
│ │ │
│ You are here │
└──────────────────────────────────────────────────────┘
Standalone Usage: a3s-search works independently for any meta search needs:
- AI agents needing web search capabilities
- Privacy-focused search aggregation
- Research tools requiring multi-source results
- Any application needing unified search across engines
Roadmap
Phase 1: Core ✅ (Complete)
- Engine trait abstraction
- Result deduplication by URL
- Consensus-based ranking algorithm
- Parallel async search execution
- Per-engine timeout handling
- 8 built-in engines (4 international + 4 Chinese)
Phase 2: Enhanced Features 🚧 (Planned)
- Image search support
- News search support
- Result caching
- Engine health monitoring
- Automatic engine suspension on failures
- More engines (Yandex, Qwant, etc.)
Phase 3: Advanced 📋 (Future)
- Instant answers (calculator, weather, etc.)
- Infobox extraction
- Search suggestions
- Spelling corrections
- Plugin system
License
MIT