cirandas.net

ref: master

plugins/solr/lib/solr_plugin/base.rb


  1
  2
  3
  4
  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
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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
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
201
202
203
# FIXME: module not being loaded
require 'solr_plugin'

class SolrPlugin::Base < Noosfero::Plugin

  def stylesheet?
    true
  end

  def js_files
    ['solr'].map{ |j| "javascripts/#{j}" }
  end

  def catalog_find_by_contents asset, scope, query, paginate_options={}, options={}
  	klass = Product

  	# Search for products -> considers the query and the filters:
    params[:facet] = {}
    params[:facet][:solr_f_category] = params[:category] if params[:category].present?
    params[:facet][:solr_f_qualifier] = params[:qualifier] if params[:qualifier].present?
    solr_options = build_solr_options asset, klass, scope, nil
    solr_options[:all_facets] = false

    order = params[:order]
    order = if order.blank? then :relevance else order.to_sym end
    if sort = SortOptions[:catalog][order] rescue nil
      solr_options.merge! (if query.blank? and sort[:empty_solr_opts] then sort[:empty_solr_opts] else sort[:solr_opts] end)
    end
    result = scope.find_by_contents query, paginate_options, solr_options

    # Preparing the filters -> they must always contain all filters for the specific query:
    solr_options = build_solr_options asset, klass, scope, nil, ignore_filters: true
    solr_options[:all_facets] = false
    query = "" if result[:results].total_entries == 0
    result_facets = scope.find_by_contents query, paginate_options, solr_options
    facets = result_facets[:facets]['facet_fields'] || {}

    result[:categories] = facets['solr_f_category_facet'].to_a.map{ |name,count| ["#{name} (#{count})", name] }
    result[:categories].sort!{ |a,b| a[0] <=> b[0] }
    result[:qualifiers] = facets['solr_f_qualifier_facet'].to_a
    result[:qualifiers] = Product.solr_f_qualifier_proc nil, result[:qualifiers]
    result[:qualifiers].map!{ |id, name, count| ["#{name} (#{count})", id] }
    result[:qualifiers].sort!{ |a,b| a[0] <=> b[0] }

    result
  end

  def find_by_contents asset, scope, query, paginate_options={}, options={}
  	# The query in the catalog top bar is too specific and therefore must be treated differently
    return catalog_find_by_contents asset, scope, query, paginate_options, options if asset == :catalog

    category = options.delete :category
    filter = options.delete(:filter).to_s.to_sym
  	klass = asset_class asset

  	solr_options = build_solr_options asset, klass, scope, category
    solr_options.merge! sort_options asset, klass, filter
    solr_options.merge! options
    # We don't yet use the option to filter by template
    solr_options.delete :template_id

    scope.find_by_contents query, paginate_options, solr_options
  rescue Exception => e
    # solr seaches depends on a constant translation of named scopes SQL's into solr filtered fields
    # so while we can't keep up it core changes, report the error and use default like search
    if Rails.env.production?
      ExceptionNotifier.notify_exception e,
        env: context.request.env, data: {message: "Solr search failed"}
      super
    else
      raise
    end
  end

  def autocomplete asset, scope, query, paginate_options={}, options={}
    solr_options = {}
    solr_options.merge! paginate_options

    case asset
    when :catalog
      klass = Product
      solr_options[:query_fields] = %w[solr_ac_name^100 solr_ac_category^90 solr_ac_supplier^80]
      solr_options[:highlight] = {fields: 'name'}
      solr_options[:filter_queries] = scopes_to_solr_options scope, klass, options
    end
    solr_options[:default_field] = 'ngramText'

    result = {results: scope.find_by_solr(query, solr_options).results}
    result
  end

  def search_order asset
    case asset
    when :catalog
      {
        select_options: SortOptions[:catalog].map do |key, options|
          option = options[:option]
          [_(option[0]), option[1]]
        end,
      }
    end
  end

  def search_pre_contents
    lambda do
      render 'solr_plugin/search/search_pre_contents'
    end
  end

  def search_post_contents
    lambda do
      render 'solr_plugin/search/search_post_contents'
    end
  end

  protected

  include SolrPlugin::SearchHelper

  def build_solr_options asset, klass, scope, category, options = {}
    solr_options = {}

    selected_facets = if options[:ignore_filters] then {} else params[:facet] end
    if klass.respond_to? :solr_facets
      solr_options.merge! klass.solr_facets_find_options selected_facets
      solr_options[:all_facets] = true
    end

    solr_options[:filter_queries] ||= []
    solr_options[:filter_queries] += solr_filters_queries asset, environment
    solr_options[:filter_queries] << klass.solr_facet_category_query.call(category) if category
    solr_options[:filter_queries] += scopes_to_solr_options scope, klass, options

    solr_options[:boost_functions] ||= []
    params[:order_by] = nil if params[:order_by] == 'none'
    if params[:order_by]
      order = SortOptions[asset][params[:order_by].to_sym]
      raise "Unknown order by" if order.nil?
      order[:solr_opts].each do |opt, value|
        solr_options[opt] = value.is_a?(Proc) ? instance_eval(&value) : value
      end
    end

    solr_options
  end

  def scopes_to_solr_options scope, klass = nil, options = {}
    filter_queries = []
    klass ||= scope.base_class
    solr_fields = klass.configuration[:solr_fields].keys rescue []
    scopes_applied = scope.scopes_applied.dup rescue [] #rescue association and class direct filtering

    scope.scope_attributes.each do |attr, value|
      next if attr.to_sym == :type

      raise "#{klass.name}: non-indexed attribute '#{attr}' speficied in scope_attributes" unless solr_fields.include? attr.to_sym

      # if the filter is present here, then prefer it
      scopes_applied.reject!{ |name| name == attr.to_sym }

      filter_queries << "#{attr}:#{value}"
    end

    scopes_applied.each do |name|
      #next if name.to_s == options[:filter].to_s
      next if name.to_s == context.instance_variable_get(:@order)
      # not yet supported as it involves ordering
      next if name.to_s.in? klass::SEARCH_FILTERS[:order]

      has_value = name === Hash
      if has_value
        name, args = name.keys.first, name.values.first
        value = args.first
      end

      related_field = nil
      related_field = name if solr_fields.include? name
      related_field = "solr_#{name}" if solr_fields.include? :"solr_#{name}"

      if has_value
        if related_field
          filter_queries << "#{related_field}:#{value}"
        else
          filter_queries << klass.send("solr_filter_#{name}", *args)
        end
      else
        raise "#{klass.name}: undeclared solr field for scope '#{name}'" if related_field.nil?
        if related_field
          filter_queries << "#{related_field}:true"
        end
      end
    end

    filter_queries
  end

  def sort_options asset, klass, filter
    options = SolrPlugin::SearchHelper::SortOptions[asset]
    options[filter][:solr_opts] || {} rescue {}
  end

end