Module: Solrsam::Search::ClassMethods

Defined in:
lib/solrsam/search.rb,
lib/solrsam/search.rb,
lib/solrsam/indexer.rb

Constant Summary collapse

HL_START_TAG =
"<mark>"
HL_END_TAG =
"</mark>"

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#solr_serverObject

Returns the value of attribute solr_server.



6
7
8
# File 'lib/solrsam/search.rb', line 6

def solr_server
  @solr_server
end

Instance Method Details

#class_nameObject



11
12
13
# File 'lib/solrsam/search.rb', line 11

def class_name
    to_s.underscore
end

#destroy_all_index_documents!Object



76
77
78
79
80
# File 'lib/solrsam/indexer.rb', line 76

def destroy_all_index_documents!
  self.perform_solr_command(:write) do |rsolr|
    rsolr.delete_by_query("type:#{class_name}")
  end
end

#destroy_index_document(doc) ⇒ Object



66
67
68
69
70
71
72
73
74
# File 'lib/solrsam/indexer.rb', line 66

def destroy_index_document(doc)
  if doc.respond_to?(:solr_id_value)
    self.perform_solr_command(:write) do |rsolr|
      rsolr.delete_by_query("id:#{doc.solr_id_value}")
    end
  else
    raise "Object must include Solrsam::Search"
  end
end

#embed_highlighting(search_response) ⇒ Object



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
# File 'lib/solrsam/search.rb', line 151

def embed_highlighting(search_response)
    return search_response unless search_response[:highlighting]

    excluded_highlighting_fields = ['id', 'db_id', 'type']

    highlighted_docs = search_response[:docs].map do |doc|
         = search_response[:highlighting][doc['id']]

        .drop_while{|k,v| excluded_highlighting_fields.include?(k) }.each do |k,v|
            new_value = if doc[k].is_a?(Array)
                            matched = v.map{|t| t.gsub(HL_START_TAG,"").gsub(HL_END_TAG,"") }
                            v.concat(doc[k].drop_while{|text| matched.include?(text) })
                        else
                            v
                        end
            doc[k] = new_value
        end if 

        doc
    end

    search_response[:docs] = highlighted_docs

    search_response[:docs].extend RSolr::Pagination::PaginatedDocSet

    search_response
end

#index(doc) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/solrsam/indexer.rb', line 46

def index(doc)
  solr_docs = []
  if doc.respond_to?(:map)
    solr_docs = doc.map{|document| document.indexed_fields }
  elsif doc.respond_to?(:as_solr_document) && doc.respond_to?(:indexed_fields)
    solr_docs << doc.indexed_fields
  else
    raise "Indexed document must define a as_solr_document method."
  end
  self.perform_solr_command(:write) do |rsolr|
    rsolr.add(solr_docs)
  end
end

#index_allObject



60
61
62
63
64
# File 'lib/solrsam/indexer.rb', line 60

def index_all
  self.find_in_batches(:batch_size => 100) do |group|
    self.index(group)
  end
end

#key_value_query(key, value) ⇒ Object



104
105
106
107
108
109
110
111
112
113
# File 'lib/solrsam/search.rb', line 104

def key_value_query(key, value)
    if value.starts_with?("[")
        "#{key}:#{value}"
    elsif value.starts_with?("(")
        # we don't want to escape double quotes
        "#{key}:" + value
    else
        "#{key}:\"#{value}\""
    end
end

#map_facet_array_to_facet_hash(facet_collection) ⇒ Object

solr facet_fields comes in tuple array format []



143
144
145
146
147
148
149
# File 'lib/solrsam/search.rb', line 143

def map_facet_array_to_facet_hash(facet_collection)
    if facet_collection.is_a?(Array)
        facet_collection.each_slice(2).reduce({}){|acc, tuple| acc[tuple[0]] = tuple[1]; acc}
    else
        facet_collection
    end
end

#parse_element_in_fq(element) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/solrsam/search.rb', line 88

def parse_element_in_fq(element)
    if element.is_a?(String)
        element
    elsif element.is_a?(Hash)
        element.map do |k,values|
            if values.is_a?(String)
                key_value_query(k,values)
            else
                values.map{|value| key_value_query(k,value) }
            end
        end
    else
        raise "each fq parameter must be a string or hash"
    end
