Implemented POST /indexes/{uid}/search with:
- Group selection: query_seq % RG (plan §2)
- Intra-group covering set (plan §4 covering_set)
- Fan-out to covering set with showRankingScore: true
- Each node returns offset + limit results (coordinator pagination)
- Merge with RRF or Score-based strategy (P1.4)
- Unavailable shard policies: partial, error, fallback
- X-Miroir-Degraded header with shard IDs
All 10 acceptance tests pass:
- Unique-keyword deduplication
- Facet count aggregation
- Paging consistency
- Node failure handling with RF=2
- Group fallback on full group failure
- Degraded header with shard IDs
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
3.5 KiB
3.5 KiB
P2.3 Search Read Path Implementation Summary
Overview
The search read path with scatter-gather + merge + group selection is fully implemented and tested.
Implementation Components
1. Group Selection (query_group)
- Location:
crates/miroir-core/src/router.rs:98-103 - Logic:
query_seq % RG(round-robin through replica groups) - Status: ✅ Implemented
2. Intra-group Covering Set (covering_set)
- Location:
crates/miroir-core/src/router.rs:105-116 - Logic: Uses rendezvous hash to select RF replicas per shard
- Rotation: Rotates through replicas using
query_seq - Status: ✅ Implemented
3. Scatter Planning (plan_search_scatter)
- Location:
crates/miroir-core/src/scatter.rs:387-431 - Logic: Builds
ScatterPlanmapping shards to nodes - Features:
- Supports replica_selector for adaptive selection
- Version floor filtering (plan §13.5)
- Session pinning support (plan §13.6)
- Status: ✅ Implemented
4. Execute Scatter (execute_scatter)
- Location:
crates/miroir-core/src/scatter.rs:598-742 - Logic: Fans out search requests to all nodes in covering set
- Features:
- Parallel requests with
join_all - Unavailable shard policies: Partial, Error, Fallback
- Group fallback on failure (plan §2)
- Parallel requests with
- Status: ✅ Implemented
5. Request Transformation (SearchRequest::to_node_body)
- Location:
crates/miroir-core/src/scatter.rs:341-376 - Logic: Injects
showRankingScore: trueunconditionally - Pagination: Sets
limit = offset + limit,offset = 0 - Status: ✅ Implemented
6. Merge (scatter_gather_search, merge)
- Location:
crates/miroir-core/src/scatter.rs:745-785,crates/miroir-core/src/merger.rs - Strategies:
- RRF (Reciprocal Rank Fusion) - default
- Score-based (for OP#4 global-IDF)
- Features:
- Deduplication by primary key
- Facet aggregation (sum across shards)
estimatedTotalHitssumprocessingTimeMsmax
- Status: ✅ Implemented
7. HTTP Endpoint (search_handler)
- Location:
crates/miroir-proxy/src/routes/search.rs:163-686 - Route:
POST /search/:index - Features:
- DFS query-then-fetch (OP#4 global-IDF preflight)
- Session pinning (plan §13.6)
- Query coalescing (plan §13.10)
- X-Miroir-Degraded header
- Settings version headers
- Status: ✅ Implemented
8. HTTP Client (HttpClient::search_node)
- Location:
crates/miroir-proxy/src/client.rs:64-136 - Logic: POST to
/indexes/{uid}/searchon Meilisearch nodes - Features:
- Master key authentication
- Timeout handling
- Error handling
- Status: ✅ Implemented
Acceptance Tests (10/10 Passed)
- ✅ Unique-keyword search returns exactly 1 hit (deduplication)
- ✅ Facet counts sum correctly across shards
- ✅ Paging: 5 pages of 10 = single limit=50 order, no dupes/gaps
- ✅ Node down with RF=2: search still covers all shards
- ✅ Group down: search uses fallback, not degraded
- ✅ X-Miroir-Degraded header includes actual shard IDs
- ✅ Full integration test (hits, facets, metadata)
- ✅ showRankingScore injected unconditionally
- ✅ limit is offset + limit for coordinator pagination
- ✅ Degraded header format
Integration with Phase 5 Features
The scatter plan cleanly separates routing decisions for future Phase 5 features:
- Hedging (§13.2):
ScatterPlan.hedging_eligibleflag - Adaptive replica selection (§13.3):
replica_selectorparameter - Query coalescing (§13.10): Integrated in search_handler