Module: Redis::TextSearch::InstanceMethods

Defined in:
lib/redis/text_search.rb

Overview

:nodoc:

Instance Method Summary collapse

Instance Method Details

#delete_text_indexes(*fields) ⇒ Object

Delete all text indexes that the object is a member of. Should be used in an after_destroy hook to remove the dead object.



313
314
315
316
317
318
319
320
# File 'lib/redis/text_search.rb', line 313

def delete_text_indexes(*fields)
  fields = self.class.text_indexes.keys if fields.empty?
  fields.each do |field|
    del_indexes = text_indexes_for(field)
    exec_pipelined_index_cmd(:srem, del_indexes)
    redis.del field_key("#{field}_indexes")
  end
end

#field_key(name) ⇒ Object

:nodoc:



220
221
222
# File 'lib/redis/text_search.rb', line 220

def field_key(name) #:nodoc:
  self.class.field_key(name, id)
end

#redisObject



219
# File 'lib/redis/text_search.rb', line 219

def redis() self.class.redis end

#reverse_index_key(field) ⇒ Object

Name of the reverse index key



237
238
239
# File 'lib/redis/text_search.rb', line 237

def reverse_index_key(field)
  self.class.reverse_index_key(id, field)
end

#text_index_options_for(field) ⇒ Object

Retrieve the options for the given field



225
226
227
228
# File 'lib/redis/text_search.rb', line 225

def text_index_options_for(field)
  self.class.text_indexes[field] ||
    raise(BadTextIndex, "No such text index #{field} in #{self.class.name}")
end

#text_indexesObject

Retrieve all text indexes



242
243
244
245
# File 'lib/redis/text_search.rb', line 242

def text_indexes
  fields = self.class.text_indexes.keys
  fields.collect{|f| text_indexes_for(f)}.flatten
end

#text_indexes_for(field) ⇒ Object

Retrieve the reverse-mapping of text indexes for a given field. Designed as a utility method but maybe you will find it useful.



232
233
234
# File 'lib/redis/text_search.rb', line 232

def text_indexes_for(field)
  self.class.text_indexes_for(id, field)
end

#update_text_indexes(*fields) ⇒ Object

Update all text indexes for the given object. Should be used in an after_save hook or other applicable area, for example r.update_text_indexes. Can pass an array of field names to restrict updates just to those fields.



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/redis/text_search.rb', line 250

def update_text_indexes(*fields)
  fields = self.class.text_indexes.keys if fields.empty?
  fields.each do |field|
    options = self.class.text_indexes[field]
    value = self.send(field).to_s
    next if value.length < options[:minlength]  # too short to index
    indexes = []

    # If values is array, like :tags => ["a", "b"], use as-is
    # Otherwise, split words on /\s+/ so :title => "Hey there" => ["Hey", "there"]
    values = value.is_a?(Array) ? value : options[:split] ? value.split(options[:split]) : value
    values.each do |val|
      val.gsub!(/[^\w\s]+/,'')
      val.downcase!
      next if value.length < options[:minlength]
      next if self.class.text_index_exclude_list.include? value
      if options[:exact]
        str = val.gsub(/\s+/, '.')  # can't have " " in Redis cmd string
        indexes << "#{options[:key]}:#{str}"
      else
        len = options[:minlength]
        while len <= val.length
          str = val[0,len].gsub(/\s+/, '.')  # can't have " " in Redis cmd string
          indexes << "#{options[:key]}:#{str}"
          len += 1
        end
      end
    end
    
    # Also left-anchor the cropped string if "full" is specified
    if options[:full]
      val = values.join('.')
      len = options[:minlength]
      while len <= val.length
        str = val[0,len].gsub(/\s+/, '.')  # can't have " " in Redis cmd string
        indexes << "#{options[:key]}:#{str}"
        len += 1
      end
    end

    # Determine what, if anything, needs to be done.  If the indexes are unchanged,
    # don't make any trips to Redis.  Saves tons of useless network calls.
    old_indexes = text_indexes_for(field)
    new_indexes = indexes - old_indexes
    del_indexes = old_indexes - indexes

    # No change, so skip
    # puts "[#{field}] old=#{old_indexes.inspect} / idx=#{indexes.inspect} / new=#{new_indexes.inspect} / del=#{del_indexes.inspect}"
    next if new_indexes.empty? and del_indexes.empty?

    # Add new indexes
    exec_pipelined_index_cmd(:sadd, new_indexes)

    # Delete indexes no longer used
    exec_pipelined_index_cmd(:srem, del_indexes)
    
    # Replace our reverse map of indexes
    redis.set reverse_index_key(field), indexes.join(';')
  end # fields.each
end