# Filtered Search

> USearch for Rust

Cross-referencing an external database during traversal beats paging through results and filtering afterwards.
Non-matching entries still route the traversal, so recall does not collapse at low selectivity.

```rust
let mut arena = Arena::new_in(&executor)?;
let is_odd = |key: Key| u64::try_from(key).is_ok_and(|value| value % 2 == 1);
let matches = index.on(&executor).search(&rows(&query, 768)?, DenseSearchConfig {
    predicate: Some(&is_odd),
    ..DenseSearchConfig::from(10)
}, &mut arena)?;
```

A predicate is `Fn` and `Sync`, since the executor's threads call it together, and a panic inside it rejects the key.
A VRAM handle refuses a host predicate with `Status::Device`.

Every long verb's config takes a `progress` handler, called with the units finished so far and the units the call finishes if it runs to the end.
Answering `ControlFlow::Break(())` stops the call at the next increment boundary.

```rust
use std::ops::ControlFlow;
use std::time::{Duration, Instant};

let deadline = Instant::now() + Duration::from_secs(30);
let mut before_the_deadline = move |_finished: usize, _total: usize| match Instant::now() < deadline {
    true => ControlFlow::Continue(()),
    false => ControlFlow::Break(()),
};
let refined = index.on(&executor).refine(DenseRefineConfig {
    expansion_factor: 128,
    progress: Some(&mut before_the_deadline),
    ..DenseRefineConfig::default()
});
if let Err(failure) = refined {
    assert_eq!(failure.status, Status::Cancelled, "only the deadline stops it");
}
```

The handler is `FnMut` and `Send` where a predicate is `Fn` and `Sync`: it arrives on whichever thread advanced the work and never on two at once, which is what lets it carry a counter or a deadline without a lock of its own.
A panic inside it is read as a stop.
Reports are denominated in whatever the verb consumes: entries for an insertion, queries for a search, re-selected nodes for a refine, an absorb or a split, draws for a sample, shards for a checkpoint, and bytes for a buffer.
How often they arrive is the increment's size rather than a guarantee, so read the counts and never the number of calls.

What a stop leaves behind is each verb's own contract.
An `insert` cannot be stopped: it claims every entry before its first report, ignores a `Break`, and publishes the whole batch at once.
A stopped search reports `Status::Cancelled` and leaves no matches.
A stopped `refine` is the time budget a whole-graph sweep is meant to run under: re-selection claims no identity, and the call still re-links its islands, so the graph stays correct and merely less improved, and it reports `Status::Cancelled`.
A stopped load creates no index, and a stopped `save_buffer` leaves no monolith.

`use usearch::*;`

## ProgressCallback

A periodic report of finished and total units; `Break` stops the call at the next increment wherever the verb can stop, which an insertion cannot.

```rust
pub type ProgressCallback<'a> = dyn FnMut(usize, usize) -> ControlFlow<()> + Send + 'a;
```

It runs on whichever thread advanced the work, never on two at once, so it owes `Send` and may
be `FnMut`. A panic inside it stops the call like a `Break` and is re-raised once the call is final.

## Predicate

A search filter, run on the executor's threads together; a panic rejects the key and is re-raised once the call is final.

```rust
pub type Predicate<'a> = dyn Fn(Key) -> bool + Sync + 'a;
```

