Reference Entry
How the Aggregations Sidebar Works
Demo Internals · advanced · order 20
How the demo calculates live text facets, word-count buckets, and significant terms for the right-hand sidebar.
Relevant APIs
How the Aggregations Sidebar Works
The right sidebar in the demo is a live faceting panel. Its job is to answer questions like:
- Which tags appear in the current results?
- Which sections are represented?
- Which APIs are most common?
- How long are the matching articles?
- Which terms are unusually characteristic of this result set?
The core idea
The sidebar is not driven by a separate database. It is driven by the same DocumentIndex search results that power the result list.
The flow is:
- Run the current query.
- Collect the matched document ids.
- Run aggregations on fields such as
tags,section,api, andwordCountusing only those ids. - Render the counts as clickable chips.
That means the sidebar always reflects the current query state.
Where this happens in the demo
Relevant source:
The important pieces are:
buildFacetFilterQueries(...): turns current UI filter state intoTermQueryandRangeQueryfilterssearchForState(...): runs the search, computes selected ids, and derives facetsrenderFacets(...): renders the sidebar groups and active filter chips
Indexing metadata so aggregations stay clean
The demo indexes tags, sections, and API names with a keyword-style analyzer instead of full text analysis.
It also indexes article word count as a dedicated numeric field.
That matters because facet values should usually stay intact:
vector-searchshould remain one tag valueBM25should remain one API valueAdvancedshould remain one level value
This setup is defined in the demo data/index creation code, where metadata fields are added as dedicated index fields.
Example
Imagine three docs:
[
{ id: "a", tags: ["vector", "demo"] },
{ id: "b", tags: ["vector", "aggregations"] },
{ id: "c", tags: ["highlighting"] }
]
If the current search only matches a and b, the sidebar tag aggregation is effectively:
const subsetIds = new Set(["a", "b"]);
const tagFacets = tagsIndex.termsAggregation(12, subsetIds);
Expected result:
{
vector: 2,
demo: 1,
aggregations: 1
}
Doc c does not contribute because it is not part of the active result set.
Why significant terms are also shown
Tag counts answer “what is here?” Significant terms answer “what is unusually prominent here?”
The demo computes significant terms from the body field for the current result ids. This is why the sidebar can suggest topic words that are not explicit tags but still characterize the current slice of docs.
That is useful when:
- users do not know the official tag vocabulary
- you want discovery hints beyond curated metadata
- the result set is narrow enough to have a recognizable topic
What happens when filters are clicked
Clicking a tag chip does not rerun a special facet query. It updates the search state and runs the normal search flow again with an added TermQuery("tags", value) filter.
The article-length chips work the same way, except they add a RangeQuery("wordCount", ...) filter.
After that:
- the result list changes
- the selected document ids change
- the sidebar counts are recomputed from the new subset
So the sidebar is both:
- an explanation of the current result set
- a control surface for narrowing it further
Why this is a good fit for docs
Documentation search is often exploratory. Users do not always arrive with the exact page title or exact API name.
The sidebar helps because it turns a flat result list into a navigable slice of the corpus:
- tags reveal topic clusters
- sections reveal where the results live
- APIs reveal concrete entry points
- word-count buckets show whether the current slice skews short or deep
- significant terms reveal vocabulary worth trying next
That is a big improvement over just showing ten blue links.