mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2026-10-12 09:24:52 -05:00
feat(cqld4): gate the predicated search on attainable recall and report it beside the strict measure
The workload surveys its ground truth in its derived parameters and refuses to run below min_attainable (default 0.95; 0 for a smoke run), and its verifier reports recall_attainable beside recall. The adapter docs state the regime: survey before loading, report the attainable measure beside the strict one, and choose the profile by what the survey says it can pay out, since selectivity times base count is only a first guess.
This commit is contained in:
1 parent
6ae106a5eb
commit
b4bfb22800
2 files changed
+62
-5
No files matched your search
+24
-5
@@ -14,6 +14,7 @@ description: |
|
||||
similarity: {{similarity == dataset(spec).attributes().getOrDefault('distance_function','COSINE').toString().toLowerCase()}}
|
||||
metadata columns: {{columns == recordColumns(spec, 'metadata_content')}}
|
||||
predicate forms: {{forms == predicateForms(spec, 'metadata_predicates', 'metadata_content')}}
|
||||
ground truth: {{coverage == requireAttainableRecall(spec, paramOr('groundtruth','prefiltered') + '_neighbor_indices', paramOr('min_attainable','0.95'))}}
|
||||
|
||||
The rampup phase stores each base vector with its metadata record,
|
||||
bound field by field through a prepared statement: RecordField reads
|
||||
@@ -44,11 +45,28 @@ description: |
|
||||
exact top-k among the base vectors that satisfy the predicate — since
|
||||
SAI restricts before it ranks. Pass groundtruth=postfiltered to
|
||||
compare against the top-k of an unfiltered search with the
|
||||
non-matching neighbors removed instead. When fewer than k base
|
||||
vectors satisfy a predicate, the ground-truth row is padded with -1
|
||||
sentinels, which count as misses, so recall on very selective
|
||||
predicates reads low by construction. The unfiltered search block is
|
||||
included for the baseline comparison.
|
||||
non-matching neighbors removed instead.
|
||||
|
||||
Reading recall. When fewer than k base vectors satisfy a predicate,
|
||||
the ground-truth row is padded with -1 sentinels, which the strict
|
||||
recall counts as misses, so on a slice too small for its predicates
|
||||
recall reads low by construction — not because the search missed.
|
||||
Two things keep that from cascading into a false failure. First, the
|
||||
ground-truth facet is surveyed before anything is loaded (the
|
||||
coverage line above): the recall@k ceiling a perfect search would
|
||||
score is printed, and the run is refused when it is below
|
||||
min_attainable (default 0.95) — pass min_attainable=0 for a smoke
|
||||
run on a padded profile. Second, the verifier reports
|
||||
recall_attainable beside recall: the share of the neighbors that
|
||||
exist which were found, so a padded profile still reads through.
|
||||
A profile whose predicates all reach k matches reads at a ceiling of
|
||||
1.0, and its strict recall is the number to hold a system to. A
|
||||
uniform set with selectivity x base_count comfortably above k is the
|
||||
place to look — tessera's 1m-uniform-2-1e-3 is complete, while its
|
||||
300k-uniform-2-1e-3 leaves a fifth of its queries short — but the
|
||||
survey, not the arithmetic, decides; a mixed ladder at a small size
|
||||
is a smoke test. The unfiltered search block is included for the
|
||||
baseline comparison.
|
||||
|
||||
Operational knobs stay conventional: keyspace, table, rf, and cl are
|
||||
TEMPLATE parameters with the usual defaults. The base facet is warmed
|
||||
@@ -227,6 +245,7 @@ blocks:
|
||||
k={{@maxk}}
|
||||
relevancy=new io.nosqlbench.nb.api.engine.metrics.wrappers.RelevancyMeasures(_parsed_op)
|
||||
relevancy.addFunction(io.nosqlbench.engine.extensions.computefunctions.RelevancyFunctions.recall("recall",k));
|
||||
relevancy.addFunction(io.nosqlbench.engine.extensions.computefunctions.RelevancyFunctions.attainable_recall("recall_attainable",k));
|
||||
relevancy.addFunction(io.nosqlbench.engine.extensions.computefunctions.RelevancyFunctions.precision("precision",k));
|
||||
relevancy.addFunction(io.nosqlbench.engine.extensions.computefunctions.RelevancyFunctions.F1("F1",k));
|
||||
relevancy.addFunction(io.nosqlbench.engine.extensions.computefunctions.RelevancyFunctions.reciprocal_rank("RR",k));
|
||||
|
||||
@@ -145,6 +145,44 @@ console before the first cycle — the number of prepared statements the
|
||||
run will hold, and how many predicates take each — so a run declares
|
||||
its shapes before it starts.
|
||||
|
||||
### Reading recall on a predicated search
|
||||
|
||||
A filtered ground truth holds, per query, the top-k among the rows
|
||||
that satisfy its predicate. On a slice too small for the predicate —
|
||||
a selectivity of one in a million against a hundred thousand rows —
|
||||
fewer than k rows satisfy it, and the row is padded with `-1`
|
||||
sentinels that no search can return. The strict `recall` divides by k
|
||||
regardless, so such a profile reads low by construction, and a regime
|
||||
that holds a system to that number fails for a reason that has
|
||||
nothing to do with the system.
|
||||
|
||||
Three rules keep the reading honest, and `cql_vector_predicated`
|
||||
follows all three:
|
||||
|
||||
- **Survey before loading.** `groundTruthCoverage(spec, facet)` reads
|
||||
the ground truth alone — a few megabytes — and reports how many
|
||||
queries have all k neighbors, how many have none, and the recall@k
|
||||
ceiling a perfect search would score. `requireAttainableRecall(spec,
|
||||
facet, minimum)` refuses the run below the ceiling you will accept,
|
||||
before a million rows are loaded for a number that cannot be read;
|
||||
`min_attainable=0` lets a smoke run through.
|
||||
- **Report the attainable measure beside the strict one.**
|
||||
`RelevancyFunctions.attainable_recall("recall_attainable", k)` leaves
|
||||
the sentinels out of the denominator: the share of the neighbors that
|
||||
exist which were found. A padded profile whose `recall` equals its
|
||||
ceiling and whose `recall_attainable` is 1.0 found everything there
|
||||
was.
|
||||
- **Choose the profile by what it can pay out.** A uniform predicate
|
||||
set whose `selectivity x base_count` is comfortably above k is where
|
||||
to look — `1m-uniform-2-1e-3` on a base of a million has a ceiling of
|
||||
1.0, and its strict recall is the number to hold a system to — but
|
||||
the survey decides, not the arithmetic: `300k-uniform-2-1e-3` nominally
|
||||
reaches 300 matches per predicate and still leaves a fifth of its
|
||||
queries short, at a ceiling of 0.988. A mixed ladder that runs far
|
||||
below the slice size is a smoke test of the binding path, and the
|
||||
selector says which candidates to survey:
|
||||
`dataset:family=uniform,base_count>=1m`.
|
||||
|
||||
## CQLd4 Op Template Examples
|
||||
|
||||
```yaml
|
||||
|
||||
Reference in new issue
Block a user