• 
      
    Fish Trophy

    dan.casares got a fish trophy!

    Fish Trophy

    Search: Add faceted fields to ReviewRequestIndex and UserIndex

    Review Request #15051 — Created May 13, 2026 and updated

    Information

    Review Board
    release-8.x

    Reviewers

    Extends ReviewRequestIndex and UserIndex with new Elasticsearch-specific
    fields required by the faceted search engine. These fields are ignored by
    Whoosh.

    ReviewRequestIndex gains:
    - status, branchCharField(faceted=True) for status and branch
    filters and aggregations
    - repository_id, submitter_idIntegerField FKs for the repository
    and author searchable filters
    - date_created, date_updateddatetime fields for creation and
    last-updated range filters
    - target_reviewer_ids, reviewer_user_ids, commenter_user_ids
    multi-value integer fields for reviewer and commenter filters
    - has_ship_it, has_reviews, has_issues_open, has_file_attachment,
    has_depends_onBooleanField for option-count term queries
    - comment_issue_statuses, file_attachment_types — multi-value fields
    for issue status and file type filters

    The review-based boolean fields (has_ship_it, has_reviews,
    reviewer_user_ids) use the prefetched _public_reviews attribute when
    available during rebuild_index and fall back to direct DB queries during
    on-the-fly indexing. has_issues_open and commenter_user_ids always use
    direct DB queries since comment volumes can be very large.

    UserIndex gains:
    - is_active, is_staffBooleanField(faceted=True) for user status
    and role filters
    - group_ids — multi-value field for group membership filter
    - date_joined, last_login — datetime fields for date range filters
    - username_display — stored keyword copy of username for terms
    aggregations

    UserIndex.index_queryset now indexes all users regardless of their
    is_active status (the is_active=True filter has been removed).
    Inactive users now appear in search results by default and can be filtered
    out using the is_active faceted field.

    A new GroupIndex is introduced to support the groups search tab. It
    indexes:
    - has_open_review_requests, in_active_reviewsBooleanField for
    filtering groups by review request activity
    - member_countIntegerField for filtering groups by membership size
    - invite_onlyBooleanField used by the permission filter to exclude
    groups the searching user cannot access

    A rebuild_index is required after upgrading to populate these new fields.

    Ran full test suite.
    Verified that each new prepare_* method on ReviewRequestIndex and
    UserIndex returns the correct value, including fallback behaviour for
    on-the-fly indexing when prefetches are not available. Confirmed that
    index_queryset on both indexes does not introduce N+1 queries for any of the
    new fields.

    Summary ID
    Search: Add faceted fields to ReviewRequestIndex and UserIndex
    af3e918c0bfcb3ee69c09b8f18ab8a661ab0a7b1
    Fix N+1 queries in ReviewRequestIndex and add faceted search fields
    acfe5b5d4e8f92028f0507025c4e5d3de8475d1c
    Updated styling to match standard
    7f11411ff3865d6f1121c5583921a97d4319061d
    Description From Last Updated

    Omg sorry I had a brain fart... we just release Review Board 8, all the "Version Added"s should say Review …

    maubin maubin

    line too long (81 > 79 characters) Column: 80 Error code: E501

    reviewbot reviewbot

    'typing.Sequence' imported but unused Column: 1 Error code: F401

    reviewbot reviewbot

    line break before binary operator Column: 13 Error code: W503

    reviewbot reviewbot

    line break before binary operator Column: 13 Error code: W503

    reviewbot reviewbot

    line break before binary operator Column: 13 Error code: W503

    reviewbot reviewbot

    line too long (80 > 79 characters) Column: 80 Error code: E501

    reviewbot reviewbot

    local variable 'review' is assigned to but never used Column: 9 Error code: F841

    reviewbot reviewbot

    local variable 'reviewer' is assigned to but never used Column: 9 Error code: F841

    reviewbot reviewbot

    Can you add a blank line between these.

    maubin maubin

    For this and any other class attributes that are newly added, can you add a Version Added to its docstring, …

    maubin maubin

    For our class variable docstrings, we like to have a one-sentence summary, then a newline, then a description if needed: …

    maubin maubin

    Was the previous description for this supposed to be deleted, does it no longer apply?

    maubin maubin

    We still like to keep arguments on one line per argument, e.g: def prepare_groups( self, user: RBUser, ) -> str: …

    maubin maubin

    It seems like this is meant to use user.username_display? Is username_display even needed or can we just use username?

    maubin maubin

    For lists that are expected to be immutable, where we're just reading from them and not modifying, we use Sequence[int] …

    maubin maubin

    We already import django.contrib.auth.models.User at the top of the test file. Let's use that instead of re-importing here. Update this …

    maubin maubin

    This description got moved here from the UserIndex.

    maubin maubin

    For every new method that was added, let's add a Version Changed: 8.0 to the docstring. It comes before the …

    maubin maubin

    Can you add a blank line before and after the if block. Same below.

    maubin maubin

    Same comment about using Sequence and everywhere else where we return list.

    maubin maubin

    Do these need to be imported here for some reason? If not we can import them at the top of …

    maubin maubin

    Instead of hardcoding mimetypes here, which can lead to some getting forgotten (for example pdfs can also have an application/x-pdf …

    maubin maubin

    line too long (81 > 79 characters) Column: 80 Error code: E501

    reviewbot reviewbot

    'typing.Sequence' imported but unused Column: 1 Error code: F401

    reviewbot reviewbot

    line too long (82 > 79 characters) Column: 80 Error code: E501

    reviewbot reviewbot

    line break before binary operator Column: 13 Error code: W503

    reviewbot reviewbot

    line break before binary operator Column: 13 Error code: W503

    reviewbot reviewbot

    line break before binary operator Column: 13 Error code: W503

    reviewbot reviewbot

    line too long (80 > 79 characters) Column: 80 Error code: E501

    reviewbot reviewbot

    local variable 'review' is assigned to but never used Column: 9 Error code: F841

    reviewbot reviewbot

    line break before binary operator Column: 28 Error code: W503

    reviewbot reviewbot

    line too long (80 > 79 characters) Column: 80 Error code: E501

    reviewbot reviewbot

    line too long (82 > 79 characters) Column: 80 Error code: E501

    reviewbot reviewbot
    Checks run (1 failed, 1 succeeded)
    flake8 failed.
    JSHint passed.

    flake8

    dan.casares
    Review request changed
    Commits:
    Summary ID Author
    Search: Add faceted fields to ReviewRequestIndex and UserIndex
    db34923f5d331db3d4fa24ba08831e46adff5815 DanielCasaresIglesias
    Search: Add faceted fields to ReviewRequestIndex and UserIndex
    f65a481a34533f3c8214a101dcdc89181664accd DanielCasaresIglesias

    Checks run (1 failed, 1 succeeded)

    flake8 failed.
    JSHint passed.

    flake8

    dan.casares
    maubin
    1. A good start. Most of these are formatting comments, can you apply these comments to your other changes too.

    2. reviewboard/accounts/search_indexes.py (Diff revision 3)
       
       
       
      Show all issues

      Can you add a blank line between these.

    3. reviewboard/accounts/search_indexes.py (Diff revision 3)
       
       
       
      Show all issues

      For this and any other class attributes that are newly added, can you add a Version Added to its docstring, for example:

      #: Keyword copy of username for ES ``terms`` aggregations.
      #:
      #: Version Added:
      #:     8.0
      
    4. reviewboard/accounts/search_indexes.py (Diff revision 3)
       
       
      Show all issues

      For our class variable docstrings, we like to have a one-sentence summary, then a newline, then a description if needed:

      #: Summary.
      #:
      #: Optional description if things need more explanation.
      

      Can you reformat this and the rest of the docstrings.

    5. reviewboard/accounts/search_indexes.py (Diff revision 3)
       
       
      Show all issues

      Was the previous description for this supposed to be deleted, does it no longer apply?

    6. reviewboard/accounts/search_indexes.py (Diff revision 3)
       
       
      Show all issues

      We still like to keep arguments on one line per argument, e.g:

          def prepare_groups(
              self,
              user: RBUser,
          ) -> str:
      

      Can you revert this change to go back to that format, here and below.

    7. reviewboard/accounts/search_indexes.py (Diff revision 3)
       
       
      Show all issues

      It seems like this is meant to use user.username_display? Is username_display even needed or can we just use username?

    8. reviewboard/accounts/search_indexes.py (Diff revision 3)
       
       
      Show all issues

      For lists that are expected to be immutable, where we're just reading from them and not modifying, we use Sequence[int] instead of list.

    9. Show all issues

      We already import django.contrib.auth.models.User at the top of the test file. Let's use that instead of re-importing here. Update this here and below.

    10. reviewboard/reviews/search_indexes.py (Diff revision 3)
       
       
       
       
       
       
       
       
       
       
      Show all issues

      This description got moved here from the UserIndex.

    11. reviewboard/reviews/search_indexes.py (Diff revision 3)
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
      Show all issues

      For every new method that was added, let's add a

      Version Changed:
          8.0
      

      to the docstring. It comes before the Args section.

    12. reviewboard/reviews/search_indexes.py (Diff revision 3)
       
       
       
       
      Show all issues

      Can you add a blank line before and after the if block. Same below.

    13. reviewboard/reviews/search_indexes.py (Diff revision 3)
       
       
      Show all issues

      Same comment about using Sequence and everywhere else where we return list.

    14. reviewboard/reviews/search_indexes.py (Diff revision 3)
       
       
       
       
       
       
       
       
      Show all issues

      Do these need to be imported here for some reason? If not we can import them at the top of the file.

    15. reviewboard/reviews/search_indexes.py (Diff revision 3)
       
       
       
       
       
       
       
       
       
       
       
       
      Show all issues

      Instead of hardcoding mimetypes here, which can lead to some getting forgotten (for example pdfs can also have an application/x-pdf type), lets build these programmatically using our Review UIs. For example:

      from reviewboard.attachments.mimetypes import TextMimetype
      
      code_mimetypes = set(TextMimetype.supported_mimetypes)
      ...
      elif any(mime.startswith(p) for p in code_mimetypes)
      

      Also you don't have access to this codebase, but we recently fleshed out document review in the new RB release, so instead of a pdf type can you switch it to document, and then for the mimetypes you can do this import:

      from rbpowerpack.docreview import (OFFICE_DOC_SUPPORTED_MIMETYPES,
                                         PDF_SUPPORTED_MIMETYPES)
      

      And then do a set union (the two variables are already sets).

    16. 
        
    dan.casares
    Review request changed
    Change Summary:

    Fixed the issues highlighted by Michelle.

    I also added indexing for groups.

    Description:
       

    Extends ReviewRequestIndex and UserIndex with new Elasticsearch-specific

        fields required by the faceted search engine. These fields are ignored by
        Whoosh.

       
       

    ReviewRequestIndex gains:

    ~   - status, branchCharField(faceted=True) for status and branch filters
    ~   and aggregations
    ~   - repository_id, submitter_idIntegerField FKs for the repository and author
    ~   searchable filters
      ~ - status, branchCharField(faceted=True) for status and branch
      ~ filters and aggregations
      ~ - repository_id, submitter_idIntegerField FKs for the repository
      ~ and author searchable filters
        - date_created, date_updateddatetime fields for creation and
        last-updated range filters
        - target_reviewer_ids, reviewer_user_ids, commenter_user_ids
        multi-value integer fields for reviewer and commenter filters
        - has_ship_it, has_reviews, has_issues_open, has_file_attachment,
        has_depends_onBooleanField for option-count term queries
    ~   - comment_issue_statuses, file_attachment_types — multi-value fields for
    ~   issue status and file type filters

      ~ - comment_issue_statuses, file_attachment_types — multi-value fields
      ~ for issue status and file type filters

       
       

    The review-based boolean fields (has_ship_it, has_reviews,

    ~   eviewer_user_ids) use the prefetched _public_reviews attribute when
      ~ reviewer_user_ids) use the prefetched _public_reviews attribute when
        available during rebuild_index and fall back to direct DB queries during
        on-the-fly indexing. has_issues_open and commenter_user_ids always use
        direct DB queries since comment volumes can be very large.

       
       

    UserIndex gains:

    ~   - is_active, is_staffBooleanField(faceted=True) for user status and
    ~   role filters
      ~ - is_active, is_staffBooleanField(faceted=True) for user status
      ~ and role filters
        - group_ids — multi-value field for group membership filter
        - date_joined, last_login — datetime fields for date range filters
    ~   - username_display — stored keyword copy of username for terms aggregations

      ~ - username_display — stored keyword copy of username for terms
      + aggregations

      +
      +

    UserIndex.index_queryset now indexes all users regardless of their

      + is_active status (the is_active=True filter has been removed).
      + Inactive users now appear in search results by default and can be filtered
      + out using the is_active faceted field.

      +
      +

    A new GroupIndex is introduced to support the groups search tab. It

      + indexes:
      + - has_open_review_requests, in_active_reviewsBooleanField for
      + filtering groups by review request activity
      + - member_countIntegerField for filtering groups by membership size
      + - invite_onlyBooleanField used by the permission filter to exclude
      + groups the searching user cannot access

       
       

    A rebuild_index is required after upgrading to populate these new fields.

    Commits:
    Summary ID Author
    Search: Add faceted fields to ReviewRequestIndex and UserIndex
    e0cdd4eeba17442551f980d44a39b7266afe6be1 DanielCasaresIglesias
    Search: Add faceted fields to ReviewRequestIndex and UserIndex
    a151ae824e8077accaafb535845df75aec48133c Daniel Casares-Iglesias

    Checks run (1 failed, 1 succeeded)

    flake8 failed.
    JSHint passed.

    flake8

    dan.casares
    Review request changed
    Change Summary:

    Fix N+1 queries
    prepare_author** was calling user.get_profile(cached_only=True), which checks a custom cache that select_related does not populate, causing a full profile fetch per review request. Replaced with user.has_private_profile(), which reads from Django's select_related cache.
    Added prefetches to index_queryset for submitter (with profile), reviews, file_attachments, and depends_on to support the new prepare_* methods without N+1 queries. Published reviews are cached to _public_reviews and shared across multiple preparers; file attachments and depends-on results are cached to _file_attachments and _depends_on respectively.
    Add faceted search fields**
    Added index fields and prepare_* methods to support Elasticsearch faceted filtering: review ship-it and reviewer data, comment issue statuses and commenters, file attachment presence and type, dependency tracking, and various scalar fields (status, branch, repository_id, submitter_id, date_created, date_updated). Preparers fall back to direct DB queries when prefetch caches are unavailable, for compatibility with on-the-fly indexing.

    Commits:
    Summary ID
    Search: Add faceted fields to ReviewRequestIndex and UserIndex
    a151ae824e8077accaafb535845df75aec48133c
    Search: Add faceted fields to ReviewRequestIndex and UserIndex
    af3e918c0bfcb3ee69c09b8f18ab8a661ab0a7b1
    Fix N+1 queries in ReviewRequestIndex and add faceted search fields
    a6e6ab5f569ca3776b8e7d2352c7bfb77f5d1026

    Checks run (1 failed, 1 succeeded)

    flake8 failed.
    JSHint passed.

    flake8

    dan.casares
    dan.casares
    maubin
    1. I'm gonna give this and your other changes a deeper review of the implementation over the next couple days, I need to learn a bit more about search and Elasticsearch. For now can you go over your other changes and apply all the formatting feedback that I gave here.

    2. Show all issues

      Omg sorry I had a brain fart... we just release Review Board 8, all the "Version Added"s should say Review Board 9.0.

    3. 
        
    dan.casares
    dan.casares
    Review request changed
    Change Summary:

    Updated styling to match standard.

    Commits:
    Summary ID
    Search: Add faceted fields to ReviewRequestIndex and UserIndex
    af3e918c0bfcb3ee69c09b8f18ab8a661ab0a7b1
    Fix N+1 queries in ReviewRequestIndex and add faceted search fields
    2d243e676d8165518a3c86c1aab15a4f728b2beb
    Search: Add faceted fields to ReviewRequestIndex and UserIndex
    af3e918c0bfcb3ee69c09b8f18ab8a661ab0a7b1
    Fix N+1 queries in ReviewRequestIndex and add faceted search fields
    acfe5b5d4e8f92028f0507025c4e5d3de8475d1c
    Updated styling to match standard
    7f11411ff3865d6f1121c5583921a97d4319061d

    Checks run (2 succeeded)

    flake8 passed.
    JSHint passed.