Search
Culling Matched Rows
Why later algorithms in a find-all pipeline skip rows an earlier algorithm already matched, and when it matters.
.cullMatchedRows(enabled?) controls whether a dataset row that one algorithm
matches is removed from the pool later algorithms in the run order search
through. It defaults to true.
new Search()
.register(NaiveSearch())
.register(Levenshtein()) // skips rows NaiveSearch already matched
.defineDataset(allModels)
.defineBehavior("find-all")
.cullMatchedRows(); // true by default; call with false to disable
Why it exists
In a find-all pipeline with more than one algorithm registered, every
algorithm scans the whole dataset by default. Without culling, a candidate
the cheap algorithm already caught still gets scored by every expensive
algorithm behind it in the run order, for a result you already had. Culling
removes that wasted work and the duplicate matches that come with it.
Internally, Search.search() tracks matched indices in a Set and passes it
to each algorithm’s run() as context.culled. BaseAlgorithm.run skips
scoring a culled index entirely, rather than scoring it and discarding the
result:
for (let index = 0; index < dataset.length; index += 1) {
if (context.culled.has(index)) continue;
// ...score this candidate
}
Disabling it
Call .cullMatchedRows(false) to have every algorithm see the whole dataset
regardless of what earlier algorithms matched. The behavior you get if you
never call the method at all is the opposite: culling is on unless you
explicitly turn it off.
new Search()
.register(NaiveSearch())
.register(Levenshtein())
.defineDataset(allModels)
.cullMatchedRows(false); // every algorithm sees every row
This is the right call when you want every algorithm’s independent opinion on every row: for instance, comparing algorithms against each other rather than combining them into one pipeline.
When it has no effect
Culling only changes anything for find-all pipelines with more than one
algorithm registered in the run order:
- An algorithm that stops at its own first match (
stopOnMatch: true, or a globalstop-on-matchthat ends the pipeline there) never gives a later algorithm the chance to run at all, so there is nothing to cull against. - A pipeline with a single algorithm has no “later algorithm” to skip rows for.
It also only removes rows matched by an earlier algorithm, not the whole dataset: an algorithm that only matched three of six rows still leaves the other three fully visible to whatever runs next.