@@ -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