• 
      

    Search: Add DisjointFacetEngine, FilterBuilder, FacetCache, and search groups

    Review Request #15052 — Created May 13, 2026 and updated — Latest diff uploaded

    Information

    Review Board
    release-8.x

    Reviewers

    Adds the core faceted search engine, the reviewboard/search/facets/ package,
    along with benchmark tooling for performance validation.

    Key components:
    - DisjointFacetEngine (aggregations.py) builds and executes a single
    Elasticsearch msearch body per request containing: a paginated results
    query, one aggregation sub-query per faceted=True FilterSpec (each
    excluding its own filter clause so bucket counts remain accurate when the
    filter is active — the disjoint property), and one option-count query per
    compound filter choice.
    - FilterSpec / FilterBuilder (schema.py, builder.py) provide a
    declarative schema for filter dimensions and translate active filter values
    into Elasticsearch bool.filter clauses. Compound filters (ship-it, issues,
    reviews, file attachments) use custom build_fn callables.
    - FacetCache (cache.py) caches aggregation results per group, query, and
    filter state for the lifetime of a request.
    - FacetedSearchEngine (engine.py) orchestrates searches across
    ReviewRequestSearchGroup, UserSearchGroup, and ReviewGroupSearchGroup.
    For the active group it runs a full search with aggregations; for inactive
    groups it runs a count-only query so sidebar tab totals are accurate.
    - ReviewRequestSearchGroup additionally handles the Contents filter, which
    restricts the text query to specific ES fields and optionally runs a parallel
    query against comment indexes to surface review requests with matching
    comments.
    - Also adds populate_bench_data management command and bench_manager.py for
    populating and benchmarking persistent datasets at 1k, 10k, 100k, and 1M
    scale across Postgres, MySQL, and MariaDB.

    Verified that DisjointFacetEngine builds the correct msearch body structure,
    enforces the disjoint property on aggregation sub-queries, and produces exactly
    one msearch call per search regardless of how many filters are active. Verified
    that FilterBuilder generates correct Elasticsearch clauses for each filter
    type and that the permission filter is always injected. Verified that
    FacetedSearchEngine routes full searches to the active group and count-only
    queries to inactive groups.

    Performance benchmarks were run at 10k, 100k, and 1M review requests on
    Postgres, MySQL, and MariaDB. A 6-filter faceted search against a 1M-document
    index completes in 4.7ms with latency remaining flat across all scales. Full
    results are in the attached benchmark report.

    Commits

    Files