mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-04-29 21:49:16 +08:00
## Overview
This PR introduces comprehensive search functionality for chat messages,
enabling users to search through their chat history both globally across
all accessible channels and within specific channels.
### Search Capabilities
**All-Channel Search**: When no channel is specified, users can search
across all channels they have access to. The search respects channel
permissions through `ChannelFetcher.all_secured_channel_ids`, ensuring
users only see results from channels they can view.
**Per-Channel Search**: Users can scope their search to a specific
channel by providing a `channel_id` parameter, useful for finding
messages within a particular conversation context.
**Search Features**:
- Full-text search using PostgreSQL's tsvector/tsquery
- Advanced filters: `@username` to filter by author, `#channel` to
filter by channel slug
- Sort options: relevance (default) or latest
- Pagination support
- Search data weighted by relevance
## Site Setting: `chat_search_enabled`
This feature is gated behind the `chat_search_enabled` site setting,
which is currently:
- **Default**: `false`
- **Hidden**: `true`
- **Client-accessible**: `true`
### Deployment Strategy
Due to the need for chat messages to be indexed before search becomes
useful, we're implementing a two-phase deployment:
**Phase 1 (Initial Merge)**:
- `chat_search_enabled` remains `false` and hidden
- The `register_search_index` uses default (true) instead of `chat_search_enabled` value
- This allows the reindexing infrastructure to begin indexing existing
chat messages even if we don't show the UI yet
**Wait Period**:
- Wait at least one week after Phase 1 deployment
- `Jobs::ReindexSearch` runs every 2 hours and will progressively index
all chat messages
- This ensures most sites have a significant part of their chat history indexed
**Phase 2 (Follow-up Merge)**:
- Set `chat_search_enabled` default to `true` and unhide it
- Update the `register_search_index` enabled proc uses the default
(true) instead of using the `chat_search_enabled` setting
- Users can now access search with pre-indexed data
**Rationale**: Without this phased approach, users would see the search
UI immediately but receive no results until the reindexing job runs,
creating a confusing experience. By pre-indexing while the UI is hidden,
we ensure search works immediately when enabled.
## New Plugin API: `register_search_index`
This PR introduces a new plugin API that allows plugins to register
custom search indexes that integrate seamlessly with Discourse's search
infrastructure.
### API Signature
```ruby
register_search_index(
model_class:, # The ActiveRecord model to index
search_data_class:, # The model for storing search data
index_version:, # Version number for re-indexing
search_data:, # Proc that returns weighted search data
load_unindexed_record_ids:,# Proc that finds records needing indexing
enabled: # Optional proc to enable/disable (default: -> { true })
)
```
### How It Works
**Integration with SearchIndexer**: When `SearchIndexer.index(obj)` is
called, it checks registered search handlers for the object's type. If a
handler matches, it:
1. Calls the `search_data` proc with the object and an `IndexerHelper`
instance
2. Receives weighted search data (`:a_weight`, `:b_weight`, `:c_weight`,
`:d_weight`)
3. Updates the corresponding search data table with PostgreSQL's
tsvector
**Integration with Jobs::ReindexSearch**: The scheduled job (runs every
2 hours) calls `rebuild_registered_search_handlers`, which:
1. Iterates through all registered search handlers
2. Skips handlers where `enabled` proc returns `false`
3. Calls `load_unindexed_record_ids` to find records needing indexing
4. Indexes up to `limit` records per handler (default: 10,000)
### Chat Implementation Example
```ruby
register_search_index(
model_class: Chat::Message,
search_data_class: Chat::MessageSearchData,
index_version: 1,
search_data: proc { |message, indexer_helper|
{
a_weight: message.message,
d_weight: indexer_helper.scrub_html(message.cooked)[0..600_000]
}
},
load_unindexed_record_ids: proc { |limit:, index_version:|
Chat::Message
.joins("LEFT JOIN chat_message_search_data ON chat_message_id = chat_messages.id")
.where(
"chat_message_search_data.locale IS NULL OR
chat_message_search_data.locale != ? OR
chat_message_search_data.version != ?",
SiteSetting.default_locale,
index_version
)
.order("chat_messages.id ASC")
.limit(limit)
.pluck(:id)
}
)
```
Co-authored-by: Martin Brennan <mjrbrennan@gmail.com>
Co-authored-by: Loïc Guitaut <5648+Flink@users.noreply.github.com>
|
||
|---|---|---|
| .. | ||
| regular | ||
| scheduled | ||
| about_stats_spec.rb | ||
| activation_reminder_emails_spec.rb | ||
| auto_queue_handler_spec.rb | ||
| automatic_group_membership_spec.rb | ||
| backfill_sidebar_site_settings_spec.rb | ||
| bookmark_reminder_notifications_spec.rb | ||
| bulk_grant_trust_level_spec.rb | ||
| bulk_invite_spec.rb | ||
| bump_topic_spec.rb | ||
| call_discourse_hub_spec.rb | ||
| change_display_name_spec.rb | ||
| check_new_features_spec.rb | ||
| check_translation_overrides_spec.rb | ||
| clean_dismissed_topic_users_spec.rb | ||
| clean_up_associated_accounts_spec.rb | ||
| clean_up_crawler_stats_spec.rb | ||
| clean_up_email_change_requests_spec.rb | ||
| clean_up_email_logs_spec.rb | ||
| clean_up_inactive_users_spec.rb | ||
| clean_up_post_reply_keys_spec.rb | ||
| clean_up_tags_spec.rb | ||
| clean_up_unused_staged_users_spec.rb | ||
| clean_up_unused_user_api_key_clients_spec.rb | ||
| clean_up_unused_user_api_keys_spec.rb | ||
| clean_up_uploads_spec.rb | ||
| clean_up_user_api_keys_max_life_spec.rb | ||
| clean_up_user_export_topics_spec.rb | ||
| cleanup_imap_sync_log_spec.rb | ||
| cleanup_redelivering_web_hook_events_spec.rb | ||
| close_topic_spec.rb | ||
| correct_missing_dualstack_urls_spec.rb | ||
| crawl_topic_link_spec.rb | ||
| create_linked_topic_spec.rb | ||
| create_missing_avatars_spec.rb | ||
| create_recent_post_search_indexes_spec.rb | ||
| create_user_reviewable_spec.rb | ||
| delete_replies_spec.rb | ||
| delete_topic_spec.rb | ||
| disable_bootstrap_mode_spec.rb | ||
| download_avatar_from_url_spec.rb | ||
| download_backup_email_spec.rb | ||
| download_profile_background_from_url_spec.rb | ||
| emit_web_hook_event_spec.rb | ||
| enable_bootstrap_mode_spec.rb | ||
| enqueue_digest_emails_spec.rb | ||
| enqueue_suspect_users_spec.rb | ||
| ensure_db_consistency_spec.rb | ||
| ensure_s3_uploads_existence_multisite_spec.rb | ||
| ensure_s3_uploads_existence_spec.rb | ||
| export_csv_file_spec.rb | ||
| export_user_archive_spec.rb | ||
| feature_topic_users_spec.rb | ||
| fix_out_of_sync_user_uploaded_avatar_spec.rb | ||
| fix_primary_emails_for_staged_users_spec.rb | ||
| fix_s3_etags_spec.rb | ||
| fix_user_usernames_and_groups_names_clash_spec.rb | ||
| grant_anniversary_badges_spec.rb | ||
| grant_new_user_of_the_month_badges_spec.rb | ||
| ignored_users_summary_spec.rb | ||
| index_user_fields_for_search_spec.rb | ||
| invalidate_inactive_admins_spec.rb | ||
| invite_email_spec.rb | ||
| jobs_base_spec.rb | ||
| jobs_scheduled_spec.rb | ||
| jobs_spec.rb | ||
| mass_award_badge_spec.rb | ||
| notify_category_change_spec.rb | ||
| notify_mailing_list_subscribers_spec.rb | ||
| notify_moved_posts_spec.rb | ||
| notify_reviewable_spec.rb | ||
| notify_tag_change_spec.rb | ||
| old_keys_reminder_spec.rb | ||
| open_topic_spec.rb | ||
| pending_queued_posts_reminder_spec.rb | ||
| pending_reviewables_reminder_spec.rb | ||
| pending_users_reminder_spec.rb | ||
| periodical_updates_spec.rb | ||
| poll_mailbox_spec.rb | ||
| post_update_topic_tracking_state_spec.rb | ||
| post_uploads_recovery_spec.rb | ||
| process_bulk_invite_emails_spec.rb | ||
| process_email_spec.rb | ||
| process_localized_cooked_spec.rb | ||
| process_post_spec.rb | ||
| process_shelved_notifications_spec.rb | ||
| publish_topic_to_category_spec.rb | ||
| pull_hotlinked_images_spec.rb | ||
| pull_user_profile_hotlinked_images_spec.rb | ||
| purge_expired_ignored_users_spec.rb | ||
| push_notification_spec.rb | ||
| rebake_custom_emoji_posts_spec.rb | ||
| redeliver_web_hook_events_spec.rb | ||
| refresh_users_reviewable_counts_spec.rb | ||
| reindex_search_spec.rb | ||
| remove_banner_spec.rb | ||
| reviewable_priorities_spec.rb | ||
| run_problem_check_spec.rb | ||
| run_problem_checks_spec.rb | ||
| send_push_notification_spec.rb | ||
| send_system_message_spec.rb | ||
| suspicious_login_spec.rb | ||
| sync_access_control_for_uploads_spec.rb | ||
| sync_topic_user_bookmarked_spec.rb | ||
| tl3_promotions_spec.rb | ||
| toggle_topic_closed_spec.rb | ||
| topic_timer_enqueuer_spec.rb | ||
| truncate_user_flag_stats_spec.rb | ||
| unsilence_users_spec.rb | ||
| update_animated_uploads_spec.rb | ||
| update_gravatar_spec.rb | ||
| update_topic_hot_scores_spec.rb | ||
| update_username_spec.rb | ||
| user_email_spec.rb | ||