Search code examples
ruby-on-railssolrsunspotsunspot-rails

How to order by multi valued field using sunspot?


I'm a novice to using sunspot/solr and have stumbled upon an issue in a bigger project where it's already being used in a pretty heavy way. What I need to do is find a way to sort/boost the score of a result based on whether it has a value in a multi valued field. To make it more clear lets suppose I have the following setup:

searchable do
  integer user_ids
  integer unread_by_user_ids
end

I want to get a list of all the documents for a given user with the results being ordered by whether the user has read the document already or not. Also I need to mention that I page the results, so ordering them after the solr search is out of the question. I've tried looking at similar questions like the one here: Rails Sunsport/Solr: Ordering on multiple-value field , but since there are no actual answers, I thought I'd try my luck posting a new one. From what I've been reading it seems to me that there is no method to do this and the best course of action would be to do 2 queries, one for the unread items and one for the read items needed to complete a page of results if any are needed and concatenate the results. Still, I wanted to make sure there is no better way of doing this first. Any help/advice is appreciated.


Solution

  • I finally solved this issue by using dynamic fields. Here's what the searchable declaration looks like:

    searchable do
      integer user_ids
      dynamic_boolean :document_read_status do
        user_ids = get_all_user_ids
        unread_user_ids = get_all_unread_user_ids
        user_ids.inject({}) do |hash, user_id|
          hash.merge(:"unread_by_#{user_id}" => unread_user_ids.include?(user_id))
        end
      end
    end
    

    and the actual search looks like this:

    search.build do
      with(:user_ids, user.id)
      dynamic :document_read_status do
        order_by(:"unread_by_#{user.id}", :desc)
      end
    end
    

    In case you're wondering what's with the the interpolated string as the key and why I didn't use the user id as the key directly, that answer can be found here: Indexing and ordering by dynamic field with sunspot

    In case there's something wrong with this approach, any input would be welcomed.