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

Side by Side Diff: components/omnibox/browser/shortcuts_provider.cc

Issue 1877833002: Optimize shortcuts provider (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase on master and minor format fix Created 4 years, 8 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
« no previous file with comments | « components/omnibox/browser/shortcuts_provider.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "components/omnibox/browser/shortcuts_provider.h" 5 #include "components/omnibox/browser/shortcuts_provider.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 #include <cmath> 10 #include <cmath>
(...skipping 10 matching lines...) Expand all
21 #include "base/time/time.h" 21 #include "base/time/time.h"
22 #include "base/trace_event/trace_event.h" 22 #include "base/trace_event/trace_event.h"
23 #include "components/history/core/browser/history_service.h" 23 #include "components/history/core/browser/history_service.h"
24 #include "components/metrics/proto/omnibox_input_type.pb.h" 24 #include "components/metrics/proto/omnibox_input_type.pb.h"
25 #include "components/omnibox/browser/autocomplete_i18n.h" 25 #include "components/omnibox/browser/autocomplete_i18n.h"
26 #include "components/omnibox/browser/autocomplete_input.h" 26 #include "components/omnibox/browser/autocomplete_input.h"
27 #include "components/omnibox/browser/autocomplete_match.h" 27 #include "components/omnibox/browser/autocomplete_match.h"
28 #include "components/omnibox/browser/autocomplete_provider_client.h" 28 #include "components/omnibox/browser/autocomplete_provider_client.h"
29 #include "components/omnibox/browser/autocomplete_result.h" 29 #include "components/omnibox/browser/autocomplete_result.h"
30 #include "components/omnibox/browser/history_provider.h" 30 #include "components/omnibox/browser/history_provider.h"
31 #include "components/omnibox/browser/match_compare.h"
31 #include "components/omnibox/browser/omnibox_field_trial.h" 32 #include "components/omnibox/browser/omnibox_field_trial.h"
32 #include "components/omnibox/browser/url_prefix.h" 33 #include "components/omnibox/browser/url_prefix.h"
33 #include "components/prefs/pref_service.h" 34 #include "components/prefs/pref_service.h"
34 #include "components/url_formatter/url_fixer.h" 35 #include "components/url_formatter/url_fixer.h"
35 #include "url/third_party/mozilla/url_parse.h" 36 #include "url/third_party/mozilla/url_parse.h"
36 37
37 namespace { 38 namespace {
38 39
39 class DestinationURLEqualsURL { 40 class DestinationURLEqualsURL {
40 public: 41 public:
41 explicit DestinationURLEqualsURL(const GURL& url) : url_(url) {} 42 explicit DestinationURLEqualsURL(const GURL& url) : url_(url) {}
42 bool operator()(const AutocompleteMatch& match) const { 43 bool operator()(const AutocompleteMatch& match) const {
43 return match.destination_url == url_; 44 return match.destination_url == url_;
44 } 45 }
45 46
46 private: 47 private:
47 const GURL url_; 48 const GURL url_;
48 }; 49 };
49 50
51 // ShortcutMatch holds sufficient information about a single match from the
52 // shortcut database to allow for destination deduping and relevance sorting.
53 // After those stages the top matches are converted to the more heavyweight
54 // AutocompleteMatch struct. Avoiding constructing the larger struct for
55 // every such match can save significant time when there are many shortcut
56 // matches to process.
57 struct ShortcutMatch {
58 ShortcutMatch(int relevance,
59 const GURL& stripped_destination_url,
60 const ShortcutsDatabase::Shortcut* shortcut)
61 : relevance(relevance),
62 stripped_destination_url(stripped_destination_url),
63 shortcut(shortcut),
64 contents(shortcut->match_core.contents),
65 type(static_cast<AutocompleteMatch::Type>(shortcut->match_core.type)) {}
66
67 int relevance;
68 GURL stripped_destination_url;
69 const ShortcutsDatabase::Shortcut* shortcut;
70 base::string16 contents;
71 AutocompleteMatch::Type type;
72 };
73
74 // Sorts |matches| by destination, taking into account demotions based on
75 // |page_classification| when resolving ties about which of several
76 // duplicates to keep. The matches are also deduplicated.
77 void SortAndDedupMatches(
78 metrics::OmniboxEventProto::PageClassification page_classification,
79 std::vector<ShortcutMatch>* matches) {
80 // Sort matches such that duplicate matches are consecutive.
81 std::sort(matches->begin(), matches->end(),
82 DestinationSort<ShortcutMatch>(page_classification));
83
84 // Erase duplicate matches. Duplicate matches are those with
85 // stripped_destination_url fields equal and non empty.
86 matches->erase(
87 std::unique(matches->begin(), matches->end(),
88 [](const ShortcutMatch& elem1, const ShortcutMatch& elem2) {
89 return !elem1.stripped_destination_url.is_empty() &&
90 (elem1.stripped_destination_url ==
91 elem2.stripped_destination_url);
92 }),
93 matches->end());
94 }
95
50 } // namespace 96 } // namespace
51 97
52 const int ShortcutsProvider::kShortcutsProviderDefaultMaxRelevance = 1199; 98 const int ShortcutsProvider::kShortcutsProviderDefaultMaxRelevance = 1199;
53 99
54 ShortcutsProvider::ShortcutsProvider(AutocompleteProviderClient* client) 100 ShortcutsProvider::ShortcutsProvider(AutocompleteProviderClient* client)
55 : AutocompleteProvider(AutocompleteProvider::TYPE_SHORTCUTS), 101 : AutocompleteProvider(AutocompleteProvider::TYPE_SHORTCUTS),
56 client_(client), 102 client_(client),
57 initialized_(false) { 103 initialized_(false) {
58 scoped_refptr<ShortcutsBackend> backend = client_->GetShortcutsBackend(); 104 scoped_refptr<ShortcutsBackend> backend = client_->GetShortcutsBackend();
59 if (backend.get()) { 105 if (backend.get()) {
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 // completely match the search term. 176 // completely match the search term.
131 base::string16 term_string(base::i18n::ToLower(input.text())); 177 base::string16 term_string(base::i18n::ToLower(input.text()));
132 DCHECK(!term_string.empty()); 178 DCHECK(!term_string.empty());
133 179
134 int max_relevance; 180 int max_relevance;
135 if (!OmniboxFieldTrial::ShortcutsScoringMaxRelevance( 181 if (!OmniboxFieldTrial::ShortcutsScoringMaxRelevance(
136 input.current_page_classification(), &max_relevance)) 182 input.current_page_classification(), &max_relevance))
137 max_relevance = kShortcutsProviderDefaultMaxRelevance; 183 max_relevance = kShortcutsProviderDefaultMaxRelevance;
138 TemplateURLService* template_url_service = client_->GetTemplateURLService(); 184 TemplateURLService* template_url_service = client_->GetTemplateURLService();
139 const base::string16 fixed_up_input(FixupUserInput(input).second); 185 const base::string16 fixed_up_input(FixupUserInput(input).second);
186
187 std::vector<ShortcutMatch> shortcut_matches;
140 for (ShortcutsBackend::ShortcutMap::const_iterator it = 188 for (ShortcutsBackend::ShortcutMap::const_iterator it =
141 FindFirstMatch(term_string, backend.get()); 189 FindFirstMatch(term_string, backend.get());
142 it != backend->shortcuts_map().end() && 190 it != backend->shortcuts_map().end() &&
143 base::StartsWith(it->first, term_string, 191 base::StartsWith(it->first, term_string,
144 base::CompareCase::SENSITIVE); 192 base::CompareCase::SENSITIVE);
145 ++it) { 193 ++it) {
146 // Don't return shortcuts with zero relevance. 194 // Don't return shortcuts with zero relevance.
147 int relevance = CalculateScore(term_string, it->second, max_relevance); 195 int relevance = CalculateScore(term_string, it->second, max_relevance);
148 if (relevance) { 196 if (relevance) {
149 matches_.push_back( 197 const ShortcutsDatabase::Shortcut& shortcut = it->second;
150 ShortcutToACMatch(it->second, relevance, input, fixed_up_input)); 198 GURL stripped_destination_url(AutocompleteMatch::GURLToStrippedGURL(
151 matches_.back().ComputeStrippedDestinationURL(input, 199 shortcut.match_core.destination_url, input, template_url_service,
152 template_url_service); 200 shortcut.match_core.keyword));
201 shortcut_matches.push_back(
202 ShortcutMatch(relevance, stripped_destination_url, &it->second));
153 } 203 }
154 } 204 }
155 // Remove duplicates. This is important because it's common to have multiple 205 // Remove duplicates. This is important because it's common to have multiple
156 // shortcuts pointing to the same URL, e.g., ma, mai, and mail all pointing 206 // shortcuts pointing to the same URL, e.g., ma, mai, and mail all pointing
157 // to mail.google.com, so typing "m" will return them all. If we then simply 207 // to mail.google.com, so typing "m" will return them all. If we then simply
158 // clamp to kMaxMatches and let the AutocompleteResult take care of 208 // clamp to kMaxMatches and let the SortAndDedupMatches take care of
159 // collapsing the duplicates, we'll effectively only be returning one match, 209 // collapsing the duplicates, we'll effectively only be returning one match,
160 // instead of several possibilities. 210 // instead of several possibilities.
161 // 211 //
162 // Note that while removing duplicates, we don't populate a match's 212 // Note that while removing duplicates, we don't populate a match's
163 // |duplicate_matches| field--duplicates don't need to be preserved in the 213 // |duplicate_matches| field--duplicates don't need to be preserved in the
164 // matches because they are only used for deletions, and this provider 214 // matches because they are only used for deletions, and this provider
165 // deletes matches based on the URL. 215 // deletes matches based on the URL.
166 AutocompleteResult::DedupMatchesByDestination( 216 SortAndDedupMatches(input.current_page_classification(), &shortcut_matches);
167 input.current_page_classification(), false, &matches_); 217
168 // Find best matches. 218 // Find best matches.
169 std::partial_sort( 219 std::partial_sort(
170 matches_.begin(), 220 shortcut_matches.begin(),
171 matches_.begin() + 221 shortcut_matches.begin() +
172 std::min(AutocompleteProvider::kMaxMatches, matches_.size()), 222 std::min(AutocompleteProvider::kMaxMatches, shortcut_matches.size()),
173 matches_.end(), &AutocompleteMatch::MoreRelevant); 223 shortcut_matches.end(),
174 if (matches_.size() > AutocompleteProvider::kMaxMatches) { 224 [](const ShortcutMatch& elem1, const ShortcutMatch& elem2) {
175 matches_.erase(matches_.begin() + AutocompleteProvider::kMaxMatches, 225 // Ensure a stable sort by sorting equal-relevance matches
176 matches_.end()); 226 // alphabetically.
227 return elem1.relevance == elem2.relevance
228 ? elem1.contents < elem2.contents
229 : elem1.relevance > elem2.relevance;
230 });
231 if (shortcut_matches.size() > AutocompleteProvider::kMaxMatches) {
232 shortcut_matches.erase(
233 shortcut_matches.begin() + AutocompleteProvider::kMaxMatches,
234 shortcut_matches.end());
177 } 235 }
178 // Guarantee that all scores are decreasing (but do not assign any scores 236 // Create and initialize autocomplete matches from shortcut matches.
179 // below 1). 237 // Also guarantee that all relevance scores are decreasing (but do not assign
180 for (ACMatches::iterator it = matches_.begin(); it != matches_.end(); ++it) { 238 // any scores below 1).
181 max_relevance = std::min(max_relevance, it->relevance); 239 WordMap terms_map(CreateWordMapForString(term_string));
182 it->relevance = max_relevance; 240 matches_.reserve(shortcut_matches.size());
241 for (ShortcutMatch& match : shortcut_matches) {
242 max_relevance = std::min(max_relevance, match.relevance);
243 matches_.push_back(ShortcutToACMatch(*match.shortcut, max_relevance, input,
244 fixed_up_input, term_string,
245 terms_map));
183 if (max_relevance > 1) 246 if (max_relevance > 1)
184 --max_relevance; 247 --max_relevance;
185 } 248 }
186 } 249 }
187 250
188 AutocompleteMatch ShortcutsProvider::ShortcutToACMatch( 251 AutocompleteMatch ShortcutsProvider::ShortcutToACMatch(
189 const ShortcutsDatabase::Shortcut& shortcut, 252 const ShortcutsDatabase::Shortcut& shortcut,
190 int relevance, 253 int relevance,
191 const AutocompleteInput& input, 254 const AutocompleteInput& input,
192 const base::string16& fixed_up_input_text) { 255 const base::string16& fixed_up_input_text,
256 const base::string16 term_string,
257 const WordMap& terms_map) {
193 DCHECK(!input.text().empty()); 258 DCHECK(!input.text().empty());
194 AutocompleteMatch match; 259 AutocompleteMatch match;
195 match.provider = this; 260 match.provider = this;
196 match.relevance = relevance; 261 match.relevance = relevance;
197 match.deletable = true; 262 match.deletable = true;
198 match.fill_into_edit = shortcut.match_core.fill_into_edit; 263 match.fill_into_edit = shortcut.match_core.fill_into_edit;
199 match.destination_url = shortcut.match_core.destination_url; 264 match.destination_url = shortcut.match_core.destination_url;
200 DCHECK(match.destination_url.is_valid()); 265 DCHECK(match.destination_url.is_valid());
201 match.contents = shortcut.match_core.contents; 266 match.contents = shortcut.match_core.contents;
202 match.contents_class = AutocompleteMatch::ClassificationsFromString( 267 match.contents_class = AutocompleteMatch::ClassificationsFromString(
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 URLPrefix::GetInlineAutocompleteOffset( 303 URLPrefix::GetInlineAutocompleteOffset(
239 input.text(), fixed_up_input_text, true, match.fill_into_edit); 304 input.text(), fixed_up_input_text, true, match.fill_into_edit);
240 if (inline_autocomplete_offset != base::string16::npos) { 305 if (inline_autocomplete_offset != base::string16::npos) {
241 match.inline_autocompletion = 306 match.inline_autocompletion =
242 match.fill_into_edit.substr(inline_autocomplete_offset); 307 match.fill_into_edit.substr(inline_autocomplete_offset);
243 match.allowed_to_be_default_match = 308 match.allowed_to_be_default_match =
244 !HistoryProvider::PreventInlineAutocomplete(input) || 309 !HistoryProvider::PreventInlineAutocomplete(input) ||
245 match.inline_autocompletion.empty(); 310 match.inline_autocompletion.empty();
246 } 311 }
247 } 312 }
248 match.EnsureUWYTIsAllowedToBeDefault(input, 313
249 client_->GetTemplateURLService()); 314 match.EnsureUWYTIsAllowedToBeDefault(input, client_->GetTemplateURLService());
250 315
251 // Try to mark pieces of the contents and description as matches if they 316 // Try to mark pieces of the contents and description as matches if they
252 // appear in |input.text()|. 317 // appear in |input.text()|.
253 const base::string16 term_string = base::i18n::ToLower(input.text());
254 WordMap terms_map(CreateWordMapForString(term_string));
255 if (!terms_map.empty()) { 318 if (!terms_map.empty()) {
256 match.contents_class = ClassifyAllMatchesInString( 319 match.contents_class = ClassifyAllMatchesInString(
257 term_string, terms_map, match.contents, match.contents_class); 320 term_string, terms_map, match.contents, match.contents_class);
258 match.description_class = ClassifyAllMatchesInString( 321 match.description_class = ClassifyAllMatchesInString(
259 term_string, terms_map, match.description, match.description_class); 322 term_string, terms_map, match.description, match.description_class);
260 } 323 }
261 return match; 324 return match;
262 } 325 }
263 326
264 // static 327 // static
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
414 const double kMaxDecaySpeedDivisor = 5.0; 477 const double kMaxDecaySpeedDivisor = 5.0;
415 const double kNumUsesPerDecaySpeedDivisorIncrement = 5.0; 478 const double kNumUsesPerDecaySpeedDivisorIncrement = 5.0;
416 double decay_divisor = std::min( 479 double decay_divisor = std::min(
417 kMaxDecaySpeedDivisor, 480 kMaxDecaySpeedDivisor,
418 (shortcut.number_of_hits + kNumUsesPerDecaySpeedDivisorIncrement - 1) / 481 (shortcut.number_of_hits + kNumUsesPerDecaySpeedDivisorIncrement - 1) /
419 kNumUsesPerDecaySpeedDivisorIncrement); 482 kNumUsesPerDecaySpeedDivisorIncrement);
420 483
421 return static_cast<int>((base_score / exp(decay_exponent / decay_divisor)) + 484 return static_cast<int>((base_score / exp(decay_exponent / decay_divisor)) +
422 0.5); 485 0.5);
423 } 486 }
OLDNEW
« no previous file with comments | « components/omnibox/browser/shortcuts_provider.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698