| Module | Foo::Acts::Indexed::ClassMethods |
| In: |
lib/acts_as_indexed.rb
|
Declares a class as searchable.
| fields: | Names of fields to include in the index. Symbols pointing to instance methods of your model may also be given here. |
| index_file_depth: | Tuning value for the index partitioning. Larger values result in quicker searches, but slower indexing. Default is 3. |
| min_word_size: | Sets the minimum length for a word in a query. Words shorter than this value are ignored in searches unless preceded by the ’+’ operator. Default is 3. |
# File lib/acts_as_indexed.rb, line 33
33: def acts_as_indexed(options = {})
34: class_eval do
35: extend Foo::Acts::Indexed::SingletonMethods
36: end
37: include Foo::Acts::Indexed::InstanceMethods
38:
39: after_create :add_to_index
40: before_update :update_index
41: after_destroy :remove_from_index
42:
43: cattr_accessor :aai_config
44:
45: # default config
46: self.aai_config = {
47: :index_file => [RAILS_ROOT,'index',RAILS_ENV,name],
48: :index_file_depth => 3,
49: :min_word_size => 3,
50: :fields => []
51: }
52:
53: # set fields
54: aai_config[:fields] = options[:fields] if options.include?(:fields)
55:
56: # set minimum word size if available.
57: aai_config[:min_word_size] = options[:min_word_size] if options.include?(:min_word_size)
58:
59: # set index file depth if available.
60: # Min size of 1.
61: aai_config[:index_file_depth] = options[:index_file_depth].to_i if options.include?(:index_file_depth) && options[:index_file_depth].to_i > 0
62:
63: # Set file location for plugin testing.
64: # TODO: Find more portable (ruby) way of doing the up-one-level.
65: aai_config[:index_file] = [File.dirname(__FILE__),'../test/index',RAILS_ENV,name] if options.include?(:self_test)
66:
67: end
Adds the passed record to the index. Index is built if it does not already exist. Clears the query cache.
# File lib/acts_as_indexed.rb, line 71
71: def index_add(record)
72: build_index if !File.exists?(File.join(aai_config[:index_file]))
73: index = SearchIndex.new(aai_config[:index_file], aai_config[:index_file_depth], aai_config[:fields], aai_config[:min_word_size])
74: index.add_record(record)
75: index.save
76: @query_cache = {}
77: true
78: end
Removes the passed record from the index. Clears the query cache.
# File lib/acts_as_indexed.rb, line 82
82: def index_remove(record)
83: index = SearchIndex.new(aai_config[:index_file], aai_config[:index_file_depth], aai_config[:fields], aai_config[:min_word_size])
84: # record won't be in index if it doesn't exist. Just return true.
85: return true if !index.exists?
86: index.remove_record(record)
87: index.save
88: @query_cache = {}
89: true
90: end
Updates the index.
# File lib/acts_as_indexed.rb, line 96
96: def index_update(record)
97: build_index if !File.exists?(File.join(aai_config[:index_file]))
98: index = SearchIndex.new(aai_config[:index_file], aai_config[:index_file_depth], aai_config[:fields], aai_config[:min_word_size])
99: #index.remove_record(find(record.id))
100: #index.add_record(record)
101: index.update_record(record,find(record.id))
102: index.save
103: @query_cache = {}
104: true
105: end
Finds instances matching the terms passed in query. Terms are ANDed by default. Returns an array of model instances or, if ids_only is true, an array of integer IDs.
Keeps a cache of matched IDs for the current session to speed up multiple identical searches.
A hash passed on to active_record‘s find when retrieving the data from db, useful for pagination.
| ids_only: | Method returns an array of integer IDs when set to true. |
| no_query_cache: | Turns off the query cache when set to true. Useful for testing. |
# File lib/acts_as_indexed.rb, line 121
121: def search_index(query, find_options={}, options={})
122: # Clear the query cache off if the key is set.
123: @query_cache = {} if (options.has_key?('no_query_cache') || options[:no_query_cache])
124: if !@query_cache || !@query_cache[query]
125: logger.debug('Query not in cache, running search.')
126: build_index if !File.exists?(File.join(aai_config[:index_file]))
127: index = SearchIndex.new(aai_config[:index_file], aai_config[:index_file_depth], aai_config[:fields], aai_config[:min_word_size])
128: @query_cache = {} if !@query_cache
129: @query_cache[query] = index.search(query)
130: else
131: logger.debug('Query held in cache.')
132: end
133: return @query_cache[query].sort{|a,b| b <=> a }.collect{|a| a.first} if (options.has_key?(:ids_only) && options[:ids_only]) || @query_cache[query].empty?
134:
135: # slice up the results by offset and limit
136: offset = find_options[:offset] || 0
137: limit = find_options.include?(:limit) ? find_options[:limit] : @query_cache[query].size
138: part_query = @query_cache[query].sort{|a,b| b <=> a }.slice(offset,limit).collect{|a| a.first}
139:
140: # Set these to nil as we are dealing with the pagination by setting
141: # exactly what records we want.
142: find_options[:offset] = nil
143: find_options[:limit] = nil
144:
145: with_scope :find => find_options do
146: # Doing the find like this eliminates the possibility of errors occuring
147: # on either missing records (out-of-sync) or an empty results array.
148: records = find(:all, :conditions => [ "#{class_name.tableize}.id IN (?)", part_query])
149:
150: # Results come back in random order from SQL, so order again.
151: ranked_records = {}
152: records.each do |r|
153: ranked_records[r] = @query_cache[query][r.id]
154: end
155:
156: ranked_records.to_a.sort{|a,b| b.last <=> a.last }.collect{|a| a.first}
157: end
158:
159: end