Module: PgFullTextSearchable

Extended by:
ActiveSupport::Concern
Included in:
Ci::BuildName, Ci::Catalog::Resource, Issue
Defined in:
app/models/concerns/pg_full_text_searchable.rb

Overview

This module adds PG full-text search capabilities to a model. A search_data association with a search_vector column is required.

Declare the fields that will be part of the search vector with their corresponding weights. Possible values for weight are A, B, C, or D. For example:

include PgFullTextSearchable pg_full_text_searchable columns: [{ name: ‘title’, weight: ‘A’ }, { name: ‘description’, weight: ‘B’ }]

This module sets up an after_commit hook that updates the search data when the searchable columns are changed. You will need to implement the #persist_pg_full_text_search_vector method that does the actual insert or update.

This also adds a pg_full_text_search scope so you can do:

Model.pg_full_text_search(“some search term”)

For situations where the search_vector column exists within the model table and not in a search_data association, you may instead use pg_full_text_search_in_model.

Constant Summary collapse

VERY_LONG_WORDS_WITH_AT_REGEX =
%r([A-Za-z0-9@]{500,})
LONG_WORDS_REGEX =
%r([A-Za-z0-9+/]{50,})
TSVECTOR_MAX_LENGTH =
1.megabyte.freeze
TEXT_SEARCH_DICTIONARY =
'english'
XML_TAG_REGEX =
%r{</?([^>]+)>}

Instance Method Summary collapse

Instance Method Details

#update_search_data!Object



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'app/models/concerns/pg_full_text_searchable.rb', line 33

def update_search_data!
  tsvector_sql_nodes = self.class.pg_full_text_searchable_columns.map do |column, weight|
    tsvector_arel_node(column, weight)&.to_sql
  end

  persist_pg_full_text_search_vector(Arel.sql(tsvector_sql_nodes.compact.join(' || ')))
rescue ActiveRecord::StatementInvalid => e
  raise unless e.cause.is_a?(PG::ProgramLimitExceeded) && e.message.include?('string is too long for tsvector')

  Gitlab::AppJsonLogger.error(
    message: 'Error updating search data: string is too long for tsvector',
    class: self.class.name,
    model_id: self.id
  )
end