Class: Supernova::SolrCriteria

Inherits:
Criteria
  • Object
show all
Defined in:
lib/supernova/solr_criteria.rb

Constant Summary

Constants inherited from Criteria

Criteria::DEFAULT_PER_PAGE, Criteria::FIRST_PAGE

Instance Attribute Summary

Attributes inherited from Criteria

#clazz, #filters, #results, #search_options

Instance Method Summary collapse

Methods inherited from Criteria

#attribute_mapping, #clone, #conditions, #current_page, #except, #facet_fields, #facet_queries, #for_classes, #group_by, #immutable!, #immutable?, immutable_by_default!, immutable_by_default?, #implement_in_subclass, #initialize, #limit, #merge, #merge_filters, #merge_filters_array, #merge_filters_or_search_options, #merge_search_options, method_missing, #method_missing, mutable_by_default!, #named_scope_class, #named_scope_defined?, #near, #normalize_coordinates, #options, #order, #paginate, #pagination_attribute_when_greater_zero, #per_page, #populate, #populated?, #read_first_attribute, #rows, #search, #select, select, #self_or_clone, #start, #to_a, #to_parameters, #where, #with, #within, #without

Constructor Details

This class inherits a constructor from Supernova::Criteria

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Supernova::Criteria

Instance Method Details

#build_doc(hash) ⇒ Object



133
134
135
136
137
138
139
# File 'lib/supernova/solr_criteria.rb', line 133

def build_doc(hash)
  if hash["type"].respond_to?(:constantize)
    Supernova.build_ar_like_record(hash["type"].constantize, convert_doc_attributes(hash), hash)
  else
    hash
  end
end

#build_doc_method(method) ⇒ Object



129
130
131
# File 'lib/supernova/solr_criteria.rb', line 129

def build_doc_method(method)
  merge_search_options :build_doc_method, method
end

#build_docs(docs) ⇒ Object



123
124
125
126
127
# File 'lib/supernova/solr_criteria.rb', line 123

def build_docs(docs)
  docs.map do |hash|
    self.search_options[:build_doc_method] ? self.search_options[:build_doc_method].call(hash) : build_doc(hash)
  end
end

#convert_doc_attributes(hash) ⇒ Object

called in build doc, all hashes have strings as keys!!!



142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/supernova/solr_criteria.rb', line 142

def convert_doc_attributes(hash)
  converted_hash = hash.inject({}) do |ret, (key, value)|
    if key == "id"
      ret["id"] = value.to_s.split("/").last
    else
      ret[reverse_lookup_solr_field(key).to_s] = value
    end
    ret
  end
  self.select_fields.each do |select_field|
    converted_hash[select_field.to_s] = nil if !converted_hash.has_key?(select_field.to_s)
  end
  converted_hash
end

#convert_search_order(order) ⇒ Object



51
52
53
54
55
56
57
58
59
# File 'lib/supernova/solr_criteria.rb', line 51

def convert_search_order(order)
  order.split(/\s*,\s*/).map do |chunk|
    if chunk.match(/(.*?) (asc|desc)/i)
      "#{solr_field_from_field($1)} #{$2}"
    else
      chunk
    end
  end.join(",")
end

#executeObject



192
193
194
195
196
197
198
199
200
# File 'lib/supernova/solr_criteria.rb', line 192

def execute
  response = execute_raw
  collection = Supernova::Collection.new(current_page, per_page == 0 ? 1 : per_page, response["response"]["numFound"])
  collection.original_criteria = self.clone
  collection.original_response = response
  collection.facets = hashify_facets_from_response(response)
  collection.replace(build_docs(response["response"]["docs"]))
  collection
end

#execute_rawObject



188
189
190
# File 'lib/supernova/solr_criteria.rb', line 188

def execute_raw
  JSON.parse(Typhoeus::Request.post(Supernova::Solr.select_url, :params => to_params.merge(:wt => "json")).body)
end

#format(the_format) ⇒ Object



165
166
167
# File 'lib/supernova/solr_criteria.rb', line 165

def format(the_format)
  merge_search_options(:wt, the_format)
end

#fq_filter_for_key_and_value(key, value) ⇒ Object



105
106
107
108
109
110
111
112
113
# File 'lib/supernova/solr_criteria.rb', line 105

def fq_filter_for_key_and_value(key, value)
  if value.nil?
    "!#{key}:[* TO *]"
  elsif value.is_a?(Range)
    "#{key}:[#{value_for_fq_filter(value.first)} TO #{value_for_fq_filter(value.last)}]"
  else
    "#{key}:#{value_for_fq_filter(value)}"
  end
end

#fq_from_with(with) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/supernova/solr_criteria.rb', line 74

def fq_from_with(with)
  if with.blank?
    []
  else
    with.map do |with_part|
      if with_part.is_a?(Hash)
        with_part.map do |key_or_condition, values|
          values_from_key_or_condition_and_values(key_or_condition, values).map do |value|
            if key_or_condition.respond_to?(:solr_filter_for)
              key_or_condition.key = solr_field_from_field(key_or_condition.key)
              key_or_condition.solr_filter_for(value)
            else
              fq_filter_for_key_and_value(solr_field_from_field(key_or_condition), value)
            end
          end
        end
      else
        with_part
      end
    end.flatten
  end
end

#hashify_facets_from_response(response) ⇒ Object



