Module: ActiveRecord::Acts::Searchable::ClassMethods
- Defined in:
- lib/acts_as_searchable.rb
Constant Summary collapse
- VALID_FULLTEXT_OPTIONS =
[:limit, :offset, :order, :attributes, :raw_matches, :find]
Instance Method Summary collapse
-
#acts_as_searchable(options = {}) ⇒ Object
Configuration options.
-
#clear_index! ⇒ Object
Clear all entries from index.
-
#estraier_index ⇒ Object
:nodoc:.
-
#fulltext_search(query = "", options = {}) ⇒ Object
Perform a fulltext search against the Hyper Estraier index.
-
#get_docs_from(result) ⇒ Object
:nodoc:.
-
#reindex! ⇒ Object
Peform a full re-index of the model data for this model.
Instance Method Details
#acts_as_searchable(options = {}) ⇒ Object
Configuration options
-
searchable_fields
- Fields to provide searching and indexing for (default: ‘body’) -
attributes
- Additional attributes to store in Hyper Estraier with the appropriate method supplying the value -
if_changed
- Extra list of attributes to add to the list of attributes that trigger an index update when changed
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.
Attribute naming
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'
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/acts_as_searchable.rb', line 113 def acts_as_searchable( = {}) return if self.included_modules.include?(ActiveRecord::Acts::Searchable::ActMethods) send :include, ActiveRecord::Acts::Searchable::ActMethods cattr_accessor :searchable_fields, :attributes_to_store, :if_changed, :estraier_connection, :estraier_node, :estraier_host, :estraier_port, :estraier_user, :estraier_password self.estraier_node = estraier_config['node'] || RAILS_ENV self.estraier_host = estraier_config['host'] || 'localhost' self.estraier_port = estraier_config['port'] || 1978 self.estraier_user = estraier_config['user'] || 'admin' self.estraier_password = estraier_config['password'] || 'admin' self.searchable_fields = [:searchable_fields] || [ :body ] self.attributes_to_store = [:attributes] || {} self.if_changed = [:if_changed] || [] send :attr_accessor, :changed_attributes class_eval do after_update :update_index after_create :add_to_index after_destroy :remove_from_index after_save :clear_changed_attributes (if_changed + searchable_fields + attributes_to_store.collect { |attribute, method| method or attribute }).each do |attr_name| define_method("#{attr_name}=") do |value| write_changed_attribute attr_name, value end end connect_estraier end end |
#clear_index! ⇒ Object
Clear all entries from index
209 210 211 |
# File 'lib/acts_as_searchable.rb', line 209 def clear_index! estraier_index.each { |d| estraier_connection.out_doc(d.attr('@id')) unless d.nil? } end |
#estraier_index ⇒ Object
:nodoc:
218 219 220 221 222 223 224 |
# File 'lib/acts_as_searchable.rb', line 218 def estraier_index #:nodoc: cond = EstraierPure::Condition::new cond.add_attr("type STREQ #{self.to_s}") result = estraier_connection.search(cond, 1) docs = get_docs_from(result) docs end |
#fulltext_search(query = "", options = {}) ⇒ Object
Perform a fulltext search against the Hyper Estraier index.
Options taken:
-
limit
- Maximum number of records to retrieve (default:100
) -
offset
- Number of records to skip (default:0
) -
order
- Hyper Estraier expression to sort the results (example:@title STRA
, default: ordering by score) -
attributes
- String to append to Hyper Estraier search query -
raw_matches
- Returns raw Hyper Estraier documents instead of instantiated AR objects -
find
- Options to pass on to theActiveRecord::Base#find
call
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
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/acts_as_searchable.rb', line 172 def fulltext_search(query = "", = {}) .reverse_merge!(:limit => 100, :offset => 0) .assert_valid_keys(VALID_FULLTEXT_OPTIONS) = [:find] || {} [ :limit, :offset ].each { |k| .delete(k) } unless .blank? cond = EstraierPure::Condition.new cond.set_phrase query cond.add_attr("type STREQ #{self.to_s}") [[:attributes]].flatten.reject { |a| a.blank? }.each do |attr| cond.add_attr attr end cond.set_max [:limit] cond.set_skip [:offset] cond.set_order [:order] if [:order] matches = nil seconds = Benchmark.realtime do result = estraier_connection.search(cond, 1); return [] unless result matches = get_docs_from(result) return matches if [:raw_matches] end logger.debug( connection.send(:format_log_entry, "#{self.to_s} seach for '#{query}' (#{sprintf("%f", seconds)})", "Condition: #{cond.to_s}" ) ) matches.blank? ? [] : find(matches.collect { |m| m.attr('db_id') }, ) end |
#get_docs_from(result) ⇒ Object
:nodoc:
226 227 228 229 230 231 232 |
# File 'lib/acts_as_searchable.rb', line 226 def get_docs_from(result) #:nodoc: docs = [] for i in 0...result.doc_num docs << result.get_doc(i) end docs end |
#reindex! ⇒ Object
Peform a full re-index of the model data for this model
214 215 216 |
# File 'lib/acts_as_searchable.rb', line 214 def reindex! find(:all).each { |r| r.update_index(true) } end |