tire elasticsearch kaminari pagination with overriden search in active record model

679 views Asked by At

How to paginate results optimally when using a custom search method in model. I've also pushed ordering of the results to elasticsearch and after fetching from db the results are again sorted based on elasticsearch order.

My model search method looks like this:

def self.search query
    model_objs = Model.tire.search do
        query do
            boolean do
                should { string "field:#{query}", boost: 10}
                should { string "#{query}"}
                //other boolean queries
            end
        end
        sort do
            by "fieldname"
        end
    end
    ids = model_objs.results.map {|x| x.id.to_i}
    model_objs = Model.find(ids)
    ids.collect {|id| model_objs.detect {|x| x.id == id}}
end

And in my controller I just have an action to get the results.

def search
    search_term = params[:search_term].strip
    @model_objs = Model.search search_term
end

I have two goals here, first I want to optimize the number of calls going to elasticsearch or to my database. And I want to paginate the results.

The default pagination mentioned in tire does not work cause I've overridden my search method.

@articles = Article.search params[:q], :page => (params[:page] || 1)

Also using the approach of getting paginated results from elastic search using the from and size would mean I make calls to elasticsearch over and over to fetch results, so I dont want to do something like this.

def self.search query, page_num
    model_objs = Model.tire.search do
        query do
            boolean do
                should { string "field:#{query}", boost: 10}
                should { string "#{query}"}
                //other boolean queries
            end
        end
        sort do
            by "fieldname"
        end
        size 10
        from (page_num - 1) * 10

    end
    ids = model_objs.results.map {|x| x.id.to_i}
    model_objs = Model.find(ids)
    ids.collect {|id| model_objs.detect {|x| x.id == id}}
end

How can I achieve this with limited network calls?

2

There are 2 answers

1
Anil Maurya On

you can pass page parameter to elastic search

model_objs = Model.tire.search({page: page_num}) do
        query do
            boolean do
                should { string "field:#{query}", boost: 10}
                should { string "#{query}"}
                //other boolean queries
            end
        end

no need to pass add 'from'.

0
Srikanth Venugopalan On

Disclaimer: I work with the OP, and this is just to post the solution we took.

Instead of fetching part of the attributes from ES and fetching the rest from the database, the Elastic Search index can be made to hold all the fields that's required for displaying the search results.

This way, query call to elasticsearch is good to display the search result page, without making any extra network calls.

The actual detailed view of the entity can fetch all that is required, but that would be only per entity, which works for us.