From 3ebc0ad4d3c2fe0b0951a334642b769bd521a799 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 9 Feb 2018 23:04:47 +0100 Subject: Full-text search for authorized statuses (#6423) * Add full-text search for authorized statuses - Search API will return statuses that match the query - Only for logged in users - Only if you are author of the status, - Or you were mentioned in it - Or you favourited or reblogged it - Configuration over `ES_ENABLED`, `ES_HOST`, `ES_PORT`, `ES_PREFIX` - Run `rails chewy:deploy` to create & populate index Fix #5880 Fix #4293 Fix #1152 * Add commented out docker-compose configuration for ES container * Optimize index import, filter search results * Add basic normalization to the index * Add better stemming and normalization to the index * Skip webfinger request if search query includes both @ and a space * Fix code style * Visually separate search result sections * Fix code style issues --- app/services/search_service.rb | 43 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) (limited to 'app/services') diff --git a/app/services/search_service.rb b/app/services/search_service.rb index 5f763b8f7..fe9856686 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -1,21 +1,43 @@ # frozen_string_literal: true class SearchService < BaseService - attr_accessor :query + attr_accessor :query, :account, :limit, :resolve def call(query, limit, resolve = false, account = nil) - @query = query + @query = query + @account = account + @limit = limit + @resolve = resolve default_results.tap do |results| if url_query? results.merge!(url_resource_results) unless url_resource.nil? elsif query.present? - results[:accounts] = AccountSearchService.new.call(query, limit, account, resolve: resolve) - results[:hashtags] = Tag.search_for(query.gsub(/\A#/, ''), limit) unless query.start_with?('@') + results[:accounts] = perform_accounts_search! if account_searchable? + results[:statuses] = perform_statuses_search! if full_text_searchable? + results[:hashtags] = perform_hashtags_search! if hashtag_searchable? end end end + private + + def perform_accounts_search! + AccountSearchService.new.call(query, limit, account, resolve: resolve) + end + + def perform_statuses_search! + statuses = StatusesIndex.filter(term: { searchable_by: account.id }) + .query(multi_match: { type: 'most_fields', query: query, operator: 'and', fields: %w(text text.stemmed) }) + .limit(limit).objects + + statuses.reject { |status| StatusFilter.new(status, account).filtered? } + end + + def perform_hashtags_search! + Tag.search_for(query.gsub(/\A#/, ''), limit) + end + def default_results { accounts: [], hashtags: [], statuses: [] } end @@ -35,4 +57,17 @@ class SearchService < BaseService def url_resource_symbol url_resource.class.name.downcase.pluralize.to_sym end + + def full_text_searchable? + return false unless Chewy.enabled? + !account.nil? && !((query.start_with?('#') || query.include?('@')) && !query.include?(' ')) + end + + def account_searchable? + !(query.include?('@') && query.include?(' ')) + end + + def hashtag_searchable? + !query.include?('@') + end end -- cgit