Search code examples
ruby-on-railselasticsearchsearchkick

Sort Elasticsearch results by integer value via Searchkick


I'm working on a Rails application that uses Searchkick as an interface to Elasticsearch. Site search is working just fine, but I'm running into an unexpected issue on a page where I'm attempting to retrieve the most recent recoreds from Searchkick across a couple different models. The goal is a reverse chronological list of this recent activity, with the two object types intermingled.

I'm using the following code:

models = [ Post, Project ]
includes = { 
    Post    => [ :account => [ :profile ] ], 
    Project => [ :account => [ :profile ] ],
}
@results = Searchkick.search('*', 
    :models => models,
    :model_includes => includes,
    :order => { :id => :desc },
    :limit => 27,
)

For the purposes of getting the backend working, the page in development is currently just displaying the title, record type (class name), and ID, like this:

<%= "#{result.title} (#{result.class} #{result.id})" %>

Which will output this:

Greetings from Tennessee! (Post 999)

This generally seems to be working fine, except that ES is returning the results sorted by ID as strings, not integers. I tested by setting the results limit to 1000 and found that with tables containing ~7,000 records, 999 is considered highest, while 6905 comes after 691 in the list.

Looking through the Elasticsearch documentation, I do see mention of sorting numeric fields but I'm unable to figure out how to translate that to the Seachkick DSL. It this possible and supported?

I'm running Searchkick 4.4 and Elasticsearch 7.


Solution

  • Because Elasticsearch stores IDs as strings rather than integers, I solved this problem by adding a new obj_id field in ES and ordering results based on that.

    In my Post and Project models:

    def search_data
        {
            :obj_id => id,
            :title => title,
            :content => ActionController::Base.helpers.strip_tags(content),
        }
    end
    

    And in the controller I changed the order value to:

    :order => { :obj_id => :desc }
    

    The records are sorting correctly now.