about summary refs log tree commit diff
path: root/app/services/search_service.rb
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2018-02-09 23:04:47 +0100
committerGitHub <noreply@github.com>2018-02-09 23:04:47 +0100
commit3ebc0ad4d3c2fe0b0951a334642b769bd521a799 (patch)
tree9b88b2da41dbbc24cb922660937b5ee65366c38d /app/services/search_service.rb
parent235c14c79d620d47012a08425324df222a136457 (diff)
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
Diffstat (limited to 'app/services/search_service.rb')
-rw-r--r--app/services/search_service.rb43
1 files changed, 39 insertions, 4 deletions
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