diff options
author | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2014-12-12 20:49:31 +0000 |
---|---|---|
committer | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2014-12-12 20:49:31 +0000 |
commit | 2fe806a4a49cc3fcd7c2b7fe3a385d3a46ffbfd5 (patch) | |
tree | 82f8da72bfdc6e68c83cbecf3ffac2b5bcc9738a /app/controllers/search_controller.rb | |
parent | 963719042a12e7833a95396036a662237a7939a0 (diff) | |
download | redmine-2fe806a4a49cc3fcd7c2b7fe3a385d3a46ffbfd5.tar.gz redmine-2fe806a4a49cc3fcd7c2b7fe3a385d3a46ffbfd5.zip |
Rewrites search engine to properly paginate results (#18631).
Instead of counting and retrieving results based on their timestamps, we now load all result ids then load the appropriate results by their ids. This also brings a 2x performance improvement as we search tokens in one of the 2 queries only.
git-svn-id: http://svn.redmine.org/redmine/trunk@13739 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'app/controllers/search_controller.rb')
-rw-r--r-- | app/controllers/search_controller.rb | 56 |
1 files changed, 29 insertions, 27 deletions
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index ec8b4812c..0abac94d3 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -36,9 +36,6 @@ class SearchController < ApplicationController @project end - offset = nil - begin; offset = params[:offset].to_time if params[:offset]; rescue; end - # quick jump to an issue if (m = @question.match(/^#?(\d+)$/)) && (issue = Issue.visible.find_by_id(m[1].to_i)) redirect_to issue_path(issue) @@ -66,34 +63,39 @@ class SearchController < ApplicationController # no more than 5 tokens to search for @tokens.slice! 5..-1 if @tokens.size > 5 - @results = [] - @results_by_type = Hash.new {|h,k| h[k] = 0} - limit = 10 - @scope.each do |s| - r, c = s.singularize.camelcase.constantize.search(@tokens, projects_to_search, + + @result_count = 0 + @result_count_by_type = Hash.new {|h,k| h[k] = 0} + ranks_and_ids = [] + + # get all the results ranks and ids + @scope.each do |scope| + klass = scope.singularize.camelcase.constantize + ranks_and_ids_in_scope = klass.search_result_ranks_and_ids(@tokens, User.current, projects_to_search, :all_words => @all_words, - :titles_only => @titles_only, - :limit => (limit+1), - :offset => offset, - :before => params[:previous].nil?) - @results += r - @results_by_type[s] += c + :titles_only => @titles_only + ) + @result_count_by_type[scope] += ranks_and_ids_in_scope.size + @result_count += ranks_and_ids_in_scope.size + ranks_and_ids += ranks_and_ids_in_scope.map {|r| [scope, r]} end - @results = @results.sort {|a,b| b.event_datetime <=> a.event_datetime} - if params[:previous].nil? - @pagination_previous_date = @results[0].event_datetime if offset && @results[0] - if @results.size > limit - @pagination_next_date = @results[limit-1].event_datetime - @results = @results[0, limit] - end - else - @pagination_next_date = @results[-1].event_datetime if offset && @results[-1] - if @results.size > limit - @pagination_previous_date = @results[-(limit)].event_datetime - @results = @results[-(limit), limit] - end + @result_pages = Paginator.new @result_count, limit, params['page'] + + # sort results, higher rank and id first + ranks_and_ids.sort! {|a,b| b.last <=> a.last } + ranks_and_ids = ranks_and_ids[@result_pages.offset, limit] || [] + + # load the results to display + results_by_scope = Hash.new {|h,k| h[k] = []} + ranks_and_ids.group_by(&:first).each do |scope, rs| + klass = scope.singularize.camelcase.constantize + results_by_scope[scope] += klass.search_results_from_ids(rs.map(&:last).map(&:last)) end + + @results = ranks_and_ids.map do |scope, r| + results_by_scope[scope].detect {|record| record.id == r.last} + end.compact else @question = "" end |