Mind::members: the walk's page size is the mind's by construction
The walk selection is built field by field from the caller's filters, so a caller's limit, projection, order or cursor cannot reach it (one select per member at limit 1 measured 300 ms against 14 ms). A test pins it. Unverified at this commit: built and tested once at the end of the batch. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f13138c3fc
commit
abd2890834
1 changed files with 45 additions and 2 deletions
|
|
@ -23,7 +23,7 @@
|
|||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use cultnet_rs::{
|
||||
Cursor, EdgeAnchor, EdgeMatch, Evaluation, LIMIT_MAX, LIMIT_MIN, PROJECTION_DOCUMENT, Row, Selection, select, validate,
|
||||
Cursor, EdgeAnchor, EdgeMatch, Evaluation, LIMIT_MAX, LIMIT_MIN, PROJECTION_DOCUMENT, PROJECTION_HEADER, Row, Selection, select, validate,
|
||||
};
|
||||
use eureka_pipeline::{
|
||||
ClaimOutcome, CommitRange, Date, FindingConfidence, FindingOrigin, FindingSeverity, Label, Line, OrgRepo,
|
||||
|
|
@ -517,6 +517,26 @@ impl<S: MindStore> Mind<S> {
|
|||
refuse_values(selection)
|
||||
}
|
||||
|
||||
/// The selection `members` walks: the caller's filters and nothing else.
|
||||
/// Built field by field, never spread from the caller's selection, so the
|
||||
/// page size is ours (the caller's `limit` shapes an answer, not the
|
||||
/// walk's cost: one select per member at limit 1) and the walk is headers
|
||||
/// only, from the first page, in the one order.
|
||||
fn walk_selection(selection: Selection) -> Selection {
|
||||
let Selection { schemas, keys, fields, cites, cited, .. } = selection;
|
||||
Selection {
|
||||
schemas,
|
||||
keys,
|
||||
fields,
|
||||
cites,
|
||||
cited,
|
||||
projection: PROJECTION_HEADER.into(),
|
||||
descending: false,
|
||||
limit: Some(LIMIT_MAX),
|
||||
cursor: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// The members of a semantic query: every document the selection matches
|
||||
/// at the head, decided before the index is asked anything.
|
||||
///
|
||||
|
|
@ -529,7 +549,7 @@ impl<S: MindStore> Mind<S> {
|
|||
let selection = Self::semantic_selection(selection, semantic)?;
|
||||
let head = receipt::head(self)?;
|
||||
let rows = Reader::at(self, head)?.rows()?;
|
||||
let mut walk = Selection { limit: Some(LIMIT_MAX), ..selection };
|
||||
let mut walk = Self::walk_selection(selection);
|
||||
let mut ids = Vec::new();
|
||||
loop {
|
||||
let evaluation = select(&Vocabulary, &rows, &walk, head, self.cursor_key())?;
|
||||
|
|
@ -1887,6 +1907,29 @@ mod tests {
|
|||
assert_eq!(mind.members(&limited, &asking(5)).unwrap().ids.len(), 250);
|
||||
}
|
||||
|
||||
/// The walk costs one select per 200 members whatever the caller asked
|
||||
/// for: a caller's `limit`, projection, order or cursor never reach it,
|
||||
/// and its filters all do.
|
||||
#[test]
|
||||
fn the_members_walk_takes_its_page_size_from_the_mind_not_the_caller() {
|
||||
let questions = of_kinds(&[K::Question]);
|
||||
let caller = Selection {
|
||||
limit: Some(1),
|
||||
projection: PROJECTION_DOCUMENT.into(),
|
||||
descending: true,
|
||||
cursor: Some("caller-cursor".into()),
|
||||
keys: Some(vec!["Q1".into()]),
|
||||
cited: Some(Incoming { role: "subject".into(), exists: false }),
|
||||
..questions
|
||||
};
|
||||
let walk = Mind::<MemoryStore>::walk_selection(caller.clone());
|
||||
assert_eq!(walk.limit, Some(LIMIT_MAX));
|
||||
assert_eq!(walk.projection, PROJECTION_HEADER);
|
||||
assert!(!walk.descending);
|
||||
assert_eq!(walk.cursor, None);
|
||||
assert_eq!((walk.schemas, walk.keys, walk.cited), (caller.schemas, caller.keys, caller.cited));
|
||||
}
|
||||
|
||||
/// `matched` is what the selection admits, not what the index returned:
|
||||
/// two hits among five members still say five.
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Reference in a new issue