feat(core): batch exact semantic queries - #53
Conversation
Signed-off-by: Seongho Bae <me@seonghobae.me>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| if authorized_candidate_ids.is_empty() { | ||
| return Err(SemanticIndexError::EmptyAuthorization); |
There was a problem hiding this comment.
🟡 Single-query error precedence changes
When both inputs are invalid, rank_authorized_batch_refs validates authorization first. Existing single-query calls now return a different stable error code.
Prompt for agents
Restore the existing single-query validation precedence in crates/rankweave-core/src/semantic_index.rs. Before this change, rank_authorized and rank_authorized_packed validated model, then query dimension/finiteness/norm, then authorization contents. Their delegation through rank_authorized_batch_refs now validates authorization before the query. Refactor validation or delegation so the stable single-query APIs preserve their prior error codes while the new batch API retains clearly defined validation semantics. Add regression tests where both the query and authorization are invalid.
Was this helpful? React with 👍 or 👎 to provide feedback.
| An additive packed batch operation accepts two or more ordered query vectors | ||
| against one identical packed authorization buffer and immutable snapshot. It |
| let best_by_query = authorized_indices | ||
| .par_iter() | ||
| .fold( | ||
| || (vec![0.0; query_count], empty_best_maps(query_count)), | ||
| |(mut dots, mut best_by_query), index| { | ||
| dots.fill(0.0); | ||
| let start = index * dimension; | ||
| for coordinate in 0..dimension { | ||
| let candidate_value = self.normalized_vectors[start + coordinate]; | ||
| let query_start = coordinate * query_count; | ||
| for (dot, query_value) in dots.iter_mut().zip( | ||
| &normalized_queries_by_coordinate | ||
| [query_start..query_start + query_count], | ||
| ) { | ||
| *dot += query_value * candidate_value; | ||
| } | ||
| } | ||
| let (item_id, unit_id) = &self.candidate_ids[*index]; | ||
| for (query_index, query) in unique_queries.iter().enumerate() { | ||
| let score = (dots[query_index] / (query.norm * self.vector_norms[*index])) | ||
| .clamp(0.0, 1.0); | ||
| retain_best_unit(&mut best_by_query[query_index], item_id, unit_id, score); | ||
| } | ||
| (dots, best_by_query) | ||
| }, | ||
| ) | ||
| .map(|(_, best_by_query)| best_by_query) | ||
| .reduce( | ||
| || empty_best_maps(query_count), | ||
| |mut left, right| { | ||
| for (left_query, right_query) in left.iter_mut().zip(right) { | ||
| for result in right_query.into_values() { | ||
| retain_best_unit( | ||
| left_query, | ||
| &result.item_id, | ||
| &result.winning_unit_id, | ||
| result.score, | ||
| ); | ||
| } | ||
| } | ||
| left | ||
| }, | ||
| ); |
There was a problem hiding this comment.
| let unique_reports = unique_query_indices | ||
| .iter() | ||
| .zip(best_by_query) | ||
| .map(|(query_index, best_by_item)| { | ||
| self.finish_query_report( | ||
| &model_digest, | ||
| query_vectors[*query_index], | ||
| authorized_candidate_ids, | ||
| best_by_item, | ||
| ) | ||
| }) | ||
| .collect::<Vec<_>>(); | ||
| Ok(original_to_unique | ||
| .into_iter() | ||
| .map(|unique_index| unique_reports[unique_index].clone()) | ||
| .collect()) |
Signed-off-by: Seongho Bae <seonghobae@users.noreply.github.com>
47b0dfb
into
docs/product-technical-gap-baseline
Summary
Validation
cargo +1.97.1 fmt --all -- --checkcargo +1.97.1 clippy --workspace --all-targets -- -D warningscargo +1.97.1 llvm-cov --package rankweave-core --fail-under-lines 100 --fail-under-functions 100 --fail-under-regions 100(100% line/function/region)uvx uv@0.12.1 run --frozen python -m ruff check .uvx uv@0.12.1 run --frozen python -m coverage run -m pytest -q(692 passed)Boundary
This is an exact owner prerequisite, not LineageWeave ADR 0272 or authenticated k6 acceptance. No approximate backend, threshold change, cache, or worker-count policy is introduced.
Signed-off-by: Seongho Bae seonghobae@users.noreply.github.com