Skip to content

Instantly share code, notes, and snippets.

@alanstevens
Created July 31, 2015 19:36
Show Gist options
  • Save alanstevens/3c2810aa9d0b6884c187 to your computer and use it in GitHub Desktop.
Save alanstevens/3c2810aa9d0b6884c187 to your computer and use it in GitHub Desktop.
def find_associate_common user_ids
# search types
@selected_types = []
@selected_types << 'User'.constantize
# default fields to search
@default_assoc_search_fields = ['last_name_text', 'first_name_text', 'middle_name_text', 'email_text', 'city_region_text', 'country_text']
@search_all_profile = params[:search_all_profile] ||= false
# selected content search type
@selected_search_type = params[:stype].present? ? params[:stype] : 'anyword'
@selected_specialty_search_type = params[:sptype].present? ? params[:sptype] : 'anyspec'
# include professional bio fields
@include_professional_bio = params[:cpbio].present? ? params[:cpbio] : 'false'
# include personal bio fields
@include_personal_bio = params[:cpbio].present? ? params[:cpbio] : 'false'
# set up pagination
cur_page = params[:page] ||= 1
per_page = params[:per_page] ||= 10
# setup the search type and value...
@q = params[:assoc_keywords] ||= nil
qry_empty = @q.nil? || @q.blank? || @q.empty?
# 02-JUL-2012 - downcase the search string. For some reason lucene won't find "Finn" as part of a "standard" query
# but does find "finn".
qry = @q.downcase
qry = qry + "*" if qry.size < 5
if !qry.nil?
qry.strip!
logger.debug "qry(1): #{qry}"
case @selected_search_type
when 'allwords'
qry = "(#{qry.gsub(' ', ' AND ')})"
when 'exact'
qry = "\"#{qry}\""
else
# defaults to any words...
end
end
logger.debug "qry(2): #{qry}"
qry = "( #{qry} ) AND " if !qry.blank?
qry += ' !agent_categories_text:"Alternate Contact" '
# check for specialties
aspec_qry = ""
aspec_op = @selected_specialty_search_type == 'anyspec' ? " OR " : " AND "
qt_param = "standard"
if params[:search_for_specialties] == '1' && params[:agent_specialties].present? && params[:agent_specialties][:specialty_id].present?
params[:agent_specialties][:specialty_id].each do |spec_id|
aspec_qry += "specialty_tags_text:\"#{AgentSpecialtyList[spec_id.to_i].name}\" #{aspec_op} "
# still trying to figure out when / how to use dismax
# it seems that when we're searching against the main "text" (e.g., keywords)
# and are also searching specific fields for content (e.g., specialties) then
# dismax is the way to go. otherwise, leave the qt_param empty so solr / lucene
# use the "standard" search parser
qt_param = "standard" if qt_param == "" && !qry_empty
qry_empty = false
end
aspec_qry.chomp!("#{aspec_op} ").strip!
aspec_qry = " ( #{aspec_qry} )" unless aspec_qry == ""
end
qry += " AND " if qry != "" && aspec_qry != ""
qry += aspec_qry
logger.debug "qry: #{qry}"
logger.debug "qry: #{qry}"
# check for market longitude / latitutde
# run the search with paginated results
@results = Sunspot.search(@selected_types) do
# setup a full text query
fulltext qry
# adjust the solr parameters as needed
adjust_solr_params do |param|
# use the qt param vs the deftype param - not sure why but solr's dismax parser works better with the :qt option
param[:defType] = ''
param[:qt] = qt_param if qt_param != ""
param[:sort] = 'score desc, last_name_text asc'
#param[:qt] = 'dismax'
#param[:qt] = 'standard'
#param[:qf] << " content_text"
end
# setup pagination
paginate :page => cur_page, :per_page => per_page
end unless qry_empty
end
@alanstevens
Copy link
Author

I would like to pass a collection of user ids and have those users filtered from the query results.

I found this: http://stackoverflow.com/questions/11855830/how-to-do-not-in-query-in-solr

which suggests that it can be done using a filter query but I can't find a way to use it here.

@aaronlerch
Copy link

So the answer depends on how the User model is configured for indexing via sunspot. You have to make sure you have the id field included. If it's not included, then it's possible but sunspot doesn't make it very easy. Something like this would make sure it's included, assuming standard integer IDs:

class User < ActiveRecord::Base
  # yada yada yada
  searchable do
    integer :id
    text :last_name, :first_name, :email
    # other fields, etc
  end
end

If you have the id field indexed, and if you pass a collection of user IDs into the method (e.g. user_ids is [1,2,3,4]) then you can update your Sunspot search to the following:

  @results = Sunspot.search(@selected_types) do
      # setup a full text query
      fulltext qry

      without(:id, user_ids)

      # adjust the solr parameters as needed
      adjust_solr_params do |param|
        # use the qt param vs the deftype param - not sure why but solr's dismax parser works better with the :qt option
        param[:defType] = ''
        param[:qt] = qt_param if qt_param != ""
        param[:sort] = 'score desc, last_name_text asc'
        #param[:qt] = 'dismax'
        #param[:qt] = 'standard'
        #param[:qf] << " content_text"
      end

      # setup pagination
      paginate :page => cur_page, :per_page => per_page

    end unless qry_empty

The "without" API does what the stackoverflow post suggests -- it adds the - exclusion to the fq portion of the query. I verified this in my app that uses sunspot and solr, and I was able to exclude things based on ID using this API.

It also might depend on what version of the sunspot gem you are using -- not sure when the without API was added.

IF, like in my project by default, you don't specify the config to index the id, then the id value put into solr is a string like "User 523" -- {class name} {id}. Using the solr admin web interface I was able to issue the right query and it excluded things, but the sunspot ruby API validates field names and didn't like me specifying id when it wasn't in the list defined on the model.

Hope that helps, let me know what you find out.

@aaronlerch
Copy link

You can enable solr debugging output in the sunspot results like this:

@results = Sunspot.search do
  fulltext qry

  adjust_solr_params do |param|
    param['debugQuery'] = 'on'
    # ...
  end
end

And you can access it in the result with a hack like this: @results.try(:instance_variable_get, :@solr_result).try(:[], 'debug')

That will yield a hash with keys like querystring, timing, and explain (I personally love explain as it makes it really helpful to determine why results came back the way they did, which can be a common client/user question.)

You can also see the XML in the results, I believe -- not sure the debug key to use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment