Curiosity

Filters and Facets

Facets are the structured-data sidekicks of free-text search — checkboxes, sliders, and date ranges that let the user narrow results without re-typing a query. Curiosity supports three facet shapes, each with a different cost/value trade-off.

Property facets

Driven by a property directly on the node. Best for low-cardinality, normalized fields:

Property example Good facet? Why
SupportCase.Status Yes Small set ("Open", "Pending", "Resolved").
Article.Category Yes Curated, small set.
SupportCase.Summary No Unique per row — facet would explode.
Article.Updated Use time facet Use the time filter instead.

Configure under Settings → Search → Property Facets. The workspace auto-generates checkbox or sort-by-count UI from there.

The differentiator versus most search engines. A related facet filters by an edge to a normalized entity node — e.g. "cases for devices made by Apple".

flowchart LR Query[SupportCase] -->|ForDevice| Device Device -->|MadeBy| Manufacturer Filter[User picks 'Apple'] -.-> Manufacturer

Two reasons to use related facets instead of duplicating the field on the node:

  1. No denormalization. If a device changes manufacturer, all cases follow automatically.
  2. Multi-hop. Filter on something two or three edges away (manufacturer of the device of the case).

Configure under Settings → Search → Related Facets.

From code:

var req = SearchRequest.For("screen flicker");
req.BeforeTypesFacet = new HashSet<string> { "SupportCase" };

req.RelatedFacets = new Dictionary<string, List<RelatedFacet>>
{
    ["Manufacturer"] = new()
    {
        new RelatedFacet { TargetType = "Manufacturer", TargetKey = "Apple" }
    }
};

var query = await Graph.CreateSearchAsUserAsync(req, CurrentUser, CancellationToken);
return query.Emit();

Time filter

Every node carries a Timestamp (or Time) field. The workspace exposes a global time filter (week, month, custom range) that applies to any indexed node type.

Exclude reference types from the time filter — Manufacturer, Status, Category rarely change and would show up in every time window:

  • Settings → Search → Time Filter Exclusions

Value facets

Driven by a numeric range — score buckets, age ranges, prices. Configured the same way as property facets but rendered as a range slider.

Performance tips

  • Cardinality matters. Facets over millions of distinct values become slow to count. Pre-aggregate by binning if necessary.
  • Pre-compute multi-hop facets. If a related facet walks three hops, consider materializing the relationship onto the source node during ingestion so the facet is one hop.
  • Lazy load facet values. The UI defaults to top-N values per facet. Don't expose Show all for high-cardinality facets in production.

Referenced by

© 2026 Curiosity. All rights reserved.