Module: ActsAsFerret::ClassMethods

Defined in:
lib/acts_as_ferret/class_methods.rb

Instance Method Summary collapse

Instance Method Details

#aaf_indexObject

Retrieve the index instance for this model class. This can either be a LocalIndex, or a RemoteIndex instance.



106
107
108
# File 'lib/acts_as_ferret/class_methods.rb', line 106

def aaf_index
  @index ||= ActsAsFerret::get_index(aaf_configuration[:name])
end

#bulk_index(*ids) ⇒ Object

re-index a number records specified by the given ids. Use for large indexing jobs i.e. after modifying a lot of records with Ferret disabled. Please note that the state of Ferret (enabled or disabled at class or record level) is not checked by this method, so if you need to do so (e.g. because of a custom ferret_enabled? implementation), you have to do so yourself.



37
38
39
40
41
# File 'lib/acts_as_ferret/class_methods.rb', line 37

def bulk_index(*ids)
  options = Hash === ids.last ? ids.pop : {}
  ids = ids.first if ids.size == 1 && ids.first.is_a?(Enumerable)
  aaf_index.bulk_index(self.name, ids, options)
end

#disable_ferretObject

Disables ferret index updates for this model. When a block is given, Ferret will be re-enabled again after executing the block.



7
8
9
10
11
12
13
# File 'lib/acts_as_ferret/class_methods.rb', line 7

def disable_ferret
  aaf_configuration[:enabled] = false
  if block_given?
    yield
    enable_ferret
  end
end

#enable_ferretObject



15
16
17
# File 'lib/acts_as_ferret/class_methods.rb', line 15

def enable_ferret
  aaf_configuration[:enabled] = true
end

#ferret_enabled?Boolean

Returns:

  • (Boolean)


19
20
21
# File 'lib/acts_as_ferret/class_methods.rb', line 19

def ferret_enabled?
  aaf_configuration[:enabled]
end

#find_ids_with_ferret(q, options = {}, &block) ⇒ Object

Finds instance model name, ids and scores by contents. Useful e.g. if you want to search across models or do not want to fetch all result records (yet).

Options are the same as for find_with_ferret

A block can be given too, it will be executed with every result: find_ids_with_ferret(q, options) do |model, id, score|

id_array << id
scores_by_id[id] = score

end NOTE: in case a block is given, only the total_hits value will be returned instead of the [total_hits, results] array!



181
182
183
# File 'lib/acts_as_ferret/class_methods.rb', line 181

def find_ids_with_ferret(q, options = {}, &block)
  aaf_index.find_ids(q, options, &block)
end

#find_with_ferret(q, options = {}, find_options = {}) ⇒ Object

Finds instances by searching the Ferret index. Terms are ANDed by default, use OR between terms for ORed queries. Or specify :or_default => true in the :ferret options hash of acts_as_ferret.

You may either use the offset and limit options to implement your own pagination logic, or use the page and per_page options to use the built in pagination support which is compatible with will_paginate's view helpers. If page and per_page are given, offset and limit will be ignored.

options:

page

page of search results to retrieve

per_page

number of search results that are displayed per page

offset

first hit to retrieve (useful for paging)

limit

number of hits to retrieve, or :all to retrieve all results

lazy

Array of field names whose contents should be read directly from the index. Those fields have to be marked :store => :yes in their field options. Give true to get all stored fields. Note that if you have a shared index, you have to explicitly state the fields you want to fetch, true won't work here)

find_options is a hash passed on to active_record's find when retrieving the data from db, useful to i.e. prefetch relationships with :include or to specify additional filter criteria with :conditions (only string and array syntax supported). You can also call find_with_ferret inside named or dynamic scopes, if you like the conditions hash syntax more.

This method returns a SearchResults instance, which really is an Array that has been decorated with a total_hits attribute holding the total number of hits. Additionally, SearchResults is compatible with the pagination helper methods of the will_paginate plugin.

