Scott Rutherford

Life on and off the Rails

 

So been using Sphinx with the UltraSphinx plugin and I came across the requirement to use filters to reject records. Unfortunately in the plugin the filters are hardwired to submit the ‘exclude’ parameter as ‘false’ i.e include. Time for a quick hack I think…....

Very easy to fix, just open up the ‘internals.rb’ file in the UltraSphinx plugin or include the gem using ‘rake gems:unpack GEM=ultrasphinx’ (need to have config.gem “ultrasphinx” set in envrinoment.rb) and then find that file.

Ok, so found the file? On line 97 is this loop:

Array(opts['filters']).each do |field, value|          
  ....
 begin
     case value
     when Integer, Float, BigDecimal, NilClass, Array
       # XXX Hack to force floats to be floats
       value = value.to_f if type == 'float'
       # Just bomb the filter in there
       request.filters << Riddle::Client::Filter.new(field, Array(value), false)
     when Range
     ....
end

The ‘Riddle::Client::Filter.new(field, Array(value), false)’ call is the one we need to change (the ‘false’ is the exclude param).

So what I did was to change that loop to:

        Array(opts['filters']).each do |field, value|          

          field = field.to_s          
          type = Fields.instance.types[field]             

          # Special derived attribute
          if field == 'distance' and options['location']
            field, type = '@geodist', 'float'
          end

          raise UsageError, "field #{field.inspect} is invalid" unless type

# ADDED FROM HERE
          exclude = false
          # check for exclude flag
          if value.is_a? Hash            
            exclude = value[:exclude]
            value = value[:value]
          end
# TO HERE

          begin
            case value
              when Integer, Float, BigDecimal, NilClass, Array
                # XXX Hack to force floats to be floats
                value = value.to_f if type == 'float'
                # Just bomb the filter in there

# CHANGE CALL HERE TO PASS THE exclude PARAMETER
                request.filters << Riddle::Client::Filter.new(field, Array(value), exclude)
              when Range
                # Make sure ranges point in the right direction
                min, max = [value.begin, value.end].map {|x| x._to_numeric }
                raise NoMethodError unless min <=> max and max <=> min
                min, max = max, min if min > max
                # XXX Hack to force floats to be floats
                min, max = min.to_f, max.to_f if type == 'float'

# CHANGE CALL HERE TO PASS THE exclude PARAMETER
                request.filters << Riddle::Client::Filter.new(field, min..max, exclude)
              when String
                # XXX Hack to move text filters into the query
                opts['parsed_query'] << " @#{field} #{value}" 
              else
                raise NoMethodError
            end
          rescue NoMethodError => e
            raise UsageError, "Filter value #{value.inspect} for field #{field.inspect} is invalid" 
          end
        end

Now I can do searches like

    @search = Ultrasphinx::Search.new(
      :query => params[:q], 
      :page => page,
      :class_names => ["User"], 
      :filters => {:id => {:value => current_user.id, :exclude => true}}
    )

And the current_user gets excluded, cool.

4 Responses to “Exclude Records With UltraSphinx”

  1. Evan Says:
    Can you submit a GitHub patch for this?
  2. Scott Rutherford Says:
    Hi Evan, yep sure. I'll get on it.
  3. wictor Says:
    I confirm. You can submit a GitHub patch.
  4. Alexwebmaster Says:
    Hello webmaster I would like to share with you a link to your site write me here preonrelt@mail.ru
Leave a Reply

This blog used the Shay theme as a base and is powered by Mephisto