Runestone

Runestone provides full text search PostgreSQL's full text search capabilities. It was inspired by Postgres full-text search is Good Enough! and Super Fuzzy Searching on PostgreSQL

Installation

Install Runestone from RubyGems:

$ gem install runestone

Or include it in your project's Gemfile with Bundler:

gem 'runestone'

After installation, run the Runestone's migration to to enable the necessary database extensions and create the runestones and runestone corpus tables.

$ rails db:migrate

Usage

Indexing

To index your ActiveRecord Models:

class Building < ApplicationRecord

  runestone do
    index 'name', 'addresses.global', 'addresses.national'

    attributes(:name)
    attributes(:size, :floors)
    attribute(:addresses) {
      addresses&.map{|address| {
        local: address.local,
        regional: address.regional,
        national: address.national,
        global: address.global
      } }
    }
  end

end

When searching the attribute(s) will be available in data on the result(s), but only the attributes specified by index will indexed and used for searching.

Generally Runestone will automatically update the search index if changes are made. This is done by seeing if the corresponding column or association has changed. If your search attribute is generated you need to define on the columns or associations it depends on.

class User < ApplicationRecord
  runestone do
    # The attribute `:name` is generated from the `name_en` column
    attribute(:name, :name_en) { name_en }
  end
end

class Building < ApplicationRecord
  runestone do
    # The attribute `:address_numbers` is generated from the association `addresses`
    attribute(:address_numbers, :addresses) { addresses.map{ |a| a.number } }
  end
end

class User < ActiveRecord::Base
  runestone do
    index 'name'

    # The attribute `:name` is updated when the custom logic proc returns true
    attribute :name, -> () { ...custom logic... } do
      name
    end
  end
end

Searching

To search for the Building:

Building.search("Empire")

You can also search through all indexed models with:

Runestone::Model.search("needle")

Additionally you can highlight the results. When this is done each result will have a highlights attribute which is the same as data, but with matches wrapped in a <b> tag:

Runestone::Model.highlight(@results, "needle")

Configuration

Synonym

Runestone.add_synonym('ten', '10')

Runestone.add_synonym('one hundred', '100')
Runestone.add_synonym('100', 'one hundred')

Defaults

dictionary

The default dictionary that Runestone uses is the runestone dictionary. Which is the simple dictionary in PostgreSQL with unaccent to tranliterate some characters to the ASCII equivlent.

module RailsApplicationName
  class Application < Rails::Application
    config.runestone.dictionary = :runestone
  end
end

If you are not using Rails, you can use the following:

Runestone.dictionary = :runestone

normalization for ranking

Ranking can be configured to use the normalization paramater as described in the PostgreSQL documentation. The default is 16

module RailsApplicationName
  class Application < Rails::Application
    config.runestone.normalization = 1|16
  end
end

If you are not using Rails, you can use the following:

Runestone.normalization = 16