##// END OF EJS Templates
Cache search result ids for faster search pagination (#18631)....
Jean-Philippe Lang -
r13388:717f491f503d
parent child
Show More
@@ -18,8 +18,6
18 class SearchController < ApplicationController
18 class SearchController < ApplicationController
19 before_filter :find_optional_project
19 before_filter :find_optional_project
20
20
21 @@search_cache_store ||= ActiveSupport::Cache.lookup_store :memory_store
22
23 def index
21 def index
24 @question = params[:q] || ""
22 @question = params[:q] || ""
25 @question.strip!
23 @question.strip!
@@ -57,7 +55,7 class SearchController < ApplicationController
57
55
58 fetcher = Redmine::Search::Fetcher.new(
56 fetcher = Redmine::Search::Fetcher.new(
59 @question, User.current, @scope, projects_to_search,
57 @question, User.current, @scope, projects_to_search,
60 :all_words => @all_words, :titles_only => @titles_only
58 :all_words => @all_words, :titles_only => @titles_only, :cache => params[:page].present?
61 )
59 )
62
60
63 if fetcher.tokens.present?
61 if fetcher.tokens.present?
@@ -47,6 +47,14 module RedmineApp
47 # Do not include all helpers
47 # Do not include all helpers
48 config.action_controller.include_all_helpers = false
48 config.action_controller.include_all_helpers = false
49
49
50 # Specific cache for search results, the default file store cache is not
51 # a good option as it could grow fast. A memory store (32MB max) is used
52 # as the default. If you're running multiple server processes, it's
53 # recommended to switch to a shared cache store (eg. mem_cache_store).
54 # See http://guides.rubyonrails.org/caching_with_rails.html#cache-stores
55 # for more options (same options as config.cache_store).
56 config.redmine_search_cache_store = :memory_store
57
50 config.session_store :cookie_store, :key => '_redmine_session'
58 config.session_store :cookie_store, :key => '_redmine_session'
51
59
52 if File.exists?(File.join(File.dirname(__FILE__), 'additional_environment.rb'))
60 if File.exists?(File.join(File.dirname(__FILE__), 'additional_environment.rb'))
@@ -31,6 +31,18 module Redmine
31 search_type = search_type.to_s
31 search_type = search_type.to_s
32 @@available_search_types << search_type unless @@available_search_types.include?(search_type)
32 @@available_search_types << search_type unless @@available_search_types.include?(search_type)
33 end
33 end
34
35 # Returns the cache store for search results
36 # Can be configured with config.redmine_search_cache_store= in config/application.rb
37 def cache_store
38 @@cache_store ||= begin
39 # if config.search_cache_store was not previously set, a no method error would be raised
40 config = Rails.application.config.redmine_search_cache_store rescue :memory_store
41 if config
42 ActiveSupport::Cache.lookup_store config
43 end
44 end
45 end
34 end
46 end
35
47
36 class Fetcher
48 class Fetcher
@@ -41,6 +53,7 module Redmine
41 @question = question.strip
53 @question = question.strip
42 @scope = scope
54 @scope = scope
43 @projects = projects
55 @projects = projects
56 @cache = options.delete(:cache)
44 @options = options
57 @options = options
45
58
46 # extract tokens from the question
59 # extract tokens from the question
@@ -52,10 +65,12 module Redmine
52 @tokens.slice! 5..-1
65 @tokens.slice! 5..-1
53 end
66 end
54
67
68 # Returns the total result count
55 def result_count
69 def result_count
56 result_ids.size
70 result_ids.size
57 end
71 end
58
72
73 # Returns the result count by type
59 def result_count_by_type
74 def result_count_by_type
60 ret = Hash.new {|h,k| h[k] = 0}
75 ret = Hash.new {|h,k| h[k] = 0}
61 result_ids.group_by(&:first).each do |scope, ids|
76 result_ids.group_by(&:first).each do |scope, ids|
@@ -64,6 +79,7 module Redmine
64 ret
79 ret
65 end
80 end
66
81
82 # Returns the results for the given offset and limit
67 def results(offset, limit)
83 def results(offset, limit)
68 result_ids_to_load = result_ids[offset, limit] || []
84 result_ids_to_load = result_ids[offset, limit] || []
69
85
@@ -78,12 +94,31 module Redmine
78 end.compact
94 end.compact
79 end
95 end
80
96
97 # Returns the results ids, sorted by rank
81 def result_ids
98 def result_ids
82 @ranks_and_ids ||= load_result_ids
99 @ranks_and_ids ||= load_result_ids_from_cache
83 end
100 end
84
101
85 private
102 private
86
103
104 def project_ids
105 Array.wrap(@projects).map(&:id)
106 end
107
108 def load_result_ids_from_cache
109 if Redmine::Search.cache_store
110 cache_key = ActiveSupport::Cache.expand_cache_key(
111 [@question, @user.id, @scope.sort, @options, project_ids.sort]
112 )
113
114 Redmine::Search.cache_store.fetch(cache_key, :force => !@cache) do
115 load_result_ids
116 end
117 else
118 load_result_ids
119 end
120 end
121
87 def load_result_ids
122 def load_result_ids
88 ret = []
123 ret = []
89 # get all the results ranks and ids
124 # get all the results ranks and ids
@@ -95,6 +130,7 module Redmine
95 end
130 end
96 # sort results, higher rank and id first
131 # sort results, higher rank and id first
97 ret.sort! {|a,b| b.last <=> a.last}
132 ret.sort! {|a,b| b.last <=> a.last}
133 # only keep ids now that results are sorted
98 ret.map! {|scope, r| [scope, r.last]}
134 ret.map! {|scope, r| [scope, r.last]}
99 ret
135 ret
100 end
136 end
General Comments 0
You need to be logged in to leave comments. Login now