end

#parse_facet_counts(facet_counts) ⇒ Object



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
# File 'lib/solrsam/search.rb', line 115

def parse_facet_counts(facet_counts)
    return {} unless facet_counts

    if facet_counts['facet_fields']
        facet_counts['facet_fields'] = facet_counts['facet_fields'].reduce({}) do |acc, facet_collection|
            acc[facet_collection[0]] = map_facet_array_to_facet_hash(facet_collection[1])
            acc
        end
    end

    if facet_counts['facet_queries']
        facet_counts['facet_queries'] = facet_counts['facet_queries'].group_by{|k,v| k.split(":").first}.reduce({}) do |acc, facet_collection|
            facet_name = facet_collection[0]
            values = facet_collection[1]

            acc[facet_name] = values.reduce({}) do |inner_acc, tuple|
                range = tuple[0].split(":")[1]
                inner_acc[range] = tuple[1]
                inner_acc
            end
            acc
        end
    end

    facet_counts
end

#parse_fq(fq) ⇒ Object



77
78
79
80
81
82
83
84
85
86
# File 'lib/solrsam/search.rb', line 77

def parse_fq(fq)
    return [] if fq.nil?
    if fq.is_a?(Hash)
        fq.map{|k,v| parse_element_in_fq({k => v})}.flatten
    elsif fq.is_a?(Array)
        fq.map{|ele| parse_element_in_fq(ele)}.flatten
    else
        raise "fq must be a hash or array"
    end
end

#parse_params_for_solr(search_params = {}) ⇒ Object



43
44
45
46
47
48
49
50
51
52
# File 'lib/solrsam/search.rb', line 43

def parse_params_for_solr(search_params={})
    solr_params = { :echoParams => 'explicit',
        :q => "*:*",
        :facet => "on",
        :'facet.mincount' => 1}.merge(search_params)

    solr_params[:hl] = true unless search_params[:'hl.fl'].blank?
    solr_params[:fq] =  parse_fq(search_params[:fq]) + ( search_params[:untyped] ? [] : ["type:#{class_name}"])
    solr_params
end

#parse_solr_response(solr_response) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/solrsam/search.rb', line 54

def parse_solr_response(solr_response)
    docs = solr_response['response']['docs']
    parsed_facet_counts = parse_facet_counts(solr_response['facet_counts'])
    highlighting = solr_response['highlighting']
    suggestions = solr_response['spellcheck']['suggestions'] rescue {}

     = {
        :total_count => solr_response['response']['numFound'],
        :start => solr_response['response']['start'],
        :rows => solr_response['responseHeader']['params']['rows'],
        :time => solr_response['responseHeader']['QTime'],
        :status => solr_response['responseHeader']['status'],
        :sort => solr_response['responseHeader']['params']['sort'],
        :debug => solr_response['debug']
    }
    response = {:docs => docs, :metadata =>  ,
        :facet_counts => parsed_facet_counts, :highlighting => highlighting}
    response[:stats] = solr_response['stats'] if solr_response['stats']
    response[:suggestions] = suggestions

    embed_highlighting(response)
end

#perform_solr_command(method = :read) {|solr(method)| ... } ⇒ Object

Yields:



20
21
22
23
# File 'lib/solrsam/search.rb', line 20

def perform_solr_command(method = :read)
    yield(solr(method))
    solr(method).commit
end

#search(search_params = {}) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/solrsam/search.rb', line 25

def search(search_params={})
    start = search_params[:start] || 0
    rows = search_params[:rows] || 20

    solr_params = parse_params_for_solr(search_params)

    begin
        solr_response = solr.select :data => solr_params, :method => :post
        parse_solr_response(solr_response)
    rescue RSolr::Error::Http => e
        {:docs => [], 
            :metadata => 
        {:error => {:http_status_code => e.response[:status], 
            :http_message_status => RSolr::Error::Http::STATUS_CODES[e.response[:status].to_i],
            :full_message => e.message}}}
    end
end

#solr(method = :read) ⇒ Object



15
16
17
18
# File 'lib/solrsam/search.rb', line 15

def solr(method = :read)
    @solr_server ||= :default
    Solrsam::Config.instance.rsolr_object(@solr_server, method)
end