Class: Silver::Search

Inherits:
Object
  • Object
show all
Defined in:
lib/silver/search.rb

Overview

Searches an indexed database. What else would it do?

Instance Method Summary collapse

Constructor Details

#initialize(query, key, redis_options = {}, number = 30, offset = 0) ⇒ Search

Takes a query and a redis key from a previous indexing. There is an optional offset that can be used to paginate. It defaults to returning 30 results.

Example, query picture captions for “Barack Obama”:

search = Silver::Search.new("barack obama","picturecaption")


15
16
17
18
19
20
21
22
# File 'lib/silver/search.rb', line 15

def initialize(query,key,redis_options={},number=30,offset=0)
    @query = query
    @key = key
    @number = number
    @offset = offset
    @r = Redis.new(redis_options)
    @r.select 12
end

Instance Method Details

#find_matching_phones(phones) ⇒ Object

Takes an array of metaphones and returns the matching keys in the index. Since we are using double metaphone, it unions the results for the two possible metaphones.i



56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/silver/search.rb', line 56

def find_matching_phones(phones)
    phones.map! do |phone|
        if phone
            "#{@key}:#{phone}"
        else
            nil
        end
    end
    phones = @r.zunionstore "temp", phones.compact
    phones = @r.zrevrange "temp", 0, -1
    phones
end

#morph_wordsObject

Takes the instance’s query, splits it into words, metaphones each word and returns the array of metaphoned words.



47
48
49
50
51
# File 'lib/silver/search.rb', line 47

def morph_words
    words = @query.split(/[^a-zA-Z0-9]/)
    morphed_words = words.map{|word| [word,Text::Metaphone.double_metaphone(word)]}
    morphed_words
end

#perform(&accessor) ⇒ Object

Send a query to be metaphoned, finds the matching ids for the query and then returns the results. Finally it only returns entries that are shared by both words.

Takes a block that takes an id and then queries the database for that row. Again, Silver can be used for services that “row” is a bad metaphor like REST apis. However, it is easy to write.

Ex:

search.perform{|id| Picture.get(id) }


34
35
36
37
38
39
40
41
42
43
# File 'lib/silver/search.rb', line 34

def perform(&accessor)
    morphed_words = morph_words
    morphed_words.map! do |word|
        phones = word[1]
        phones = self.find_matching_phones(phones)
        phones
    end
    results = morphed_words.reduce{|memo,obj| memo & obj}.slice(@offset,@number)
    results.map{|result| accessor.call(result)}
end