179
180
181
182
183
184
185
186
# File 'lib/supernova/solr_criteria.rb', line 179

def hashify_facets_from_response(response)
  if response["facet_counts"] && response["facet_counts"]["facet_fields"]
    response["facet_counts"]["facet_fields"].inject({}) do |hash, (key, values)|
      hash[reverse_lookup_solr_field(key)] = Hash[*values]
      hash
    end
  end
end

#idsObject



206
207
208
209
210
# File 'lib/supernova/solr_criteria.rb', line 206

def ids
  only_ids.execute.tap do |col|
    col.replace(col.map { |h| h["id"].split("/").last.to_i })
  end
end

#include_facets?Boolean

Returns:

  • (Boolean)


47
48
49
# File 'lib/supernova/solr_criteria.rb', line 47

def include_facets?
  self.search_options[:facets] || self.search_options[:facet_queries]
end

#only_idsObject



202
203
204
# File 'lib/supernova/solr_criteria.rb', line 202

def only_ids
  self_or_clone.except(:select).select("id")
end

#reverse_lookup_solr_field(solr_field) ⇒ Object



65
66
67
68
69
70
71
72
# File 'lib/supernova/solr_criteria.rb', line 65

def reverse_lookup_solr_field(solr_field)
  if search_options[:attribute_mapping]
    search_options[:attribute_mapping].each do |field, options|
      return field if solr_field.to_s == solr_field_from_field(field)
    end
  end
  solr_field
end

#select_fieldsObject



157
158
159
160
161
162
163
# File 'lib/supernova/solr_criteria.rb', line 157

def select_fields
  if self.search_options[:select].present?
    self.search_options[:select]
  else
    self.search_options[:named_scope_class].respond_to?(:select_fields) ? self.search_options[:named_scope_class].select_fields : []
  end
end

#set_first_responding_attribute(doc, solr_key, value) ⇒ Object



169
170
171
172
173
174
175
176
177
# File 'lib/supernova/solr_criteria.rb', line 169

def set_first_responding_attribute(doc, solr_key, value)
  [reverse_lookup_solr_field(solr_key), solr_key].each do |key|
    meth = :"#{key}="
    if doc.respond_to?(meth)
      doc.send(meth, value)
      return
    end
  end
end

#solr_field_from_field(field) ⇒ Object



61
62
63
# File 'lib/supernova/solr_criteria.rb', line 61

def solr_field_from_field(field)
  Supernova::SolrIndexer.solr_field_for_field_name_and_mapping(field, search_options[:attribute_mapping])
end

#to_paramsObject

move this into separate methods (test each separatly)



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/supernova/solr_criteria.rb', line 5

def to_params
  solr_options = { :fq => [], :q => "*:*" }
  solr_options[:wt] = search_options[:wt] if search_options[:wt]
  solr_options[:fq] += fq_from_with(self.search_options[:with])
  if self.filters[:without]
   self.filters[:without].each do |field, values| 
     solr_options[:fq] += values.map { |value| "!#{solr_field_from_field(field)}:#{value}" }
   end
  end
  solr_options[:sort] = convert_search_order(self.search_options[:order].join(", ")) if self.search_options[:order]
  if self.search_options[:search].is_a?(Array)
    solr_options[:q] = self.search_options[:search].map { |query| "(#{query})" }.join(" AND ")
  end
  
  if self.search_options[:geo_center] && self.search_options[:geo_distance]
    solr_options[:pt] = "#{self.search_options[:geo_center][:lat]},#{self.search_options[:geo_center][:lng]}"
    solr_options[:d] = self.search_options[:geo_distance].to_f / Supernova::KM_TO_METER
    solr_options[:sfield] = solr_field_from_field(:location)
    solr_options[:fq] << "{!geofilt}"
  end
  if self.search_options[:select]
    self.search_options[:select] << "id" if !self.search_options[:select].map(&:to_s).include?("id")
    solr_options[:fl] = self.search_options[:select].compact.map { |field| solr_field_from_field(field) }.join(",") 
  end
  solr_options[:fq] << "type:#{self.clazz}" if self.clazz
  
  solr_options[:facet] = true if include_facets?
  if self.search_options[:facets]
    solr_options["facet.field"] = self.search_options[:facets].compact.map { |field| solr_field_from_field(field) }
  end
  
  if self.search_options[:facet_queries]
    solr_options["facet.query"] = self.search_options[:facet_queries].values
  end
  
  if self.search_options[:pagination] || search_options[:rows] || search_options[:start]
    solr_options[:rows] = self.search_options[:rows] || per_page
    solr_options[:start] = search_options[:start] || ((current_page - 1) * solr_options[:rows])
  end
  solr_options
end

#value_for_fq_filter(value) ⇒ Object



115
116
117
118
119
120
121
# File 'lib/supernova/solr_criteria.rb', line 115

def value_for_fq_filter(value)
  if value.is_a?(Date)
    Time.utc(value.year, value.month, value.day).iso8601
  else
    value
  end
end

#values_from_key_or_condition_and_values(key_or_condition, values) ⇒ Object



97
98
99
100
101
102
103
# File 'lib/supernova/solr_criteria.rb', line 97

def values_from_key_or_condition_and_values(key_or_condition, values)
  if key_or_condition.is_a?(Supernova::Condition) && values.is_a?(Array) && [:nin, :in].include?(key_or_condition.type)
    [values]
  else
    [values].flatten
  end
end