pg_search

repository·master·Indexed 23 days ago

https://github.com/casecommons/pg_search

A Ruby gem that builds named scopes to leverage PostgreSQL's full-text search capabilities within Active Record models. It provides two primary searching techniques: Multi-search for global search indexes across multiple Active Record classes, and Search Scopes for advanced searching restricted to a single class. Supported search techniques include :tsearch (PostgreSQL built-in full text search), :trigram (requiring pgtrgm), and :dmetaphone (requiring fuzzystrmatch).

Tokens
8.5K
Snippets
25
Records
53
Agent score
82%

What's inside pg_search

  1. Multi-search vs. Search Scopes

    master

    PgSearch provides two distinct searching techniques:

    1. Multi-search: Mixes records from many different Active Record classes into a single global search index. This is ideal for implementing a site-wide generic search page.
    2. Search Scopes: Allows for advanced searching restricted to a single Active Record class. This is best suited for features like autocompleters or faceted search filtering.
  2. Access multi-search associations

    master

    PgSearch automatically builds two associations:

    1. On the original record: has_one :pg_search_document.
    2. On the PgSearch::Document record: belongs_to :searchable (polymorphic).
    odyssey = EpicPoem.create!(title: "Odyssey", author: "Homer")
    search_document = odyssey.pg_search_document
    search_document.searchable # => #<EpicPoem id: 1, ...>
    odyssey = EpicPoem.create!(title: "Odyssey", author: "Homer")
    search_document = odyssey.pg_search_document
    search_document.searchable # => #<EpicPoem id: 1, title: "Odyssey", author: "Homer">
  3. Optimize search using tsvector columns

    master

    For high-performance searching, you can search against pre-computed tsvector columns instead of evaluating expressions at runtime.

    Requirements:

    1. Create a tsvector column for each search type (e.g., one for tsearch, one for dmetaphone).
    2. Create a PostgreSQL trigger function to keep these columns updated.
    3. Populate existing data using the same expression used in the trigger.

    Configuration: In your pg_search_scope, provide the tsvector_column name within the algorithm's configuration block. Note that trigram does not use tsvectors.

    pg_search_scope :fast_content_search,
                    against: :content,
                    using: {
                      dmetaphone: {
                        tsvector_column: 'tsvector_content_dmetaphone'
                      },
                      tsearch: {
                        dictionary: 'english',
                        tsvector_column: 'tsvector_content_tsearch'
                      },
                      trigram: {} # trigram does not use tsvectors
                    }
  4. Disable multi-search indexing temporarily

    master

    To speed up large bulk operations (like importing records from an external source), you can wrap the operation in a PgSearch.disable_multisearch block. This prevents indexing during the operation, allowing you to rebuild search documents offline later using more efficient methods.

    PgSearch.disable_multisearch do
      Movie.import_from_xml_file(File.open("movies.xml"))
    end
  5. Configure pg_search for Non-Rails projects

    master
    If you are using pg_search in a project that is not built on Rails, you must manually load the PgSearch rake tasks in your Rakefile to access them. Rails projects include these automatically via a Railtie.
  6. Rebuild multi-search documents

    master

    If you change :against options or if your index is out of sync (e.g., due to using update_all which skips callbacks), you must rebuild the documents.

    Using Ruby

    To delete and regenerate all documents for a specific class:

    PgSearch::Multisearch.rebuild(Product)

    Options for rebuild:

    • clean_up: false: Prevents deleting existing records before regenerating.
    • transactional: false: Runs the rebuild outside of a single transaction.

    Using Rake

    # Rebuild for a specific class
    $ rake pg_search:multisearch:rebuild[BlogPost]
    
    # Rebuild for a specific class in a specific PostgreSQL schema
    $ rake pg_search:multisearch:rebuild[BlogPost,my_schema]
  7. Set up Double Metaphone soundalike search

    master

    Double Metaphone matches words that sound alike. This requires the PostgreSQL fuzzystrmatch extension and a specific utility function.

    To set up the required database function, run:

    $ rails g pg_search:migration:dmetaphone
    $ rake db:migrate
    class Word < ActiveRecord::Base
      include PgSearch::Model
      pg_search_scope :that_sounds_like,
                      against: :spelling,
                      using: :dmetaphone
    end
    
    # Example usage:
    # Word.that_sounds_like("fir") # => [four, far, fur]
  8. Configure global multi-search options

    master

    You can set default options for all PgSearch.multisearch calls by configuring PgSearch.multisearch_options in an initializer. These options use the same syntax as pg_search_scope.

    PgSearch.multisearch_options = {
      using: [:tsearch, :trigram],
      ignoring: :accents
    }
  9. Configure multisearch options via pg_search_multisearchable_options

    master

    The Multisearchable module relies on a configuration hash (accessible via pg_search_multisearchable_options) to determine how search documents are built and when they are updated. While the specific method to define these options is not shown in this file, the module utilizes the following keys:

    • :against: An array of symbols representing the model attributes to be indexed. The module calls these methods and joins the results with spaces to create the searchable_text.
    • :additional_attributes: A proc that receives the model instance (self) and returns a hash of extra attributes to be merged into the document's content.
    • :if: An array of procs used to determine if a pg_search_document should be created or updated during the after_save lifecycle.
    • :unless: An array of procs used to determine if a pg_search_document should be destroyed if the conditions are not met.
    • :update_if: An array of procs used during the update phase to check if the document actually needs an update (to avoid unnecessary writes).