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
129it missed129.0. Theerrornames 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.
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:
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
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
// 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
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:
engine.LoadFilters(new[] { categoryFilter, priceFilter }, maxThreadCount: 2);
// Or preload all: engine.LoadAllFilters(maxThreadCount: 4);Properties
| Name | Type | Access | Description |
|---|---|---|---|
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. |