Filters

Create filters on fields marked as Filterable. Filters must be created after Init() and Load() are complete.

Never filter results client-side. Always use server-side filters so the engine applies them during search.

Filter creation returns null on failure and reports the reason via an out string? error parameter: the field is unknown, it is not Filterable, a bound or culture can't be parsed, or the filter is the wrong kind for the field's type. null means rejected, never "no filter" — passing it on would widen the search to the whole dataset.

The field's type decides the filter kind. A range filter needs a field whose values are numbers; a value filter needs a field whose values are not. Both used to be accepted and answered by walking every document. A value filter on a number was not only slow but wrong, because it compares text: asked for 129 it missed 129.0. The error names the alternative.

For an exact match on a numeric field, use a range with equal limits — CreateRangeFilter("item_id", id, id, out _). It compares as numbers and reads the field's posting index. Note that a number stored as a JSON string is a text field, so it refuses a range filter: store the values as numbers and load again.

Value Filters

Array fields (prices.amount, editions.format) hold one value per element, and a value or range filter matches a document if any element matches. Combine with OR to filter at variant level while results stay one document per work.

csharp
Filter? categoryFilter = engine.CreateValueFilter("category", "electronics", out string? error);
if (categoryFilter is null)
    throw new InvalidOperationException(error); // e.g. "Field 'category' is not filterable"

Matching is case-insensitive by default. An overload takes the flag:

csharp
Filter? exact = engine.CreateValueFilter("category", "Electronics", isCaseSensitive: true, out _);

A facet count equals a filter count only for a case-sensitive filter. Case-sensitive filters are answered by walking the documents rather than by the field's posting index, so they cost more.

Range Filters

csharp
Filter? priceFilter = engine.CreateRangeFilter("price", 10.0, 100.0, out string? error);

// Equal limits are numeric equality -- the right way to match one value on a numeric field
Filter? oneItem = engine.CreateRangeFilter("item_id", 129, 129, out _);

Both limits are inclusive. An overload takes a CultureInfo; without one the bounds are parsed as InvariantCulture.

Combining Filters

csharp
// AND — both conditions must match
Filter combined = categoryFilter & priceFilter;

// OR — either condition matches
Filter either = categoryFilter | priceFilter;

// NOT — negate a filter
Filter excluded = !categoryFilter;

Using Filters in Queries

csharp
query.Filter = combined;

// Check how many documents match
int count = combined.NumberOfDocumentsInFilter;

// Reset filter
query.Filter = null;

Preloading Filters

For large datasets where many filters are applied simultaneously:

csharp
engine.LoadFilters(new[] { categoryFilter, priceFilter }, maxThreadCount: 2);
// Or preload all: engine.LoadAllFilters(maxThreadCount: 4);

Properties

NameTypeAccessDescription
IsArray
bool
get
Set during Analyze if JsonObject is an Array.
NumberOfDocumentsInFilter
int
get
Returns the number of documents that are contained in the filter.
SerializedKey
string
get
Used internally exposed for ease of debugging.
NeedsLoading
bool
get/set
May be used in order to check if filter is loaded.
Culture
CultureInfo
get
Cultureinfo determines how double is parsed.