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 "components/omnibox/search_provider.h" | 5 #include "components/omnibox/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 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
258 match.allowed_to_be_default_match = true; | 258 match.allowed_to_be_default_match = true; |
259 matches_.push_back(match); | 259 matches_.push_back(match); |
260 } | 260 } |
261 Stop(true); | 261 Stop(true); |
262 return; | 262 return; |
263 } | 263 } |
264 | 264 |
265 input_ = input; | 265 input_ = input; |
266 | 266 |
267 DoHistoryQuery(minimal_changes); | 267 DoHistoryQuery(minimal_changes); |
268 DoAnswersQuery(input); | 268 // Answers needs scored history results before any suggest query has been |
269 // started, since the query for answer-bearing results needs additional | |
270 // prefetch information based on the highest-scored local history result. | |
271 if (OmniboxFieldTrial::EnableAnswersInSuggest()) { | |
272 ScoreHistoryResultsMultiWord(raw_default_history_results_, | |
273 false, | |
274 &transformed_default_history_results_); | |
275 ScoreHistoryResultsMultiWord(raw_keyword_history_results_, | |
276 true, | |
277 &transformed_keyword_history_results_); | |
278 | |
279 prefetch_data_ = FindAnswersPrefetchData(input.text()); | |
280 } else { | |
281 transformed_default_history_results_.clear(); | |
282 transformed_keyword_history_results_.clear(); | |
283 } | |
284 | |
269 StartOrStopSuggestQuery(minimal_changes); | 285 StartOrStopSuggestQuery(minimal_changes); |
270 UpdateMatches(); | 286 UpdateMatches(); |
271 } | 287 } |
272 | 288 |
273 void SearchProvider::Stop(bool clear_cached_results) { | 289 void SearchProvider::Stop(bool clear_cached_results) { |
274 StopSuggest(); | 290 StopSuggest(); |
275 done_ = true; | 291 done_ = true; |
276 | 292 |
277 if (clear_cached_results) | 293 if (clear_cached_results) |
278 ClearAllResults(); | 294 ClearAllResults(); |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
512 listener_->OnProviderUpdate(false); | 528 listener_->OnProviderUpdate(false); |
513 } | 529 } |
514 } | 530 } |
515 | 531 |
516 void SearchProvider::DoHistoryQuery(bool minimal_changes) { | 532 void SearchProvider::DoHistoryQuery(bool minimal_changes) { |
517 // The history query results are synchronous, so if minimal_changes is true, | 533 // The history query results are synchronous, so if minimal_changes is true, |
518 // we still have the last results and don't need to do anything. | 534 // we still have the last results and don't need to do anything. |
519 if (minimal_changes) | 535 if (minimal_changes) |
520 return; | 536 return; |
521 | 537 |
522 keyword_history_results_.clear(); | 538 raw_keyword_history_results_.clear(); |
523 default_history_results_.clear(); | 539 raw_default_history_results_.clear(); |
524 | 540 |
525 if (OmniboxFieldTrial::SearchHistoryDisable( | 541 if (OmniboxFieldTrial::SearchHistoryDisable( |
526 input_.current_page_classification())) | 542 input_.current_page_classification())) |
527 return; | 543 return; |
528 | 544 |
529 history::URLDatabase* url_db = client_->InMemoryDatabase(); | 545 history::URLDatabase* url_db = client_->InMemoryDatabase(); |
530 if (!url_db) | 546 if (!url_db) |
531 return; | 547 return; |
532 | 548 |
533 // Request history for both the keyword and default provider. We grab many | 549 // Request history for both the keyword and default provider. We grab many |
534 // more matches than we'll ultimately clamp to so that if there are several | 550 // more matches than we'll ultimately clamp to so that if there are several |
535 // recent multi-word matches who scores are lowered (see | 551 // recent multi-word matches who scores are lowered (see |
536 // AddHistoryResultsToMap()), they won't crowd out older, higher-scoring | 552 // ScoreHistoryResultsMultiWord()), they won't crowd out older, higher-scoring |
537 // matches. Note that this doesn't fix the problem entirely, but merely | 553 // matches. Note that this doesn't fix the problem entirely, but merely |
538 // limits it to cases with a very large number of such multi-word matches; for | 554 // limits it to cases with a very large number of such multi-word matches; for |
539 // now, this seems OK compared with the complexity of a real fix, which would | 555 // now, this seems OK compared with the complexity of a real fix, which would |
540 // require multiple searches and tracking of "single- vs. multi-word" in the | 556 // require multiple searches and tracking of "single- vs. multi-word" in the |
541 // database. | 557 // database. |
542 int num_matches = kMaxMatches * 5; | 558 int num_matches = kMaxMatches * 5; |
543 const TemplateURL* default_url = providers_.GetDefaultProviderURL(); | 559 const TemplateURL* default_url = providers_.GetDefaultProviderURL(); |
544 if (default_url) { | 560 if (default_url) { |
545 const base::TimeTicks start_time = base::TimeTicks::Now(); | 561 const base::TimeTicks start_time = base::TimeTicks::Now(); |
546 url_db->GetMostRecentKeywordSearchTerms(default_url->id(), input_.text(), | 562 url_db->GetMostRecentKeywordSearchTerms(default_url->id(), |
547 num_matches, &default_history_results_); | 563 input_.text(), |
564 num_matches, | |
565 &raw_default_history_results_); | |
548 UMA_HISTOGRAM_TIMES( | 566 UMA_HISTOGRAM_TIMES( |
549 "Omnibox.SearchProvider.GetMostRecentKeywordTermsDefaultProviderTime", | 567 "Omnibox.SearchProvider.GetMostRecentKeywordTermsDefaultProviderTime", |
550 base::TimeTicks::Now() - start_time); | 568 base::TimeTicks::Now() - start_time); |
551 } | 569 } |
552 const TemplateURL* keyword_url = providers_.GetKeywordProviderURL(); | 570 const TemplateURL* keyword_url = providers_.GetKeywordProviderURL(); |
553 if (keyword_url) { | 571 if (keyword_url) { |
554 url_db->GetMostRecentKeywordSearchTerms(keyword_url->id(), | 572 url_db->GetMostRecentKeywordSearchTerms(keyword_url->id(), |
555 keyword_input_.text(), num_matches, &keyword_history_results_); | 573 keyword_input_.text(), |
574 num_matches, | |
575 &raw_keyword_history_results_); | |
556 } | 576 } |
557 } | 577 } |
558 | 578 |
559 void SearchProvider::StartOrStopSuggestQuery(bool minimal_changes) { | 579 void SearchProvider::StartOrStopSuggestQuery(bool minimal_changes) { |
560 if (!IsQuerySuitableForSuggest()) { | 580 if (!IsQuerySuitableForSuggest()) { |
561 StopSuggest(); | 581 StopSuggest(); |
562 ClearAllResults(); | 582 ClearAllResults(); |
563 return; | 583 return; |
564 } | 584 } |
565 | 585 |
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
837 trimmed_verbatim, AutocompleteMatchType::SEARCH_OTHER_ENGINE, | 857 trimmed_verbatim, AutocompleteMatchType::SEARCH_OTHER_ENGINE, |
838 trimmed_verbatim, base::string16(), base::string16(), | 858 trimmed_verbatim, base::string16(), base::string16(), |
839 base::string16(), base::string16(), std::string(), std::string(), | 859 base::string16(), base::string16(), std::string(), std::string(), |
840 true, keyword_verbatim_relevance, keyword_relevance_from_server, | 860 true, keyword_verbatim_relevance, keyword_relevance_from_server, |
841 false, trimmed_verbatim); | 861 false, trimmed_verbatim); |
842 AddMatchToMap(verbatim, std::string(), | 862 AddMatchToMap(verbatim, std::string(), |
843 did_not_accept_keyword_suggestion, false, true, &map); | 863 did_not_accept_keyword_suggestion, false, true, &map); |
844 } | 864 } |
845 } | 865 } |
846 } | 866 } |
847 AddHistoryResultsToMap(keyword_history_results_, true, | 867 AddRawHistoryResultsToMap(raw_keyword_history_results_, |
848 did_not_accept_keyword_suggestion, &map); | 868 true, |
849 AddHistoryResultsToMap(default_history_results_, false, | 869 did_not_accept_keyword_suggestion, |
850 did_not_accept_default_suggestion, &map); | 870 &map); |
871 AddRawHistoryResultsToMap(raw_default_history_results_, | |
872 false, | |
873 did_not_accept_default_suggestion, | |
874 &map); | |
851 | 875 |
852 AddSuggestResultsToMap(keyword_results_.suggest_results, | 876 AddSuggestResultsToMap(keyword_results_.suggest_results, |
853 keyword_results_.metadata, &map); | 877 keyword_results_.metadata, &map); |
854 AddSuggestResultsToMap(default_results_.suggest_results, | 878 AddSuggestResultsToMap(default_results_.suggest_results, |
855 default_results_.metadata, &map); | 879 default_results_.metadata, &map); |
856 | 880 |
857 ACMatches matches; | 881 ACMatches matches; |
858 for (MatchMap::const_iterator i(map.begin()); i != map.end(); ++i) | 882 for (MatchMap::const_iterator i(map.begin()); i != map.end(); ++i) |
859 matches.push_back(i->second); | 883 matches.push_back(i->second); |
860 | 884 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
930 for (SearchSuggestionParser::NavigationResults::const_iterator it = | 954 for (SearchSuggestionParser::NavigationResults::const_iterator it = |
931 navigation_results.begin(); it != navigation_results.end(); ++it) { | 955 navigation_results.begin(); it != navigation_results.end(); ++it) { |
932 matches->push_back(NavigationToMatch(*it)); | 956 matches->push_back(NavigationToMatch(*it)); |
933 // In the absence of suggested relevance scores, use only the single | 957 // In the absence of suggested relevance scores, use only the single |
934 // highest-scoring result. (The results are already sorted by relevance.) | 958 // highest-scoring result. (The results are already sorted by relevance.) |
935 if (!it->relevance_from_server()) | 959 if (!it->relevance_from_server()) |
936 return; | 960 return; |
937 } | 961 } |
938 } | 962 } |
939 | 963 |
940 void SearchProvider::AddHistoryResultsToMap(const HistoryResults& results, | 964 void SearchProvider::AddRawHistoryResultsToMap( |
941 bool is_keyword, | 965 const HistoryResults& raw_results, |
942 int did_not_accept_suggestion, | 966 bool is_keyword, |
943 MatchMap* map) { | 967 int did_not_accept_suggestion, |
944 if (results.empty()) | 968 MatchMap* map) { |
969 if (raw_results.empty()) | |
945 return; | 970 return; |
946 | 971 |
947 base::TimeTicks start_time(base::TimeTicks::Now()); | 972 base::TimeTicks start_time(base::TimeTicks::Now()); |
948 bool prevent_inline_autocomplete = input_.prevent_inline_autocomplete() || | |
949 (input_.type() == metrics::OmniboxInputType::URL); | |
950 const base::string16& input_text = | |
951 is_keyword ? keyword_input_.text() : input_.text(); | |
952 bool input_multiple_words = HasMultipleWords(input_text); | |
953 | 973 |
954 SearchSuggestionParser::SuggestResults scored_results; | 974 // Until Answers becomes default, scoring of history results will still happen |
955 if (!prevent_inline_autocomplete && input_multiple_words) { | 975 // here for non-Answers Chrome, to prevent scoring regressions from moving the |
Mark P
2014/09/16 22:24:55
nit: ^scoring^performance
(I think)
If you are wo
groby-ooo-7-16
2014/09/18 23:27:24
performance regressions, indeed.
| |
956 // ScoreHistoryResults() allows autocompletion of multi-word, 1-visit | 976 // scoring code before the suggest request is sent. |
957 // queries if the input also has multiple words. But if we were already | 977 // For users with Answers enabled, the history results have already been |
958 // scoring a multi-word, multi-visit query aggressively, and the current | 978 // scored earlier, right after calling DoHistoryQuery(). |
959 // input is still a prefix of it, then changing the suggestion suddenly | 979 SearchSuggestionParser::SuggestResults local_transformed_results; |
960 // feels wrong. To detect this case, first score as if only one word has | 980 const SearchSuggestionParser::SuggestResults* transformed_results = NULL; |
961 // been typed, then check if the best result came from aggressive search | 981 if (!OmniboxFieldTrial::EnableAnswersInSuggest()) { |
962 // history scoring. If it did, then just keep that score set. This | 982 ScoreHistoryResultsMultiWord( |
963 // 1200 the lowest possible score in CalculateRelevanceForHistory()'s | 983 raw_results, is_keyword, &local_transformed_results); |
964 // aggressive-scoring curve. | 984 transformed_results = &local_transformed_results; |
965 scored_results = ScoreHistoryResults(results, prevent_inline_autocomplete, | 985 } else { |
966 false, input_text, is_keyword); | 986 // TODO(groby): Once answers is on by default, just pass in scored results. |
967 if ((scored_results.front().relevance() < 1200) || | 987 transformed_results = is_keyword ? &transformed_keyword_history_results_ |
Mark P
2014/09/16 22:24:55
I'd prefer if you could add somewhere (possibly he
groby-ooo-7-16
2014/09/18 23:27:24
I'm not sure I understand why results would be ann
Mark P
2014/09/19 18:45:36
Thank you for the explanation. I see my worry was
| |
968 !HasMultipleWords(scored_results.front().suggestion())) | 988 : &transformed_default_history_results_; |
969 scored_results.clear(); // Didn't detect the case above, score normally. | |
970 } | 989 } |
971 if (scored_results.empty()) | 990 DCHECK(transformed_results); |
972 scored_results = ScoreHistoryResults(results, prevent_inline_autocomplete, | 991 AddTransformedHistoryResultsToMap( |
973 input_multiple_words, input_text, | 992 *transformed_results, did_not_accept_suggestion, map); |
974 is_keyword); | |
975 for (SearchSuggestionParser::SuggestResults::const_iterator i( | |
976 scored_results.begin()); i != scored_results.end(); ++i) { | |
977 AddMatchToMap(*i, std::string(), did_not_accept_suggestion, true, | |
978 providers_.GetKeywordProviderURL() != NULL, map); | |
979 } | |
980 UMA_HISTOGRAM_TIMES("Omnibox.SearchProvider.AddHistoryResultsTime", | 993 UMA_HISTOGRAM_TIMES("Omnibox.SearchProvider.AddHistoryResultsTime", |
981 base::TimeTicks::Now() - start_time); | 994 base::TimeTicks::Now() - start_time); |
982 } | 995 } |
983 | 996 |
997 void SearchProvider::AddTransformedHistoryResultsToMap( | |
998 const SearchSuggestionParser::SuggestResults& transformed_results, | |
999 int did_not_accept_suggestion, | |
1000 MatchMap* map) { | |
1001 for (SearchSuggestionParser::SuggestResults::const_iterator i( | |
1002 transformed_results.begin()); | |
1003 i != transformed_results.end(); | |
1004 ++i) { | |
1005 AddMatchToMap(*i, std::string(), did_not_accept_suggestion, true, | |
1006 providers_.GetKeywordProviderURL() != NULL, map); | |
1007 } | |
1008 } | |
1009 | |
984 SearchSuggestionParser::SuggestResults SearchProvider::ScoreHistoryResults( | 1010 SearchSuggestionParser::SuggestResults SearchProvider::ScoreHistoryResults( |
985 const HistoryResults& results, | 1011 const HistoryResults& results, |
986 bool base_prevent_inline_autocomplete, | 1012 bool base_prevent_inline_autocomplete, |
987 bool input_multiple_words, | 1013 bool input_multiple_words, |
988 const base::string16& input_text, | 1014 const base::string16& input_text, |
989 bool is_keyword) { | 1015 bool is_keyword) { |
990 SearchSuggestionParser::SuggestResults scored_results; | 1016 SearchSuggestionParser::SuggestResults scored_results; |
991 // True if the user has asked this exact query previously. | 1017 // True if the user has asked this exact query previously. |
992 bool found_what_you_typed_match = false; | 1018 bool found_what_you_typed_match = false; |
993 const bool prevent_search_history_inlining = | 1019 const bool prevent_search_history_inlining = |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1085 for (SearchSuggestionParser::SuggestResults::iterator i( | 1111 for (SearchSuggestionParser::SuggestResults::iterator i( |
1086 scored_results.begin()); i != scored_results.end(); ++i) { | 1112 scored_results.begin()); i != scored_results.end(); ++i) { |
1087 if ((last_relevance != 0) && (i->relevance() >= last_relevance)) | 1113 if ((last_relevance != 0) && (i->relevance() >= last_relevance)) |
1088 i->set_relevance(last_relevance - 1); | 1114 i->set_relevance(last_relevance - 1); |
1089 last_relevance = i->relevance(); | 1115 last_relevance = i->relevance(); |
1090 } | 1116 } |
1091 | 1117 |
1092 return scored_results; | 1118 return scored_results; |
1093 } | 1119 } |
1094 | 1120 |
1121 void SearchProvider::ScoreHistoryResultsMultiWord( | |
1122 const HistoryResults& results, | |
1123 bool is_keyword, | |
1124 SearchSuggestionParser::SuggestResults* scored_results) { | |
1125 DCHECK(scored_results); | |
1126 if (results.empty()) { | |
1127 scored_results->clear(); | |
1128 return; | |
1129 } | |
1130 | |
1131 bool prevent_inline_autocomplete = input_.prevent_inline_autocomplete() || | |
1132 (input_.type() == metrics::OmniboxInputType::URL); | |
1133 const base::string16& input_text = GetInput(is_keyword).text(); | |
1134 bool input_multiple_words = HasMultipleWords(input_text); | |
1135 | |
1136 if (!prevent_inline_autocomplete && input_multiple_words) { | |
1137 // ScoreHistoryResults() allows autocompletion of multi-word, 1-visit | |
1138 // queries if the input also has multiple words. But if we were already | |
1139 // scoring a multi-word, multi-visit query aggressively, and the current | |
1140 // input is still a prefix of it, then changing the suggestion suddenly | |
1141 // feels wrong. To detect this case, first score as if only one word has | |
1142 // been typed, then check if the best result came from aggressive search | |
1143 // history scoring. If it did, then just keep that score set. This | |
1144 // 1200 the lowest possible score in CalculateRelevanceForHistory()'s | |
1145 // aggressive-scoring curve. | |
1146 *scored_results = ScoreHistoryResults( | |
1147 results, prevent_inline_autocomplete, false, input_text, is_keyword); | |
1148 if ((scored_results->front().relevance() < 1200) || | |
1149 !HasMultipleWords(scored_results->front().suggestion())) | |
1150 scored_results->clear(); // Didn't detect the case above, score normally. | |
1151 } | |
1152 if (scored_results->empty()) { | |
1153 *scored_results = ScoreHistoryResults(results, | |
1154 prevent_inline_autocomplete, | |
1155 input_multiple_words, | |
1156 input_text, | |
1157 is_keyword); | |
1158 } | |
1159 } | |
1160 | |
1095 void SearchProvider::AddSuggestResultsToMap( | 1161 void SearchProvider::AddSuggestResultsToMap( |
1096 const SearchSuggestionParser::SuggestResults& results, | 1162 const SearchSuggestionParser::SuggestResults& results, |
1097 const std::string& metadata, | 1163 const std::string& metadata, |
1098 MatchMap* map) { | 1164 MatchMap* map) { |
1099 for (size_t i = 0; i < results.size(); ++i) { | 1165 for (size_t i = 0; i < results.size(); ++i) { |
1100 AddMatchToMap(results[i], metadata, i, false, | 1166 AddMatchToMap(results[i], metadata, i, false, |
1101 providers_.GetKeywordProviderURL() != NULL, map); | 1167 providers_.GetKeywordProviderURL() != NULL, map); |
1102 } | 1168 } |
1103 } | 1169 } |
1104 | 1170 |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1326 if (match->answer_contents.empty() && result.size() > 1) | 1392 if (match->answer_contents.empty() && result.size() > 1) |
1327 ++match; | 1393 ++match; |
1328 if (match->answer_contents.empty() || match->answer_type.empty() || | 1394 if (match->answer_contents.empty() || match->answer_type.empty() || |
1329 match->fill_into_edit.empty()) | 1395 match->fill_into_edit.empty()) |
1330 return; | 1396 return; |
1331 | 1397 |
1332 // Valid answer encountered, cache it for further queries. | 1398 // Valid answer encountered, cache it for further queries. |
1333 answers_cache_.UpdateRecentAnswers(match->fill_into_edit, match->answer_type); | 1399 answers_cache_.UpdateRecentAnswers(match->fill_into_edit, match->answer_type); |
1334 } | 1400 } |
1335 | 1401 |
1336 void SearchProvider::DoAnswersQuery(const AutocompleteInput& input) { | 1402 AnswersQueryData SearchProvider::FindAnswersPrefetchData( |
1337 prefetch_data_ = answers_cache_.GetTopAnswerEntry(input.text()); | 1403 const base::string16& input) { |
1404 // Retrieve the top entry from scored history results. | |
1405 | |
1406 // TODO(groby): This seems a bit of a waste. Figure out if we can either | |
1407 // re-use a partially populated map, or if we should just scan through the | |
1408 // results, duplicates be damned. | |
Mark P
2014/09/16 22:24:55
Given that you've discarded this idea (fine by me)
groby-ooo-7-16
2014/09/18 23:27:24
Done.
| |
1409 MatchMap map; | |
1410 // TODO(groby): Can I just default to marking suggestions as "not accepted"? | |
1411 // This seems to only matter for AQS.... | |
Mark P
2014/09/16 22:24:55
I'm comfortable with this here. As I understand i
groby-ooo-7-16
2014/09/18 23:27:24
Correct, so removed comment.
| |
1412 AddTransformedHistoryResultsToMap(transformed_keyword_history_results_, | |
1413 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, | |
1414 &map); | |
1415 AddTransformedHistoryResultsToMap(transformed_default_history_results_, | |
1416 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, | |
1417 &map); | |
1418 | |
1419 ACMatches matches; | |
1420 for (MatchMap::const_iterator i(map.begin()); i != map.end(); ++i) | |
1421 matches.push_back(i->second); | |
1422 std::sort(matches.begin(), matches.end(), &AutocompleteMatch::MoreRelevant); | |
1423 | |
1424 LOG(ERROR) << "SIZE:" << matches.size(); | |
Mark P
2014/09/16 22:24:55
nit: remove unneeded LOG lines
groby-ooo-7-16
2014/09/18 23:27:24
Done.
| |
1425 | |
1426 // If there is a top scoring entry, find the corresponding answer. | |
1427 if (!matches.empty() && | |
1428 StartsWith(matches[0].contents, input, false /* case-insensitive */)) { | |
Mark P
2014/09/16 22:24:55
Minor question: why this is StartsWith necessary?
groby-ooo-7-16
2014/09/18 23:27:24
By missing you mean leaving the test out completel
Mark P
2014/09/19 18:45:36
Yes, search history matches should always be prefi
| |
1429 return answers_cache_.GetTopAnswerEntry(matches[0].contents); | |
1430 } | |
1431 return AnswersQueryData(); | |
1338 } | 1432 } |
OLD | NEW |