OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 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 "chrome/browser/autocomplete/search_provider.h" | 5 #include "chrome/browser/autocomplete/search_provider.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 | 9 |
10 #include "base/base64.h" | 10 #include "base/base64.h" |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 | 125 |
126 | 126 |
127 // SearchProvider ------------------------------------------------------------- | 127 // SearchProvider ------------------------------------------------------------- |
128 | 128 |
129 // static | 129 // static |
130 int SearchProvider::kMinimumTimeBetweenSuggestQueriesMs = 100; | 130 int SearchProvider::kMinimumTimeBetweenSuggestQueriesMs = 100; |
131 | 131 |
132 SearchProvider::SearchProvider(AutocompleteProviderListener* listener, | 132 SearchProvider::SearchProvider(AutocompleteProviderListener* listener, |
133 TemplateURLService* template_url_service, | 133 TemplateURLService* template_url_service, |
134 Profile* profile) | 134 Profile* profile) |
135 : BaseSearchProvider(listener, template_url_service, profile, | 135 : BaseSearchProvider(template_url_service, profile, |
136 AutocompleteProvider::TYPE_SEARCH), | 136 AutocompleteProvider::TYPE_SEARCH), |
| 137 listener_(listener), |
| 138 suggest_results_pending_(0), |
137 providers_(template_url_service) { | 139 providers_(template_url_service) { |
138 } | 140 } |
139 | 141 |
140 // static | 142 // static |
141 std::string SearchProvider::GetSuggestMetadata(const AutocompleteMatch& match) { | 143 std::string SearchProvider::GetSuggestMetadata(const AutocompleteMatch& match) { |
142 return match.GetAdditionalInfo(kSuggestMetadataKey); | 144 return match.GetAdditionalInfo(kSuggestMetadataKey); |
143 } | 145 } |
144 | 146 |
145 void SearchProvider::ResetSession() { | 147 void SearchProvider::ResetSession() { |
146 field_trial_triggered_in_session_ = false; | 148 field_trial_triggered_in_session_ = false; |
147 } | 149 } |
148 | 150 |
149 SearchProvider::~SearchProvider() { | 151 SearchProvider::~SearchProvider() { |
150 } | 152 } |
151 | 153 |
152 void SearchProvider::UpdateMatchContentsClass( | |
153 const base::string16& input_text, | |
154 SearchSuggestionParser::Results* results) { | |
155 for (SearchSuggestionParser::SuggestResults::iterator sug_it = | |
156 results->suggest_results.begin(); | |
157 sug_it != results->suggest_results.end(); ++sug_it) { | |
158 sug_it->ClassifyMatchContents(false, input_text); | |
159 } | |
160 const std::string languages( | |
161 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); | |
162 for (SearchSuggestionParser::NavigationResults::iterator nav_it = | |
163 results->navigation_results.begin(); | |
164 nav_it != results->navigation_results.end(); ++nav_it) { | |
165 nav_it->CalculateAndClassifyMatchContents(false, input_text, languages); | |
166 } | |
167 } | |
168 | |
169 // static | 154 // static |
170 int SearchProvider::CalculateRelevanceForKeywordVerbatim( | 155 int SearchProvider::CalculateRelevanceForKeywordVerbatim( |
171 metrics::OmniboxInputType::Type type, | 156 metrics::OmniboxInputType::Type type, |
172 bool prefer_keyword) { | 157 bool prefer_keyword) { |
173 // This function is responsible for scoring verbatim query matches | 158 // This function is responsible for scoring verbatim query matches |
174 // for non-extension keywords. KeywordProvider::CalculateRelevance() | 159 // for non-extension keywords. KeywordProvider::CalculateRelevance() |
175 // scores verbatim query matches for extension keywords, as well as | 160 // scores verbatim query matches for extension keywords, as well as |
176 // for keyword matches (i.e., suggestions of a keyword itself, not a | 161 // for keyword matches (i.e., suggestions of a keyword itself, not a |
177 // suggestion of a query on a keyword search engine). These two | 162 // suggestion of a query on a keyword search engine). These two |
178 // functions are currently in sync, but there's no reason we | 163 // functions are currently in sync, but there's no reason we |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 } | 243 } |
259 | 244 |
260 input_ = input; | 245 input_ = input; |
261 | 246 |
262 DoHistoryQuery(minimal_changes); | 247 DoHistoryQuery(minimal_changes); |
263 DoAnswersQuery(input); | 248 DoAnswersQuery(input); |
264 StartOrStopSuggestQuery(minimal_changes); | 249 StartOrStopSuggestQuery(minimal_changes); |
265 UpdateMatches(); | 250 UpdateMatches(); |
266 } | 251 } |
267 | 252 |
268 void SearchProvider::SortResults(bool is_keyword, | |
269 SearchSuggestionParser::Results* results) { | |
270 // Ignore suggested scores for non-keyword matches in keyword mode; if the | |
271 // server is allowed to score these, it could interfere with the user's | |
272 // ability to get good keyword results. | |
273 const bool abandon_suggested_scores = | |
274 !is_keyword && !providers_.keyword_provider().empty(); | |
275 // Apply calculated relevance scores to suggestions if valid relevances were | |
276 // not provided or we're abandoning suggested scores entirely. | |
277 if (!results->relevances_from_server || abandon_suggested_scores) { | |
278 ApplyCalculatedSuggestRelevance(&results->suggest_results); | |
279 ApplyCalculatedNavigationRelevance(&results->navigation_results); | |
280 // If abandoning scores entirely, also abandon the verbatim score. | |
281 if (abandon_suggested_scores) | |
282 results->verbatim_relevance = -1; | |
283 } | |
284 | |
285 // Keep the result lists sorted. | |
286 const CompareScoredResults comparator = CompareScoredResults(); | |
287 std::stable_sort(results->suggest_results.begin(), | |
288 results->suggest_results.end(), | |
289 comparator); | |
290 std::stable_sort(results->navigation_results.begin(), | |
291 results->navigation_results.end(), | |
292 comparator); | |
293 } | |
294 | |
295 const TemplateURL* SearchProvider::GetTemplateURL(bool is_keyword) const { | 253 const TemplateURL* SearchProvider::GetTemplateURL(bool is_keyword) const { |
296 return is_keyword ? providers_.GetKeywordProviderURL() | 254 return is_keyword ? providers_.GetKeywordProviderURL() |
297 : providers_.GetDefaultProviderURL(); | 255 : providers_.GetDefaultProviderURL(); |
298 } | 256 } |
299 | 257 |
300 const AutocompleteInput SearchProvider::GetInput(bool is_keyword) const { | 258 const AutocompleteInput SearchProvider::GetInput(bool is_keyword) const { |
301 return is_keyword ? keyword_input_ : input_; | 259 return is_keyword ? keyword_input_ : input_; |
302 } | 260 } |
303 | 261 |
304 SearchSuggestionParser::Results* SearchProvider::GetResultsToFill( | |
305 bool is_keyword) { | |
306 return is_keyword ? &keyword_results_ : &default_results_; | |
307 } | |
308 | |
309 bool SearchProvider::ShouldAppendExtraParams( | 262 bool SearchProvider::ShouldAppendExtraParams( |
310 const SearchSuggestionParser::SuggestResult& result) const { | 263 const SearchSuggestionParser::SuggestResult& result) const { |
311 return !result.from_keyword_provider() || | 264 return !result.from_keyword_provider() || |
312 providers_.default_provider().empty(); | 265 providers_.default_provider().empty(); |
313 } | 266 } |
314 | 267 |
315 void SearchProvider::StopSuggest() { | 268 void SearchProvider::StopSuggest() { |
316 // Increment the appropriate field in the histogram by the number of | 269 // Increment the appropriate field in the histogram by the number of |
317 // pending requests that were invalidated. | 270 // pending requests that were invalidated. |
318 for (int i = 0; i < suggest_results_pending_; ++i) | 271 for (int i = 0; i < suggest_results_pending_; ++i) |
319 LogOmniboxSuggestRequest(REQUEST_INVALIDATED); | 272 LogOmniboxSuggestRequest(REQUEST_INVALIDATED); |
320 suggest_results_pending_ = 0; | 273 suggest_results_pending_ = 0; |
321 timer_.Stop(); | 274 timer_.Stop(); |
322 // Stop any in-progress URL fetches. | 275 // Stop any in-progress URL fetches. |
323 keyword_fetcher_.reset(); | 276 keyword_fetcher_.reset(); |
324 default_fetcher_.reset(); | 277 default_fetcher_.reset(); |
325 } | 278 } |
326 | 279 |
327 void SearchProvider::ClearAllResults() { | 280 void SearchProvider::ClearAllResults() { |
328 keyword_results_.Clear(); | 281 keyword_results_.Clear(); |
329 default_results_.Clear(); | 282 default_results_.Clear(); |
330 } | 283 } |
331 | 284 |
332 int SearchProvider::GetDefaultResultRelevance() const { | |
333 return -1; | |
334 } | |
335 | |
336 void SearchProvider::RecordDeletionResult(bool success) { | 285 void SearchProvider::RecordDeletionResult(bool success) { |
337 if (success) { | 286 if (success) { |
338 base::RecordAction( | 287 base::RecordAction( |
339 base::UserMetricsAction("Omnibox.ServerSuggestDelete.Success")); | 288 base::UserMetricsAction("Omnibox.ServerSuggestDelete.Success")); |
340 } else { | 289 } else { |
341 base::RecordAction( | 290 base::RecordAction( |
342 base::UserMetricsAction("Omnibox.ServerSuggestDelete.Failure")); | 291 base::UserMetricsAction("Omnibox.ServerSuggestDelete.Failure")); |
343 } | 292 } |
344 } | 293 } |
345 | 294 |
| 295 void SearchProvider::OnURLFetchComplete(const net::URLFetcher* source) { |
| 296 DCHECK(!done_); |
| 297 --suggest_results_pending_; |
| 298 DCHECK_GE(suggest_results_pending_, 0); // Should never go negative. |
| 299 |
| 300 const bool is_keyword = source == keyword_fetcher_.get(); |
| 301 |
| 302 // Ensure the request succeeded and that the provider used is still available. |
| 303 // A verbatim match cannot be generated without this provider, causing errors. |
| 304 const bool request_succeeded = |
| 305 source->GetStatus().is_success() && (source->GetResponseCode() == 200) && |
| 306 GetTemplateURL(is_keyword); |
| 307 |
| 308 LogFetchComplete(request_succeeded, is_keyword); |
| 309 |
| 310 bool results_updated = false; |
| 311 if (request_succeeded) { |
| 312 scoped_ptr<base::Value> data(SearchSuggestionParser::DeserializeJsonData( |
| 313 SearchSuggestionParser::ExtractJsonData(source))); |
| 314 if (data) { |
| 315 SearchSuggestionParser::Results* results = |
| 316 is_keyword ? &keyword_results_ : &default_results_; |
| 317 results_updated = ParseSuggestResults(*data, -1, is_keyword, results); |
| 318 if (results_updated) |
| 319 SortResults(is_keyword, results); |
| 320 } |
| 321 } |
| 322 UpdateMatches(); |
| 323 if (done_ || results_updated) |
| 324 listener_->OnProviderUpdate(results_updated); |
| 325 } |
| 326 |
| 327 void SearchProvider::UpdateMatchContentsClass( |
| 328 const base::string16& input_text, |
| 329 SearchSuggestionParser::Results* results) { |
| 330 for (SearchSuggestionParser::SuggestResults::iterator sug_it = |
| 331 results->suggest_results.begin(); |
| 332 sug_it != results->suggest_results.end(); ++sug_it) { |
| 333 sug_it->ClassifyMatchContents(false, input_text); |
| 334 } |
| 335 const std::string languages( |
| 336 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); |
| 337 for (SearchSuggestionParser::NavigationResults::iterator nav_it = |
| 338 results->navigation_results.begin(); |
| 339 nav_it != results->navigation_results.end(); ++nav_it) { |
| 340 nav_it->CalculateAndClassifyMatchContents(false, input_text, languages); |
| 341 } |
| 342 } |
| 343 |
| 344 void SearchProvider::SortResults(bool is_keyword, |
| 345 SearchSuggestionParser::Results* results) { |
| 346 // Ignore suggested scores for non-keyword matches in keyword mode; if the |
| 347 // server is allowed to score these, it could interfere with the user's |
| 348 // ability to get good keyword results. |
| 349 const bool abandon_suggested_scores = |
| 350 !is_keyword && !providers_.keyword_provider().empty(); |
| 351 // Apply calculated relevance scores to suggestions if valid relevances were |
| 352 // not provided or we're abandoning suggested scores entirely. |
| 353 if (!results->relevances_from_server || abandon_suggested_scores) { |
| 354 ApplyCalculatedSuggestRelevance(&results->suggest_results); |
| 355 ApplyCalculatedNavigationRelevance(&results->navigation_results); |
| 356 // If abandoning scores entirely, also abandon the verbatim score. |
| 357 if (abandon_suggested_scores) |
| 358 results->verbatim_relevance = -1; |
| 359 } |
| 360 |
| 361 // Keep the result lists sorted. |
| 362 const CompareScoredResults comparator = CompareScoredResults(); |
| 363 std::stable_sort(results->suggest_results.begin(), |
| 364 results->suggest_results.end(), |
| 365 comparator); |
| 366 std::stable_sort(results->navigation_results.begin(), |
| 367 results->navigation_results.end(), |
| 368 comparator); |
| 369 } |
| 370 |
346 void SearchProvider::LogFetchComplete(bool success, bool is_keyword) { | 371 void SearchProvider::LogFetchComplete(bool success, bool is_keyword) { |
347 LogOmniboxSuggestRequest(REPLY_RECEIVED); | 372 LogOmniboxSuggestRequest(REPLY_RECEIVED); |
348 // Record response time for suggest requests sent to Google. We care | 373 // Record response time for suggest requests sent to Google. We care |
349 // only about the common case: the Google default provider used in | 374 // only about the common case: the Google default provider used in |
350 // non-keyword mode. | 375 // non-keyword mode. |
351 const TemplateURL* default_url = providers_.GetDefaultProviderURL(); | 376 const TemplateURL* default_url = providers_.GetDefaultProviderURL(); |
352 if (!is_keyword && default_url && | 377 if (!is_keyword && default_url && |
353 (TemplateURLPrepopulateData::GetEngineType( | 378 (TemplateURLPrepopulateData::GetEngineType( |
354 *default_url, | 379 *default_url, |
355 providers_.template_url_service()->search_terms_data()) == | 380 providers_.template_url_service()->search_terms_data()) == |
356 SEARCH_ENGINE_GOOGLE)) { | 381 SEARCH_ENGINE_GOOGLE)) { |
357 const base::TimeDelta elapsed_time = | 382 const base::TimeDelta elapsed_time = |
358 base::TimeTicks::Now() - time_suggest_request_sent_; | 383 base::TimeTicks::Now() - time_suggest_request_sent_; |
359 if (success) { | 384 if (success) { |
360 UMA_HISTOGRAM_TIMES("Omnibox.SuggestRequest.Success.GoogleResponseTime", | 385 UMA_HISTOGRAM_TIMES("Omnibox.SuggestRequest.Success.GoogleResponseTime", |
361 elapsed_time); | 386 elapsed_time); |
362 } else { | 387 } else { |
363 UMA_HISTOGRAM_TIMES("Omnibox.SuggestRequest.Failure.GoogleResponseTime", | 388 UMA_HISTOGRAM_TIMES("Omnibox.SuggestRequest.Failure.GoogleResponseTime", |
364 elapsed_time); | 389 elapsed_time); |
365 } | 390 } |
366 } | 391 } |
367 } | 392 } |
368 | 393 |
369 bool SearchProvider::IsKeywordFetcher(const net::URLFetcher* fetcher) const { | |
370 return fetcher == keyword_fetcher_.get(); | |
371 } | |
372 | |
373 void SearchProvider::UpdateMatches() { | 394 void SearchProvider::UpdateMatches() { |
374 ConvertResultsToAutocompleteMatches(); | 395 ConvertResultsToAutocompleteMatches(); |
375 | 396 |
376 // Check constraints that may be violated by suggested relevances. | 397 // Check constraints that may be violated by suggested relevances. |
377 if (!matches_.empty() && | 398 if (!matches_.empty() && |
378 (default_results_.HasServerProvidedScores() || | 399 (default_results_.HasServerProvidedScores() || |
379 keyword_results_.HasServerProvidedScores())) { | 400 keyword_results_.HasServerProvidedScores())) { |
380 // These blocks attempt to repair undesirable behavior by suggested | 401 // These blocks attempt to repair undesirable behavior by suggested |
381 // relevances with minimal impact, preserving other suggested relevances. | 402 // relevances with minimal impact, preserving other suggested relevances. |
382 | 403 |
(...skipping 858 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1241 last_answer_seen_.query_type = match->answer_type; | 1262 last_answer_seen_.query_type = match->answer_type; |
1242 } | 1263 } |
1243 | 1264 |
1244 void SearchProvider::DoAnswersQuery(const AutocompleteInput& input) { | 1265 void SearchProvider::DoAnswersQuery(const AutocompleteInput& input) { |
1245 // If the query text starts with trimmed input, this is valid prefetch data. | 1266 // If the query text starts with trimmed input, this is valid prefetch data. |
1246 prefetch_data_ = StartsWith(last_answer_seen_.full_query_text, | 1267 prefetch_data_ = StartsWith(last_answer_seen_.full_query_text, |
1247 base::CollapseWhitespace(input.text(), false), | 1268 base::CollapseWhitespace(input.text(), false), |
1248 false) ? | 1269 false) ? |
1249 last_answer_seen_ : AnswersQueryData(); | 1270 last_answer_seen_ : AnswersQueryData(); |
1250 } | 1271 } |
OLD | NEW |