Skip to content

Commit

Permalink
Add tsvector_column option to pg_search_scope.
Browse files Browse the repository at this point in the history
With this option, tsearch and dmetaphone searches can search against a
tsvector column to speed up search.
  • Loading branch information
krishicks authored and Casebook Developer committed Dec 2, 2011
1 parent edf7c56 commit 7036650
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 4 deletions.
26 changes: 26 additions & 0 deletions README.rdoc
Expand Up @@ -302,6 +302,32 @@ Ignoring accents uses the {unaccent contrib package}[http://www.postgresql.org/d
SpanishQuestion.gringo_search("Que") # => [what]
SpanishQuestion.gringo_search("Cüåñtô") # => [how_many]

=== Using tsvector columns

PostgreSQL allows you the ability to search against a column with type tsvector instead of using an expression; this speeds up searching dramatically as it offloads creation of the tsvector that the tsquery is evaluated against.

To use this functionality you'll need to do a few things:

* Create a column of type tsvector that you'd like to search against. If you want to search using multiple search methods, for example tsearch and dmetaphone, you'll need a column for each.
* Create a trigger function that will update the column(s) using the expression appropriate for that type of search. See: http://www.postgresql.org/docs/current/static/textsearch-features.html#TEXTSEARCH-UPDATE-TRIGGERS
* Should you have any pre-existing data in the table, update the newly-created tsvector columns with the expression that your trigger function uses.
* Add the option to pg_search_scope, e.g:

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
}

Please note that the :against column is only used when the tsvector_column is not present for the search type.

== REQUIREMENTS

* ActiveRecord 2 or 3
Expand Down
12 changes: 8 additions & 4 deletions lib/pg_search/features/tsearch.rb
Expand Up @@ -50,10 +50,14 @@ def tsquery
end

def tsdocument
@columns.map do |search_column|
tsvector = "to_tsvector(:dictionary, #{@normalizer.add_normalization(search_column.to_sql)})"
search_column.weight.nil? ? tsvector : "setweight(#{tsvector}, #{connection.quote(search_column.weight)})"
end.join(" || ")
if @options[:tsvector_column]
@options[:tsvector_column].to_s
else
@columns.map do |search_column|
tsvector = "to_tsvector(:dictionary, #{@normalizer.add_normalization(search_column.to_sql)})"
search_column.weight.nil? ? tsvector : "setweight(#{tsvector}, #{connection.quote(search_column.weight)})"
end.join(" || ")
end
end

def tsearch_rank
Expand Down
40 changes: 40 additions & 0 deletions spec/pg_search_spec.rb
Expand Up @@ -523,6 +523,46 @@
end
end

context "using a tsvector column" do
with_model :ModelWithPgSearchUsingTsVectorColumn do
table do |t|
t.text 'content'
t.tsvector 'content_tsvector'
end

model { include PgSearch }
end

let!(:expected) { ModelWithPgSearchUsingTsVectorColumn.create!(:content => 'tiling is grouty') }
let!(:unexpected) { ModelWithPgSearchUsingTsVectorColumn.create!(:content => 'longcat is looooooooong') }

before do
ActiveRecord::Base.connection.execute <<-SQL
UPDATE #{ModelWithPgSearchUsingTsVectorColumn.table_name}
SET content_tsvector = to_tsvector('english'::regconfig, "#{ModelWithPgSearchUsingTsVectorColumn.table_name}"."content")
SQL

ModelWithPgSearchUsingTsVectorColumn.class_eval do
pg_search_scope :search_by_content_with_tsvector,
:against => :content,
:using => {
:tsearch => {
:tsvector_column => 'content_tsvector',
:dictionary => 'english'
}
}
end
end

it "should not use to_tsvector in the query" do
ModelWithPgSearchUsingTsVectorColumn.search_by_content_with_tsvector("tiles").to_sql.should_not =~ /to_tsvector/
end

it "should find the expected result" do
ModelWithPgSearchUsingTsVectorColumn.search_by_content_with_tsvector("tiles").map(&:id).should == [expected.id]
end
end

context "ignoring accents" do
before do
model_with_pg_search.class_eval do
Expand Down

0 comments on commit 7036650

Please sign in to comment.