PAZATOR DOCS
FACETS
FEATURE — v0.May1726

Faceted
Search.

What it does

Search in Pazator used to be a linear scan — take the query, loop over every person and entity, check each field, return what matches. Fine when you have 50 entries. Painful when you have 500, and useless when you need to narrow down by nationality, threat level, or tags without retyping your query.

Faceted search builds an inverted index on load and uses it to give you filter pills (facets) that update their counts in real-time. Click a facet value to filter results further. The index covers all the object system fields — threat level, nationality, religion, occupation, ethnicity, gender, immigration status, social class, income level — plus tags.

How it works

On load, a FacetIndex is built from all humans and entities. Each facet type (nationality, threat level, etc.) becomes a map from value to set of IDs. When you type a query, the text search runs first (still a loop, but only over the fields you selected). The results feed into the facet bar, which shows the top 8 values per facet type along with how many results they match.

When you click a facet pill, the current results are filtered to only show items matching that value. The facet counts update immediately to reflect the new filtered set. Multiple facets stack — e.g., threat level = High AND nationality = Iranian shows only the intersection.

InvertedIndex
  threatLevel: { "high" => Set(id1, id5, ...), "critical" => Set(...) }
  nationality: { "iranian" => Set(id1, id3, ...), ... }
  tag:         { "suspect" => Set(id2, id5), ... }

On search: text query returns results, facet bar shows counts,
clicking a value re-filters in O(1) per item via the index.

Facet types

The facet bar shows up to eight values per type, sorted by count. The types are:

  • Threat Level — None, Low, Medium, High, Critical
  • Nationality
  • Religion
  • Occupation
  • Ethnicity
  • Gender
  • Immigration Status
  • Social Class
  • Income Level
  • Tags — any tag applied to an entry

The order and visibility is determined by what values actually exist in your results. If nobody has a religion set, that facet group just doesnt show. The counts next to each value tell you how many of the current results match it — useful for figuring out what the data looks like before filtering.

Saved searches

The old recent searches still work (history chips below the search bar). On top of that, saved searches are persisted in localStorage under pazator_saved_searches. A saved search stores the query string and the active facets. Clicking a saved search restores everything — query + facets — in one click.

Saved searches appear as bookmark chips in the search results bar. Theyre shown before recent searches and have a yellow tint to distinguish them. The save button appears next to the search clear button when you have an active query or facets.

Performance

The inverted index is built synchronously at load time. For datasets under ~10,000 entries this is effectively instant. The text search itself still walks every entry, but the facet filtering after that is a constant-time set lookup per item. The big win is that you avoid re-querying the database — once you have results, facet filtering is pure JS object lookups.

Code

The facet system lives in app/pazator_facets.js as a standalone module. The pazator_facets.FacetIndex class handles building the index, filtering, and count generation. Saved search CRUD is also there. The UI integration is in app/scriptz.js where performSearch was rewritten to work with facets, and renderFacetBar handles the dynamic pill generation.


Related

Facets build on top of the object system from pazator_objects.js. The same field types used in the autocomplete fields (nationality, occupation, etc.) are the ones that power the facet bar. See the app and open the Search tab to try it.