| Module | ActiveRecord::Acts::Searchable::ClassMethods |
| In: |
lib/acts_as_searchable.rb
|
| VALID_FULLTEXT_OPTIONS | = | [:limit, :offset, :order, :attributes, :raw_matches, :find] |
Examples:
acts_as_searchable :attributes => { :title => nil, :blog => :blog_title }, :searchable_fields => [ :title, :body ]
This would store the return value of the title method in the title attribute and the return value of the blog_title method in the blog attribute. The contents of the title and body columns would end up being indexed for searching.
Attributes that match the reserved names of the Hyper Estraier system attributes are mapped automatically. This is something to keep in mind for custom ordering options or additional query constraints in fulltext_search For a list of these attributes see EstraierPure::SYSTEM_ATTRIBUTES or visit:
http://hyperestraier.sourceforge.net/uguide-en.html#attributes
From the example above:
Model.fulltext_search('query', :order => '@title STRA') # Returns results ordered by title in ascending order
Model.fulltext_search('query', :attributes => 'blog STREQ poocs.net') # Returns results with a blog attribute of 'poocs.net'
# File lib/acts_as_searchable.rb, line 113
113: def acts_as_searchable(options = {})
114: return if self.included_modules.include?(ActiveRecord::Acts::Searchable::ActMethods)
115:
116: send :include, ActiveRecord::Acts::Searchable::ActMethods
117:
118: cattr_accessor :searchable_fields, :attributes_to_store, :if_changed, :estraier_connection, :estraier_node,
119: :estraier_host, :estraier_port, :estraier_user, :estraier_password
120:
121: self.estraier_node = estraier_config['node'] || RAILS_ENV
122: self.estraier_host = estraier_config['host'] || 'localhost'
123: self.estraier_port = estraier_config['port'] || 1978
124: self.estraier_user = estraier_config['user'] || 'admin'
125: self.estraier_password = estraier_config['password'] || 'admin'
126: self.searchable_fields = options[:searchable_fields] || [ :body ]
127: self.attributes_to_store = options[:attributes] || {}
128: self.if_changed = options[:if_changed] || []
129:
130: send :attr_accessor, :changed_attributes
131:
132: class_eval do
133: after_update :update_index
134: after_create :add_to_index
135: after_destroy :remove_from_index
136: after_save :clear_changed_attributes
137:
138: (if_changed + searchable_fields + attributes_to_store.collect { |attribute, method| method or attribute }).each do |attr_name|
139: define_method("#{attr_name}=") do |value|
140: write_changed_attribute attr_name, value
141: end
142: end
143:
144: connect_estraier
145: end
146: end
Clear all entries from index
# File lib/acts_as_searchable.rb, line 209
209: def clear_index!
210: estraier_index.each { |d| estraier_connection.out_doc(d.attr('@id')) unless d.nil? }
211: end
Perform a fulltext search against the Hyper Estraier index.
Options taken:
Examples:
Article.fulltext_search("biscuits AND gravy")
Article.fulltext_search("biscuits AND gravy", :limit => 15, :offset => 14)
Article.fulltext_search("biscuits AND gravy", :attributes => "tag STRINC food")
Article.fulltext_search("biscuits AND gravy", :attributes => ["tag STRINC food", "@title STRBW Biscuit"])
Article.fulltext_search("biscuits AND gravy", :order => "@title STRA")
Article.fulltext_search("biscuits AND gravy", :raw_matches => true)
Article.fulltext_search("biscuits AND gravy", :find => { :order => :title, :include => :comments })
Consult the Hyper Estraier documentation on proper query syntax:
http://hyperestraier.sourceforge.net/uguide-en.html#searchcond
# File lib/acts_as_searchable.rb, line 172
172: def fulltext_search(query = "", options = {})
173: options.reverse_merge!(:limit => 100, :offset => 0)
174: options.assert_valid_keys(VALID_FULLTEXT_OPTIONS)
175:
176: find_options = options[:find] || {}
177: [ :limit, :offset ].each { |k| find_options.delete(k) } unless find_options.blank?
178:
179: cond = EstraierPure::Condition.new
180: cond.set_phrase query
181: cond.add_attr("type STREQ #{self.to_s}")
182: [options[:attributes]].flatten.reject { |a| a.blank? }.each do |attr|
183: cond.add_attr attr
184: end
185: cond.set_max options[:limit]
186: cond.set_skip options[:offset]
187: cond.set_order options[:order] if options[:order]
188:
189: matches = nil
190: seconds = Benchmark.realtime do
191: result = estraier_connection.search(cond, 1);
192: return [] unless result
193:
194: matches = get_docs_from(result)
195: return matches if options[:raw_matches]
196: end
197:
198: logger.debug(
199: connection.send(:format_log_entry,
200: "#{self.to_s} seach for '#{query}' (#{sprintf("%f", seconds)})",
201: "Condition: #{cond.to_s}"
202: )
203: )
204:
205: matches.blank? ? [] : find(matches.collect { |m| m.attr('db_id') }, find_options)
206: end