Please keep in mind that the number of results delivered might be less than limit if you specify any active record conditions that further limit the result. Use limit and offset as AR find_options instead. page and per_page are supposed to work regardless of any conditions present in find_options.



148
149
150
151
152
153
154
155
# File 'lib/acts_as_ferret/class_methods.rb', line 148

def find_with_ferret(q, options = {}, find_options = {})
  if self.scoped.to_sql =~ /WHERE/ && self.scoped.where_values_hash.empty?
    # Treat external scope the same as if :conditions present 
    # (i.e. when it comes to counting results). 
    find_options[:conditions] ||= '1=1'
  end
  return ActsAsFerret::find q, self, options, find_options
end

#rebuild_indexObject

rebuild the index from all data stored for this model, and any other model classes associated with the same index. This is called automatically when no index exists yet.



27
28
29
# File 'lib/acts_as_ferret/class_methods.rb', line 27

def rebuild_index
  aaf_index.rebuild_index
end

#records_for_bulk_index(ids, batch_size = 1000) ⇒ Object

yields the records with the given ids, in batches of batch_size



91
92
93
94
95
96
97
98
99
100
101
# File 'lib/acts_as_ferret/class_methods.rb', line 91

def records_for_bulk_index(ids, batch_size = 1000)
  transaction do
    offset = 0
    ids.each_slice(batch_size) do |id_slice|
      records = where(:id => id_slice).all
      #yield records, offset
      yield where(:id => id_slice).all, offset
      offset += batch_size
    end
  end
end

#records_for_rebuild(batch_size = 1000) ⇒ Object

runs across all records yielding those to be indexed when the index is rebuilt



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/acts_as_ferret/class_methods.rb', line 73

def records_for_rebuild(batch_size = 1000)
  transaction do
    if use_fast_batches?
      offset = 0
      while (rows = where([ "#{table_name}.id > ?", offset ]).limit(batch_size).all).any?
        offset = rows.last.id
        yield rows, offset
      end
    else
      order = "#{primary_key} ASC" # fixes #212
      0.step(self.count, batch_size) do |offset|
        yield scoped.limit(batch_size).offset(offset).order(order).all, offset
      end
    end
  end
end

#records_modified_since(time) ⇒ Object

Returns all records modified or created after the specified time. Used by the rake rebuild task to find models that need to be updated in the index after the rebuild finished because they changed while the rebuild was running. Override if your models don't stick to the created_at/updated_at convention.



59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/acts_as_ferret/class_methods.rb', line 59

def records_modified_since(time)
  condition = []
  %w(updated_at created_at).each do |col|
    condition << "#{col} >= ?" if column_names.include? col
  end
  if condition.empty?
    logger.warn "#{self.name}: Override records_modified_since(time) to keep the index up to date with records changed during rebuild."
    []
  else
    where([ condition.join(' AND '), *([time]*condition.size) ]).all
  end
end

#total_hits(q, options = {}) ⇒ Object

Returns the total number of hits for the given query

Note that since we don't query the database here, this method won't deliver the expected results when used on an AR association.



163
164
165
# File 'lib/acts_as_ferret/class_methods.rb', line 163

def total_hits(q, options={})
  aaf_index.total_hits(q, options)
end

#use_fast_batches?Boolean

true if our db and table appear to be suitable for the mysql fast batch hack (see weblog.jamisbuck.org/2007/4/6/faking-cursors-in-activerecord)

Returns:

  • (Boolean)


46
47
48
49
50
51
# File 'lib/acts_as_ferret/class_methods.rb', line 46

def use_fast_batches?
  if connection.class.name =~ /Mysql/ && primary_key == 'id' && aaf_configuration[:mysql_fast_batches]
    logger.info "using mysql specific batched find :all. Turn off with  :mysql_fast_batches => false if you encounter problems (i.e. because of non-integer UUIDs in the id column)"
    true
  end
end