Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(133)

Side by Side Diff: ui/app_list/search/mixer.cc

Issue 2701123002: AppList Performance Optimization 2 (Closed)
Patch Set: Cache the tokenized name Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/app_list/search/mixer.h" 5 #include "ui/app_list/search/mixer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <map> 8 #include <map>
9 #include <set> 9 #include <set>
10 #include <string> 10 #include <string>
(...skipping 10 matching lines...) Expand all
21 void UpdateResult(const SearchResult& source, SearchResult* target) { 21 void UpdateResult(const SearchResult& source, SearchResult* target) {
22 target->set_display_type(source.display_type()); 22 target->set_display_type(source.display_type());
23 target->set_title(source.title()); 23 target->set_title(source.title());
24 target->set_title_tags(source.title_tags()); 24 target->set_title_tags(source.title_tags());
25 target->set_details(source.details()); 25 target->set_details(source.details());
26 target->set_details_tags(source.details_tags()); 26 target->set_details_tags(source.details_tags());
27 } 27 }
28 28
29 } // namespace 29 } // namespace
30 30
31 Mixer::SortData::SortData() : result(NULL), score(0.0) { 31 Mixer::SortData::SortData() : result(nullptr), score(0.0) {}
32 }
33 32
34 Mixer::SortData::SortData(SearchResult* result, double score) 33 Mixer::SortData::SortData(SearchResult* result, double score)
35 : result(result), score(score) { 34 : result(result), score(score) {
36 } 35 }
37 36
38 bool Mixer::SortData::operator<(const SortData& other) const { 37 bool Mixer::SortData::operator<(const SortData& other) const {
39 // This data precedes (less than) |other| if it has higher score. 38 // This data precedes (less than) |other| if it has higher score.
40 return score > other.score; 39 return score > other.score;
41 } 40 }
42 41
43 // Used to group relevant providers together for mixing their results. 42 // Used to group relevant providers together for mixing their results.
44 class Mixer::Group { 43 class Mixer::Group {
45 public: 44 public:
46 Group(size_t max_results, double multiplier) 45 Group(size_t max_results, double multiplier)
47 : max_results_(max_results), multiplier_(multiplier) {} 46 : max_results_(max_results), multiplier_(multiplier) {}
48 ~Group() {} 47 ~Group() {}
49 48
50 void AddProvider(SearchProvider* provider) { providers_.push_back(provider); } 49 void AddProvider(SearchProvider* provider) {
50 providers_.emplace_back(provider);
51 }
51 52
52 void FetchResults(bool is_voice_query, const KnownResults& known_results) { 53 void FetchResults(bool is_voice_query, const KnownResults& known_results) {
53 results_.clear(); 54 results_.clear();
54 55
55 for (const SearchProvider* provider : providers_) { 56 for (const SearchProvider* provider : providers_) {
56 for (SearchResult* result : provider->results()) { 57 for (const auto& result : provider->results()) {
57 DCHECK(!result->id().empty()); 58 DCHECK(!result->id().empty());
58 59
59 // We cannot rely on providers to give relevance scores in the range 60 // We cannot rely on providers to give relevance scores in the range
60 // [0.0, 1.0] (e.g., PeopleProvider directly gives values from the 61 // [0.0, 1.0] (e.g., PeopleProvider directly gives values from the
61 // Google+ API). Clamp to that range. 62 // Google+ API). Clamp to that range.
62 double relevance = std::min(std::max(result->relevance(), 0.0), 1.0); 63 const double relevance =
63 64 std::min(std::max(result->relevance(), 0.0), 1.0);
64 double multiplier = multiplier_;
65 double boost = 0.0; 65 double boost = 0.0;
66 66
67 // Recommendations should not be affected by query-to-launch correlation 67 // Recommendations should not be affected by query-to-launch correlation
68 // from KnownResults as it causes recommendations to become dominated by 68 // from KnownResults as it causes recommendations to become dominated by
69 // previously clicked results. This happens because the recommendation 69 // previously clicked results. This happens because the recommendation
70 // query is the empty string and the clicked results get forever 70 // query is the empty string and the clicked results get forever
71 // boosted. 71 // boosted.
72 if (result->display_type() != SearchResult::DISPLAY_RECOMMENDATION) { 72 if (result->display_type() != SearchResult::DISPLAY_RECOMMENDATION) {
73 KnownResults::const_iterator known_it = 73 KnownResults::const_iterator known_it =
74 known_results.find(result->id()); 74 known_results.find(result->id());
(...skipping 15 matching lines...) Expand all
90 NOTREACHED() << "Unknown result in KnownResults?"; 90 NOTREACHED() << "Unknown result in KnownResults?";
91 break; 91 break;
92 } 92 }
93 } 93 }
94 94
95 // If this is a voice query, voice results receive a massive boost. 95 // If this is a voice query, voice results receive a massive boost.
96 if (is_voice_query && result->voice_result()) 96 if (is_voice_query && result->voice_result())
97 boost += 4.0; 97 boost += 4.0;
98 } 98 }
99 99
100 results_.push_back(SortData(result, relevance * multiplier + boost)); 100 results_.emplace_back(result.get(), relevance * multiplier_ + boost);
101 } 101 }
102 } 102 }
103 103
104 std::sort(results_.begin(), results_.end()); 104 std::sort(results_.begin(), results_.end());
105 } 105 }
106 106
107 const SortedResults& results() const { return results_; } 107 const SortedResults& results() const { return results_; }
108 108
109 size_t max_results() const { return max_results_; } 109 size_t max_results() const { return max_results_; }
110 110
(...skipping 27 matching lines...) Expand all
138 const KnownResults& known_results, 138 const KnownResults& known_results,
139 size_t num_max_results) { 139 size_t num_max_results) {
140 FetchResults(is_voice_query, known_results); 140 FetchResults(is_voice_query, known_results);
141 141
142 SortedResults results; 142 SortedResults results;
143 results.reserve(num_max_results); 143 results.reserve(num_max_results);
144 144
145 // Add results from each group. Limit to the maximum number of results in each 145 // Add results from each group. Limit to the maximum number of results in each
146 // group. 146 // group.
147 for (const Group* group : groups_) { 147 for (const Group* group : groups_) {
148 size_t num_results = 148 const size_t num_results =
149 std::min(group->results().size(), group->max_results()); 149 std::min(group->results().size(), group->max_results());
150 results.insert(results.end(), group->results().begin(), 150 results.insert(results.end(), group->results().begin(),
151 group->results().begin() + num_results); 151 group->results().begin() + num_results);
152 } 152 }
153 // Remove results with duplicate IDs before sorting. If two providers give a 153 // Remove results with duplicate IDs before sorting. If two providers give a
154 // result with the same ID, the result from the provider with the *lower group 154 // result with the same ID, the result from the provider with the *lower group
155 // number* will be kept (e.g., an app result takes priority over a web store 155 // number* will be kept (e.g., an app result takes priority over a web store
156 // result with the same ID). 156 // result with the same ID).
157 RemoveDuplicates(&results); 157 RemoveDuplicates(&results);
158 std::sort(results.begin(), results.end()); 158 std::sort(results.begin(), results.end());
159 159
160 if (results.size() < num_max_results) { 160 const size_t original_size = results.size();
161 size_t original_size = results.size(); 161 if (original_size < num_max_results) {
162 // We didn't get enough results. Insert all the results again, and this 162 // We didn't get enough results. Insert all the results again, and this
163 // time, do not limit the maximum number of results from each group. (This 163 // time, do not limit the maximum number of results from each group. (This
164 // will result in duplicates, which will be removed by RemoveDuplicates.) 164 // will result in duplicates, which will be removed by RemoveDuplicates.)
165 for (const Group* group : groups_) { 165 for (const Group* group : groups_) {
166 results.insert(results.end(), group->results().begin(), 166 results.insert(results.end(), group->results().begin(),
167 group->results().end()); 167 group->results().end());
168 } 168 }
169 RemoveDuplicates(&results); 169 RemoveDuplicates(&results);
170 // Sort just the newly added results. This ensures that, for example, if 170 // Sort just the newly added results. This ensures that, for example, if
171 // there are 6 Omnibox results (score = 0.8) and 1 People result (score = 171 // there are 6 Omnibox results (score = 0.8) and 1 People result (score =
(...skipping 13 matching lines...) Expand all
185 // to item. 185 // to item.
186 // 2. Use the order of items in |new_results| to build an ordered list. If the 186 // 2. Use the order of items in |new_results| to build an ordered list. If the
187 // result IDs exist in the map, update and use the item in the map and delete 187 // result IDs exist in the map, update and use the item in the map and delete
188 // it from the map afterwards. Otherwise, clone new items from |new_results|. 188 // it from the map afterwards. Otherwise, clone new items from |new_results|.
189 // 3. Delete the objects remaining in the map as they are unused. 189 // 3. Delete the objects remaining in the map as they are unused.
190 190
191 // We have to erase all results at once so that observers are notified with 191 // We have to erase all results at once so that observers are notified with
192 // meaningful indexes. 192 // meaningful indexes.
193 auto current_results = ui_results->RemoveAll(); 193 auto current_results = ui_results->RemoveAll();
194 std::map<std::string, std::unique_ptr<SearchResult>> ui_results_map; 194 std::map<std::string, std::unique_ptr<SearchResult>> ui_results_map;
195 for (std::unique_ptr<SearchResult>& ui_result : current_results) 195 for (auto& ui_result : current_results)
196 ui_results_map[ui_result->id()] = std::move(ui_result); 196 ui_results_map[ui_result->id()] = std::move(ui_result);
197 197
198 // Add items back to |ui_results| in the order of |new_results|. 198 // Add items back to |ui_results| in the order of |new_results|.
199 for (const SortData& sort_data : new_results) { 199 for (const SortData& sort_data : new_results) {
200 const SearchResult& new_result = *sort_data.result; 200 const SearchResult& new_result = *sort_data.result;
201 auto ui_result_it = ui_results_map.find(new_result.id()); 201 auto ui_result_it = ui_results_map.find(new_result.id());
202 if (ui_result_it != ui_results_map.end()) { 202 if (ui_result_it != ui_results_map.end()) {
203 // Update and use the old result if it exists. 203 // Update and use the old result if it exists.
204 std::unique_ptr<SearchResult> ui_result = std::move(ui_result_it->second); 204 std::unique_ptr<SearchResult> ui_result = std::move(ui_result_it->second);
205 UpdateResult(new_result, ui_result.get()); 205 UpdateResult(new_result, ui_result.get());
(...skipping 14 matching lines...) Expand all
220 220
221 // Any remaining results in |ui_results_map| will be automatically deleted. 221 // Any remaining results in |ui_results_map| will be automatically deleted.
222 } 222 }
223 223
224 void Mixer::RemoveDuplicates(SortedResults* results) { 224 void Mixer::RemoveDuplicates(SortedResults* results) {
225 SortedResults final; 225 SortedResults final;
226 final.reserve(results->size()); 226 final.reserve(results->size());
227 227
228 std::set<std::string> id_set; 228 std::set<std::string> id_set;
229 for (const SortData& sort_data : *results) { 229 for (const SortData& sort_data : *results) {
230 const std::string& id = sort_data.result->id(); 230 if (!id_set.insert(sort_data.result->id()).second)
231 if (id_set.find(id) != id_set.end())
232 continue; 231 continue;
233 232
234 id_set.insert(id); 233 final.emplace_back(sort_data);
235 final.push_back(sort_data);
236 } 234 }
237 235
238 results->swap(final); 236 results->swap(final);
239 } 237 }
240 238
241 void Mixer::FetchResults(bool is_voice_query, 239 void Mixer::FetchResults(bool is_voice_query,
242 const KnownResults& known_results) { 240 const KnownResults& known_results) {
243 for (auto* group : groups_) 241 for (auto* group : groups_)
244 group->FetchResults(is_voice_query, known_results); 242 group->FetchResults(is_voice_query, known_results);
245 } 243 }
246 244
247 } // namespace app_list 245 } // namespace app_list
OLDNEW
« no previous file with comments | « chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc ('k') | ui/app_list/search/tokenized_string.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698