Module: BigIndex::Resource::ClassMethods

Defined in:
lib/big_index/resource.rb

Constant Summary collapse

INDEX_FIND_OPTIONS =
[ :source, :offset, :limit, :conditions, :order, :group, :fields, :debug, :view, :format, :raw_result ]

Instance Method Summary collapse

Instance Method Details

#add_index_field(index_field) ⇒ Object



267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/big_index/resource.rb', line 267

def add_index_field(index_field)
  configuration = @index_configuration
  if configuration[:fields]
    unless configuration[:fields].include?(index_field)
      configuration[:fields] << index_field
    else
      return
    end
  else
    configuration[:fields] = [index_field]
  end

  define_method("#{index_field.field_name}_for_index") do
    index_field.block ? index_field.block.call(self) : self.send(index_field.field_name.to_sym)
  end
end

#default_index_views_hashObject



229
230
231
# File 'lib/big_index/resource.rb', line 229

def default_index_views_hash
  {:default => self.index_configuration[:fields]}
end

#default_repository_nameObject



48
49
50
# File 'lib/big_index/resource.rb', line 48

def default_repository_name
  Repository.default_name
end

#drop_indexTrueClass, FalseClass

Drops the index for the current model.

Returns:

  • (TrueClass, FalseClass)

    whether the index was dropped.



208
209
210
# File 'lib/big_index/resource.rb', line 208

def drop_index
  index_adapter.drop_index(self)
end

#find_every_by_index(options = {}) ⇒ Object

Indexed find method called by find_with_index and dispatches the actual search to the adapter.



324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'lib/big_index/resource.rb', line 324

def find_every_by_index(options={})
  # Construct the query. First add the type information.
  query =""

  # set default operator
  options[:operator] ||= :or

  # First add the conditions predicates
  conditions = options[:conditions]
  if conditions.is_a?(String)
    query << conditions
  elsif conditions.is_a?(Array) and !conditions.empty?
    nb_conditions = conditions.size - 1
    i = 0
    query << conditions[0].gsub(/\?/) do |c|
      i += 1
      raise ArgumentError, "Missing condition argument" unless i <= nb_conditions
      "#{conditions[i]}"
    end
  elsif conditions.is_a?(Hash) and !conditions.empty?
    conditions.each do |k, v|
      query << "#{k}:#{v} "
    end
  end

  fields =
    if options[:fields]
      options[:fields]
    else
      fields = options[:view] ? index_views_hash[options[:view]] : index_views_hash[:default]
      fields ||= []
    end

  if options[:format] == :ids
    index_adapter.find_ids_by_index(self, query, {  :offset   => options[:offset],
                                              :order    => options[:order],
                                              :limit    => options[:limit],
                                              :fields   => fields,
                                              :operator => options[:operator],
                                              :raw_result => options[:raw_result]})
  else
    index_adapter.find_by_index(self, query, {  :offset   => options[:offset],
                                          :order    => options[:order],
                                          :limit    => options[:limit],
                                          :operator => options[:operator],
                                          :raw_result => options[:raw_result]})
  end

end

#find_with_index(*args) ⇒ Object

Class #find method

From - alias_method_chain :find, :index

This redefines the original #find method of the class, and replaces it with an indexed version of #find. The indexed version can be bypassed (dispatch to original instead) by passing the option :bypass_index => true to the method.

Returns:

  • the instantiated records either as a single object (case of :first), or as an array of objects. When the option :raw_result => true is passed to it, it will return a result object specific to the indexer used. In the case of Solr, it will return a SolrResult object for example.



300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/big_index/resource.rb', line 300

def find_with_index(*args)
  options = args.extract_options!
  unless options[:bypass_index]
    case args.first
      when :first then
        validate_index_find_options(options)
        find_every_by_index(options.merge({:limit => 1})).first
      when :all   then
        validate_index_find_options(options)
        find_every_by_index(options)
      else
        find_from_ids(args, options) #TODO: implement this
    end
  else
    options.delete(:bypass_index)
    find_without_index(*(args + [options]))
  end
end

#index(*params, &block) ⇒ Object

Macro for defining a class attribute as an indexed field.

Also creates the corresponding attribute finder method, which defaults to the field name. This can be defined with the :finder_name => “anothername” option.



258
259
260
261
262
263
264
265
# File 'lib/big_index/resource.rb', line 258

def index(*params, &block)
  index_field = IndexField.new(params, block)

  add_index_field(index_field)

  # Create the attribute finder method
  define_finder index_field[:finder_name]
end

#index_adapterObject



65
66
67
# File 'lib/big_index/resource.rb', line 65

def index_adapter
  repository.adapter
end

#index_configurationObject



69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/big_index/resource.rb', line 69

def index_configuration
  begin
    config = {}
    config = @index_configuration.dup

    config[:fields] = @index_configuration[:fields].dup if @index_configuration[:fields]
    config[:exclude_fields] = @index_configuration[:exclude_fields].dup if @index_configuration[:exclude_fields]

    config
  rescue
   {}
  end
end

#index_configuration=(config) ⇒ Object



83
84
85
# File 'lib/big_index/resource.rb', line 83

def index_configuration=(config)
  @index_configuration = config
end

#index_disabledObject



123
124
125
# File 'lib/big_index/resource.rb', line 123

def index_disabled
  @index_disabled ||= false
end

#index_disabled=(bool) ⇒ Object



119
120
121
# File 'lib/big_index/resource.rb', line 119

def index_disabled= bool
  @index_disabled = bool
end

#index_field(field_name) ⇒ Object



239
240
241
242
243
244
# File 'lib/big_index/resource.rb', line 239

