| 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. |
| index_file: | Sets the location for the index. By default this is RAILS_ROOT/index. Specify as an array. Heroku, for example would use RAILS_ROOT/tmp/index, which would be set as [RAILS_ROOT,’tmp’,’index] |
# File lib/acts_as_indexed.rb, line 37
37: def acts_as_indexed(options = {})
38: class_eval do
39: extend Foo::Acts::Indexed::SingletonMethods
40: end
41: include Foo::Acts::Indexed::InstanceMethods
42:
43: after_create :add_to_index
44: before_update :update_index
45: after_destroy :remove_from_index
46:
47: cattr_accessor :aai_config
48:
49: # default config
50: self.aai_config = {
51: :index_file => [RAILS_ROOT,'index'],
52: :index_file_depth => 3,
53: :min_word_size => 3,
54: :fields => []
55: }
56:
57: aai_config[:index_file] += [RAILS_ENV,name]
58:
59: aai_config.merge!(options)
60:
61: raise(ArgumentError, 'no fields specified') unless aai_config.include?(:fields)
62: raise(ArgumentError, 'index_file_depth cannot be less than one (1)') if aai_config[:index_file_depth].to_i < 1
63: 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 67
67: def index_add(record)
68: build_index if !File.exists?(File.join(aai_config[:index_file]))
69: index = SearchIndex.new(aai_config[:index_file], aai_config[:index_file_depth], aai_config[:fields], aai_config[:min_word_size])
70: index.add_record(record)
71: index.save
72: @query_cache = {}
73: true
74: end
Removes the passed record from the index. Clears the query cache.
# File lib/acts_as_indexed.rb, line 78
78: def index_remove(record)
79: index = SearchIndex.new(aai_config[:index_file], aai_config[:index_file_depth], aai_config[:fields], aai_config[:min_word_size])
80: # record won't be in index if it doesn't exist. Just return true.
81: return true if !index.exists?
82: index.remove_record(record)
83: index.save
84: @query_cache = {}
85: true
86: end
Updates the index.
# File lib/acts_as_indexed.rb, line 92
92: def index_update(record)
93: build_index if !File.exists?(File.join(aai_config[:index_file]))
94: index = SearchIndex.new(aai_config[:index_file], aai_config[:index_file_depth], aai_config[:fields], aai_config[:min_word_size])
95: #index.remove_record(find(record.id))
96: #index.add_record(record)
97: index.update_record(record,find(record.id))
98: index.save
99: @query_cache = {}
100: true
101: 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.
Same as ActiveRecord#find options hash. An :order key will override the relevance ranking
| 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 118
118: def search_index(query, find_options={}, options={})
119: # Clear the query cache off if the key is set.
120: @query_cache = {} if (options.has_key?('no_query_cache') || options[:no_query_cache])
121: if !@query_cache || !@query_cache[query]
122: logger.debug('Query not in cache, running search.')
123: build_index if !File.exists?(File.join(aai_config[:index_file]))
124: index = SearchIndex.new(aai_config[:index_file], aai_config[:index_file_depth], aai_config[:fields], aai_config[:min_word_size])
125: @query_cache = {} if !@query_cache
126: @query_cache[query] = index.search(query)
127: else
128: logger.debug('Query held in cache.')
129: end
130: 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?
131:
132: # slice up the results by offset and limit
133: offset = find_options[:offset] || 0
134: limit = find_options.include?(:limit) ? find_options[:limit] : @query_cache[query].size
135: part_query = @query_cache[query].sort{|a,b| b <=> a }.slice(offset,limit).collect{|a| a.first}
136:
137: # Set these to nil as we are dealing with the pagination by setting
138: # exactly what records we want.
139: find_options[:offset] = nil
140: find_options[:limit] = nil
141:
142: with_scope :find => find_options do
143: # Doing the find like this eliminates the possibility of errors occuring
144: # on either missing records (out-of-sync) or an empty results array.
145: records = find(:all, :conditions => [ "#{class_name.tableize}.id IN (?)", part_query])
146:
147: if find_options.include?(:order)
148: records # Just return the records without ranking them.
149: else
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: end
159:
160: end