Fix accounts search by full/partial display name and others (#11580)
- Restrict followers counts to local users to minimize local advantage - Fix emoji shortcodes causing error in search - Fix search syntax parse errors not being caught
This commit is contained in:
		| @@ -26,10 +26,17 @@ class AccountsIndex < Chewy::Index | |||||||
|   define_type ::Account.searchable.includes(:account_stat), delete_if: ->(account) { account.destroyed? || !account.searchable? } do |   define_type ::Account.searchable.includes(:account_stat), delete_if: ->(account) { account.destroyed? || !account.searchable? } do | ||||||
|     root date_detection: false do |     root date_detection: false do | ||||||
|       field :id, type: 'long' |       field :id, type: 'long' | ||||||
|       field :display_name, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'content' |  | ||||||
|       field :acct, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'content', value: ->(account) { [account.username, account.domain].compact.join('@') } |       field :display_name, type: 'text', analyzer: 'content' do | ||||||
|       field :following_count, type: 'long', value: ->(account) { account.active_relationships.count } |         field :edge_ngram, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'content' | ||||||
|       field :followers_count, type: 'long', value: ->(account) { account.passive_relationships.count } |       end | ||||||
|  |  | ||||||
|  |       field :acct, type: 'text', analyzer: 'content', value: ->(account) { [account.username, account.domain].compact.join('@') } do | ||||||
|  |         field :edge_ngram, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'content' | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       field :following_count, type: 'long', value: ->(account) { account.following.local.count } | ||||||
|  |       field :followers_count, type: 'long', value: ->(account) { account.followers.local.count } | ||||||
|       field :last_status_at, type: 'date', value: ->(account) { account.last_status_at || account.created_at } |       field :last_status_at, type: 'date', value: ->(account) { account.last_status_at || account.created_at } | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|   | |||||||
| @@ -1,14 +1,15 @@ | |||||||
| # frozen_string_literal: true | # frozen_string_literal: true | ||||||
|  |  | ||||||
| class SearchQueryParser < Parslet::Parser | class SearchQueryParser < Parslet::Parser | ||||||
|   rule(:term)     { match('[^\s":]').repeat(1).as(:term) } |   rule(:term)      { match('[^\s":]').repeat(1).as(:term) } | ||||||
|   rule(:quote)    { str('"') } |   rule(:quote)     { str('"') } | ||||||
|   rule(:colon)    { str(':') } |   rule(:colon)     { str(':') } | ||||||
|   rule(:space)    { match('\s').repeat(1) } |   rule(:space)     { match('\s').repeat(1) } | ||||||
|   rule(:operator) { (str('+') | str('-')).as(:operator) } |   rule(:operator)  { (str('+') | str('-')).as(:operator) } | ||||||
|   rule(:prefix)   { (term >> colon).as(:prefix) } |   rule(:prefix)    { (term >> colon).as(:prefix) } | ||||||
|   rule(:phrase)   { (quote >> (term >> space.maybe).repeat >> quote).as(:phrase) } |   rule(:shortcode) { (colon >> term >> colon.maybe).as(:shortcode) } | ||||||
|   rule(:clause)   { (prefix.maybe >> operator.maybe >> (phrase | term)).as(:clause) } |   rule(:phrase)    { (quote >> (term >> space.maybe).repeat >> quote).as(:phrase) } | ||||||
|   rule(:query)    { (clause >> space.maybe).repeat.as(:query) } |   rule(:clause)    { (prefix.maybe >> operator.maybe >> (phrase | term | shortcode)).as(:clause) } | ||||||
|  |   rule(:query)     { (clause >> space.maybe).repeat.as(:query) } | ||||||
|   root(:query) |   root(:query) | ||||||
| end | end | ||||||
|   | |||||||
| @@ -75,6 +75,8 @@ class SearchQueryTransformer < Parslet::Transform | |||||||
|  |  | ||||||
|     if clause[:term] |     if clause[:term] | ||||||
|       TermClause.new(prefix, operator, clause[:term].to_s) |       TermClause.new(prefix, operator, clause[:term].to_s) | ||||||
|  |     elsif clause[:shortcode] | ||||||
|  |       TermClause.new(prefix, operator, ":#{clause[:term]}:") | ||||||
|     elsif clause[:phrase] |     elsif clause[:phrase] | ||||||
|       PhraseClause.new(prefix, operator, clause[:phrase].map { |p| p[:term].to_s }.join(' ')) |       PhraseClause.new(prefix, operator, clause[:phrase].map { |p| p[:term].to_s }.join(' ')) | ||||||
|     else |     else | ||||||
|   | |||||||
| @@ -67,7 +67,7 @@ class AccountSearchService < BaseService | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   def from_elasticsearch |   def from_elasticsearch | ||||||
|     must_clauses   = [{ multi_match: { query: terms_for_query, fields: likely_acct? ? %w(acct) : %w(acct^2 display_name), type: 'best_fields' } }] |     must_clauses   = [{ multi_match: { query: terms_for_query, fields: likely_acct? ? %w(acct.edge_ngram acct) : %w(acct.edge_ngram acct display_name.edge_ngram display_name), type: 'most_fields', operator: 'and' } }] | ||||||
|     should_clauses = [] |     should_clauses = [] | ||||||
|  |  | ||||||
|     if account |     if account | ||||||
|   | |||||||
| @@ -52,7 +52,7 @@ class SearchService < BaseService | |||||||
|     preloaded_relations = relations_map_for_account(@account, account_ids, account_domains) |     preloaded_relations = relations_map_for_account(@account, account_ids, account_domains) | ||||||
|  |  | ||||||
|     results.reject { |status| StatusFilter.new(status, @account, preloaded_relations).filtered? } |     results.reject { |status| StatusFilter.new(status, @account, preloaded_relations).filtered? } | ||||||
|   rescue Faraday::ConnectionFailed |   rescue Faraday::ConnectionFailed, Parslet::ParseFailed | ||||||
|     [] |     [] | ||||||
|   end |   end | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user