def index_field(field_name)
  field_name = field_name.to_s
  if index_configuration[:fields].map(&:field_name).map(&:to_s).include?(field_name)
    index_configuration[:fields].select{|field| field.field_name.to_s == field_name}.first
  end
end

#index_fields(view_name = :default) ⇒ Object



233
234
235
236
237
# File 'lib/big_index/resource.rb', line 233

def index_fields(view_name = :default)
  field_list = index_views_hash[view_name]

  index_configuration[:fields].select{|field| field_list.include?(field.field_name)}
end

#index_typeObject

The index_type will be the name of the model class by default.



115
116
117
# File 'lib/big_index/resource.rb', line 115

def index_type
  name
end

#index_view(name, columns) ⇒ Object



212
213
214
215
# File 'lib/big_index/resource.rb', line 212

def index_view(name, columns)
  write_inheritable_attribute(:index_views_hash, read_inheritable_attribute(:index_views_hash) || default_index_views_hash)
  read_inheritable_attribute(:index_views_hash)[name] = columns
end

#index_view_namesObject



221
222
223
# File 'lib/big_index/resource.rb', line 221

def index_view_names
  @index_view_names ||= index_views_hash.keys
end

#index_viewsObject



217
218
219
# File 'lib/big_index/resource.rb', line 217

def index_views
  @index_views ||= index_views_hash.values
end

#index_views_hashObject



225
226
227
# File 'lib/big_index/resource.rb', line 225

def index_views_hash
  read_inheritable_attribute(:index_views_hash) || default_index_views_hash
end

#indexed?TrueClass, FalseClass

Whenever a Ruby class includes BigIndex::Resource, it’ll be considered as indexed.

This method checks whether the current class, as well as any ancestors in its inheritance tree, is indexed.

Returns:

  • (TrueClass, FalseClass)

    whether or not the current class, or any of its ancestors are indexed.



98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/big_index/resource.rb', line 98

def indexed?
  if @indexed.nil?
    @indexed = false
    ancestors.each do |a|
      if a.respond_to?(:indexed?) and a.indexed?
        @indexed = true
        break
      end
    end
  end
  @indexed
end

#rebuild_index(options = {}, finder_options = {}) ⇒ Integer

Dispatches a command to the current adapter to rebuild the index.

Returns:

  • (Integer)

    representing number of items processed.



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
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
# File 'lib/big_index/resource.rb', line 133

def rebuild_index(options={}, finder_options={})
  logger.info "=== Rebuilding index for: #{self.index_type}" unless options[:silent]

  if options[:drop]
    logger.info "Dropping index for: #{self.index_type}" unless options[:silent]
    index_adapter.drop_index(self)
  end

  finder_options[:batch_size] ||= 100
  finder_options[:view] ||= :all
  finder_options[:bypass_index] = true

  options[:batch_size] ||= 100
  options[:commit] = true unless options.has_key?(:commit)
  options[:optimize] = true unless options.has_key?(:optimize)

  logger.info "Offset: #{finder_options[:offset]}" unless options[:silent]
  logger.info "Stop row: #{finder_options[:stop_row]}" unless options[:silent]

  buffer = []
  items_processed = 0
  loop = 0

  if self.respond_to?(:scan)
    # TODO: This scan method doesn't always exist (in the case of ActiveRecord).
    # This will need to be removed.
    self.scan(finder_options) do |r|
      items_processed += 1
      buffer << r
      if buffer.size > options[:batch_size]
        loop += 1
        index_adapter.process_index_batch(buffer, loop, options)
        buffer.clear
      end
    end

    index_adapter.process_index_batch(buffer, loop, options) unless buffer.empty?
  elsif self.respond_to?(:find)
    ar_options = {:limit => finder_options[:batch_size]}

    while
      loop += 1

      buffer = self.find_without_index(:all, ar_options)
      break if buffer.empty?
      items_processed += buffer.size

      index_adapter.process_index_batch(buffer, loop, options)

      break if buffer.size < finder_options[:batch_size]

      buffer.clear
      ar_options[:offset] = (loop * finder_options[:batch_size])+1
    end
  else
    raise "Your model needs at least a scan() or find() method"
  end

  if items_processed > 0
    logger.info "Index for #{self.index_type} has been rebuilt (#{items_processed} records)." unless options[:silent]
  else
    logger.info "Nothing to index for #{self.index_type}." unless options[:silent]
  end

  logger.info "=== Finished rebuilding index for: #{self.index_type}" unless options[:silent]

  return items_processed
end

#repository(name = nil) ⇒ Object



56
57
58
59
60
61
62
63
# File 'lib/big_index/resource.rb', line 56

def repository(name = nil)
  @repository ||
    if block_given?
      BigIndex.repository(name || repository_name) { |*block_args| yield(*block_args) }
    else
      BigIndex.repository(name || repository_name)
    end
end

#repository_nameObject



52
53
54
# File 'lib/big_index/resource.rb', line 52

def repository_name
  Repository.context.any? ? Repository.context.last.name : default_repository_name
end

#required_index_fieldsObject



246
247
248
# File 'lib/big_index/resource.rb', line 246

def required_index_fields
  [index_configuration[:type_field], index_configuration[:primary_key_field], :id]
end

#validate_index_find_options(options) ⇒ Object

Validates the options passed to the find methods based on the accepted keys defined in INDEX_FIND_OPTIONS



381
382
383
# File 'lib/big_index/resource.rb', line 381

def validate_index_find_options(options) #:nodoc:
  options.assert_valid_keys(INDEX_FIND_OPTIONS)
end