diff options
Diffstat (limited to 'chrome/browser/autocomplete/search_provider.cc')
-rw-r--r-- | chrome/browser/autocomplete/search_provider.cc | 204 |
1 files changed, 136 insertions, 68 deletions
diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc index 45f7803..6c19708 100644 --- a/chrome/browser/autocomplete/search_provider.cc +++ b/chrome/browser/autocomplete/search_provider.cc @@ -118,9 +118,11 @@ const TemplateURL* SearchProvider::Providers::GetKeywordProviderURL() const { // SearchProvider::Result ----------------------------------------------------- SearchProvider::Result::Result(bool from_keyword_provider, - int relevance) + int relevance, + bool relevance_from_server) : from_keyword_provider_(from_keyword_provider), - relevance_(relevance) { + relevance_(relevance), + relevance_from_server_(relevance_from_server) { } SearchProvider::Result::~Result() { @@ -131,8 +133,9 @@ SearchProvider::Result::~Result() { SearchProvider::SuggestResult::SuggestResult(const string16& suggestion, bool from_keyword_provider, - int relevance) - : Result(from_keyword_provider, relevance), + int relevance, + bool relevance_from_server) + : Result(from_keyword_provider, relevance, relevance_from_server), suggestion_(suggestion) { } @@ -159,8 +162,9 @@ SearchProvider::NavigationResult::NavigationResult( const GURL& url, const string16& description, bool from_keyword_provider, - int relevance) - : Result(from_keyword_provider, relevance), + int relevance, + bool relevance_from_server) + : Result(from_keyword_provider, relevance, relevance_from_server), url_(url), formatted_url_(AutocompleteInput::FormattedStringWithEquivalentMeaning( url, provider.StringForURLDisplay(url, true, false))), @@ -196,9 +200,7 @@ class SearchProvider::CompareScoredResults { // SearchProvider::Results ---------------------------------------------------- -SearchProvider::Results::Results() - : has_suggested_relevance(false), - verbatim_relevance(-1) { +SearchProvider::Results::Results() : verbatim_relevance(-1) { } SearchProvider::Results::~Results() { @@ -207,7 +209,6 @@ SearchProvider::Results::~Results() { void SearchProvider::Results::Clear() { suggest_results.clear(); navigation_results.clear(); - has_suggested_relevance = false; verbatim_relevance = -1; } @@ -215,14 +216,33 @@ bool SearchProvider::Results::HasServerProvidedScores() const { if (verbatim_relevance >= 0) return true; - return has_suggested_relevance; + // Right now either all results of one type will be server-scored or they will + // all be locally scored, but in case we change this later, we'll just check + // them all. + for (SuggestResults::const_iterator i(suggest_results.begin()); + i != suggest_results.end(); ++i) { + if (i->relevance_from_server()) + return true; + } + for (NavigationResults::const_iterator i(navigation_results.begin()); + i != navigation_results.end(); ++i) { + if (i->relevance_from_server()) + return true; + } + + return false; } + + // SearchProvider ------------------------------------------------------------- // static const int SearchProvider::kDefaultProviderURLFetcherID = 1; const int SearchProvider::kKeywordProviderURLFetcherID = 2; int SearchProvider::kMinimumTimeBetweenSuggestQueriesMs = 100; +const char SearchProvider::kRelevanceFromServerKey[] = "relevance_from_server"; +const char SearchProvider::kTrue[] = "true"; +const char SearchProvider::kFalse[] = "false"; SearchProvider::SearchProvider(AutocompleteProviderListener* listener, Profile* profile) @@ -394,27 +414,29 @@ void SearchProvider::FinalizeInstantQuery(const string16& input_text, if (suggestion.type == INSTANT_SUGGESTION_SEARCH) { // Instant has a query suggestion. Rank it higher than SEARCH_WHAT_YOU_TYPED // so that it gets autocompleted. - const int verbatim_relevance = GetVerbatimRelevance(); + bool relevance_from_server; + const int verbatim_relevance = GetVerbatimRelevance(&relevance_from_server); int did_not_accept_default_suggestion = default_results_.suggest_results.empty() ? TemplateURLRef::NO_SUGGESTIONS_AVAILABLE : TemplateURLRef::NO_SUGGESTION_CHOSEN; MatchMap match_map; AddMatchToMap(text, adjusted_input_text, verbatim_relevance + 1, - AutocompleteMatchType::SEARCH_SUGGEST, + relevance_from_server, AutocompleteMatchType::SEARCH_SUGGEST, did_not_accept_default_suggestion, false, &match_map); if (!match_map.empty()) { matches_.push_back(match_map.begin()->second); results_updated = true; } } else { - // Instant has a URL suggestion. Rank it higher than URL_WHAT_YOU_TYPED so - // it gets autocompleted; use kNonURLVerbatimRelevance rather than - // verbatim_relevance so that the score does not change if the user keeps - // typing and the input changes from type UNKNOWN to URL. + // Instant has a URL suggestion. Rank it higher than other providers would + // rank URL_WHAT_YOU_TYPED so it gets autocompleted; use + // kNonURLVerbatimRelevance rather than |verbatim_relevance| so that the + // score does not change if the user keeps typing and the input changes from + // type UNKNOWN to URL. matches_.push_back(NavigationToMatch(NavigationResult( *this, GURL(UTF16ToUTF8(suggestion.text)), string16(), false, - kNonURLVerbatimRelevance + 1))); + kNonURLVerbatimRelevance + 1, false))); results_updated = true; } @@ -869,11 +891,11 @@ void SearchProvider::RemoveAllStaleResults() { // and ease in reasoning about the invariants involved, this code // removes stales results from the keyword provider and default // provider independently. - RemoveStaleResults(input_.text(), GetVerbatimRelevance(), + RemoveStaleResults(input_.text(), GetVerbatimRelevance(NULL), &default_results_.suggest_results, &default_results_.navigation_results); if (!keyword_input_.text().empty()) { - RemoveStaleResults(keyword_input_.text(), GetKeywordVerbatimRelevance(), + RemoveStaleResults(keyword_input_.text(), GetKeywordVerbatimRelevance(NULL), &keyword_results_.suggest_results, &keyword_results_.navigation_results); } else { @@ -889,7 +911,7 @@ void SearchProvider::AdjustDefaultProviderSuggestion( if (default_provider_suggestion_.type == INSTANT_SUGGESTION_URL) { // Description and relevance do not matter in the check for staleness. NavigationResult result(*this, GURL(default_provider_suggestion_.text), - string16(), false, 100); + string16(), false, 100, false); // If navigation suggestion is stale, clear |default_provider_suggestion_|. if (!result.IsInlineable(current_input)) default_provider_suggestion_ = InstantSuggestion(); @@ -921,8 +943,6 @@ void SearchProvider::ApplyCalculatedRelevance() { ApplyCalculatedSuggestRelevance(&default_results_.suggest_results); ApplyCalculatedNavigationRelevance(&keyword_results_.navigation_results); ApplyCalculatedNavigationRelevance(&default_results_.navigation_results); - default_results_.has_suggested_relevance = false; - keyword_results_.has_suggested_relevance = false; default_results_.verbatim_relevance = -1; keyword_results_.verbatim_relevance = -1; } @@ -933,6 +953,7 @@ void SearchProvider::ApplyCalculatedSuggestRelevance(SuggestResults* list) { result.set_relevance( result.CalculateRelevance(input_, providers_.has_keyword_provider()) + (list->size() - i - 1)); + result.set_relevance_from_server(false); } } @@ -943,6 +964,7 @@ void SearchProvider::ApplyCalculatedNavigationRelevance( result.set_relevance( result.CalculateRelevance(input_, providers_.has_keyword_provider()) + (list->size() - i - 1)); + result.set_relevance_from_server(false); } } @@ -995,7 +1017,6 @@ bool SearchProvider::ParseSuggestResults(Value* root_val, bool is_keyword) { // Reset suggested relevance information from the default provider. Results* results = is_keyword ? &keyword_results_ : &default_results_; - results->has_suggested_relevance = false; results->verbatim_relevance = -1; // 5th element: Optional key-value pairs from the Suggest server. @@ -1042,13 +1063,13 @@ bool SearchProvider::ParseSuggestResults(Value* root_val, bool is_keyword) { if (url.is_valid()) { if (descriptions != NULL) descriptions->GetString(index, &title); - results->navigation_results.push_back( - NavigationResult(*this, url, title, is_keyword, relevance)); + results->navigation_results.push_back(NavigationResult( + *this, url, title, is_keyword, relevance, true)); } } else { // TODO(kochi): Improve calculator result presentation. results->suggest_results.push_back( - SuggestResult(result, is_keyword, relevance)); + SuggestResult(result, is_keyword, relevance, true)); } } @@ -1056,8 +1077,6 @@ bool SearchProvider::ParseSuggestResults(Value* root_val, bool is_keyword) { if (relevances == NULL) { ApplyCalculatedSuggestRelevance(&results->suggest_results); ApplyCalculatedNavigationRelevance(&results->navigation_results); - } else { - results->has_suggested_relevance = true; } // Keep the result lists sorted. const CompareScoredResults comparator = CompareScoredResults(); @@ -1080,13 +1099,15 @@ void SearchProvider::ConvertResultsToAutocompleteMatches() { TemplateURLRef::NO_SUGGESTIONS_AVAILABLE : TemplateURLRef::NO_SUGGESTION_CHOSEN; - int verbatim_relevance = GetVerbatimRelevance(); + bool relevance_from_server; + int verbatim_relevance = GetVerbatimRelevance(&relevance_from_server); int did_not_accept_default_suggestion = default_results_.suggest_results.empty() ? TemplateURLRef::NO_SUGGESTIONS_AVAILABLE : TemplateURLRef::NO_SUGGESTION_CHOSEN; if (verbatim_relevance > 0) { AddMatchToMap(input_.text(), input_.text(), verbatim_relevance, + relevance_from_server, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, did_not_accept_default_suggestion, false, &map); } @@ -1099,21 +1120,22 @@ void SearchProvider::ConvertResultsToAutocompleteMatches() { // to the keyword verbatim search query. Do not create other matches // of type SEARCH_OTHER_ENGINE. if (keyword_url && !keyword_url->IsExtensionKeyword()) { - const int keyword_verbatim_relevance = GetKeywordVerbatimRelevance(); + bool keyword_relevance_from_server; + const int keyword_verbatim_relevance = + GetKeywordVerbatimRelevance(&keyword_relevance_from_server); if (keyword_verbatim_relevance > 0) { AddMatchToMap(keyword_input_.text(), keyword_input_.text(), - keyword_verbatim_relevance, + keyword_verbatim_relevance, keyword_relevance_from_server, AutocompleteMatchType::SEARCH_OTHER_ENGINE, did_not_accept_keyword_suggestion, true, &map); } } } - const size_t verbatim_matches_size = map.size(); if (!default_provider_suggestion_.text.empty() && default_provider_suggestion_.type == INSTANT_SUGGESTION_SEARCH && !input_.prevent_inline_autocomplete()) AddMatchToMap(input_.text() + default_provider_suggestion_.text, - input_.text(), verbatim_relevance + 1, + input_.text(), verbatim_relevance + 1, relevance_from_server, AutocompleteMatchType::SEARCH_SUGGEST, did_not_accept_default_suggestion, false, &map); @@ -1125,31 +1147,58 @@ void SearchProvider::ConvertResultsToAutocompleteMatches() { AddSuggestResultsToMap(keyword_results_.suggest_results, &map); AddSuggestResultsToMap(default_results_.suggest_results, &map); - // Now add the most relevant matches from the map to |matches_|. - matches_.clear(); + ACMatches matches; for (MatchMap::const_iterator i(map.begin()); i != map.end(); ++i) - matches_.push_back(i->second); + matches.push_back(i->second); if (!default_provider_suggestion_.text.empty() && default_provider_suggestion_.type == INSTANT_SUGGESTION_URL && !input_.prevent_inline_autocomplete()) { // See comment in FinalizeInstantQuery() for why we don't use // |verbatim_relevance| here. - matches_.push_back(NavigationToMatch(NavigationResult( + matches.push_back(NavigationToMatch(NavigationResult( *this, GURL(UTF16ToUTF8(default_provider_suggestion_.text)), string16(), - false, kNonURLVerbatimRelevance + 1))); + false, kNonURLVerbatimRelevance + 1, false))); } - AddNavigationResultsToMatches(keyword_results_.navigation_results); - AddNavigationResultsToMatches(default_results_.navigation_results); + AddNavigationResultsToMatches(keyword_results_.navigation_results, &matches); + AddNavigationResultsToMatches(default_results_.navigation_results, &matches); + + // Now add the most relevant matches to |matches_|. We take up to kMaxMatches + // suggest/navsuggest matches, regardless of origin. If Instant Extended is + // enabled and we have server-provided (and thus hopefully more accurate) + // scores for some suggestions, we allow more of those, until we reach + // AutocompleteResult::kMaxMatches total matches (that is, enough to fill the + // whole popup). + // + // We will always return any verbatim matches, no matter how we obtained their + // scores, unless we have already accepted AutocompleteResult::kMaxMatches + // higher-scoring matches under the conditions above. + std::sort(matches.begin(), matches.end(), &AutocompleteMatch::MoreRelevant); + matches_.clear(); + + size_t num_suggestions = 0; + for (ACMatches::const_iterator i(matches.begin()); + (i != matches.end()) && + (matches_.size() < AutocompleteResult::kMaxMatches); + ++i) { + // SEARCH_OTHER_ENGINE is only used in the SearchProvider for the keyword + // verbatim result, so this condition basically means "if this match is a + // suggestion of some sort". + if ((i->type != AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED) && + (i->type != AutocompleteMatchType::SEARCH_OTHER_ENGINE)) { + // If we've already hit the limit on non-server-scored suggestions, and + // this isn't a server-scored suggestion we can add, skip it. + if ((num_suggestions >= kMaxMatches) && + (!chrome::IsInstantExtendedAPIEnabled() || + (i->GetAdditionalInfo(kRelevanceFromServerKey) != kTrue))) { + continue; + } - // Allow additional match(es) for verbatim results if present. - const size_t max_total_matches = kMaxMatches + verbatim_matches_size; - std::partial_sort(matches_.begin(), - matches_.begin() + std::min(max_total_matches, matches_.size()), - matches_.end(), &AutocompleteMatch::MoreRelevant); + ++num_suggestions; + } - if (matches_.size() > max_total_matches) - matches_.resize(max_total_matches); + matches_.push_back(*i); + } } bool SearchProvider::IsTopMatchNavigationInKeywordMode() const { @@ -1186,7 +1235,6 @@ bool SearchProvider::IsTopMatchNotInlinable() const { // not create any other match of type SEARCH_OTHER_ENGINE. return matches_.front().type != AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED && - matches_.front().type != AutocompleteMatchType::URL_WHAT_YOU_TYPED && matches_.front().type != AutocompleteMatchType::SEARCH_OTHER_ENGINE && matches_.front().inline_autocomplete_offset == string16::npos && matches_.front().fill_into_edit != input_.text(); @@ -1235,11 +1283,10 @@ void SearchProvider::UpdateMatches() { ConvertResultsToAutocompleteMatches(); } if (IsTopMatchNotInlinable()) { - // Disregard suggested relevances if the top match is not a verbatim - // match, inlinable, or URL_WHAT_YOU_TYPED (which may be top match - // regardless of inlining). For example, input "foo" should not - // invoke a search for "bar", which would happen if the "bar" search - // match outranked all other matches. + // Disregard suggested relevances if the top match is not a verbatim match + // or inlinable. For example, input "foo" should not invoke a search for + // "bar", which would happen if the "bar" search match outranked all other + // matches. ApplyCalculatedRelevance(); ConvertResultsToAutocompleteMatches(); } @@ -1254,15 +1301,14 @@ void SearchProvider::UpdateMatches() { } void SearchProvider::AddNavigationResultsToMatches( - const NavigationResults& navigation_results) { + const NavigationResults& navigation_results, + ACMatches* matches) { for (NavigationResults::const_iterator it = navigation_results.begin(); it != navigation_results.end(); ++it) { - matches_.push_back(NavigationToMatch(*it)); + matches->push_back(NavigationToMatch(*it)); // In the absence of suggested relevance scores, use only the single // highest-scoring result. (The results are already sorted by relevance.) - if (!(it->from_keyword_provider() ? - keyword_results_.has_suggested_relevance : - default_results_.has_suggested_relevance)) + if (!it->relevance_from_server()) return; } } @@ -1302,7 +1348,7 @@ void SearchProvider::AddHistoryResultsToMap(const HistoryResults& results, is_keyword); for (SuggestResults::const_iterator i(scored_results.begin()); i != scored_results.end(); ++i) { - AddMatchToMap(i->suggestion(), input_text, i->relevance(), + AddMatchToMap(i->suggestion(), input_text, i->relevance(), false, AutocompleteMatchType::SEARCH_HISTORY, did_not_accept_suggestion, is_keyword, map); @@ -1347,7 +1393,8 @@ SearchProvider::SuggestResults SearchProvider::ScoreHistoryResults( int relevance = CalculateRelevanceForHistory(i->time, is_keyword, prevent_inline_autocomplete); - scored_results.push_back(SuggestResult(i->term, is_keyword, relevance)); + scored_results.push_back( + SuggestResult(i->term, is_keyword, relevance, false)); } // History returns results sorted for us. However, we may have docked some @@ -1374,11 +1421,12 @@ void SearchProvider::AddSuggestResultsToMap(const SuggestResults& results, const bool is_keyword = results[i].from_keyword_provider(); const string16& input = is_keyword ? keyword_input_.text() : input_.text(); AddMatchToMap(results[i].suggestion(), input, results[i].relevance(), + results[i].relevance_from_server(), AutocompleteMatchType::SEARCH_SUGGEST, i, is_keyword, map); } } -int SearchProvider::GetVerbatimRelevance() const { +int SearchProvider::GetVerbatimRelevance(bool* relevance_from_server) const { // Use the suggested verbatim relevance score if it is non-negative (valid), // if inline autocomplete isn't prevented (always show verbatim on backspace), // and if it won't suppress verbatim, leaving no default provider matches. @@ -1393,6 +1441,8 @@ int SearchProvider::GetVerbatimRelevance() const { ((default_results_.verbatim_relevance > 0) || !default_results_.suggest_results.empty() || !default_results_.navigation_results.empty()); + if (relevance_from_server) + *relevance_from_server = use_server_relevance; return use_server_relevance ? default_results_.verbatim_relevance : CalculateRelevanceForVerbatim(); } @@ -1420,7 +1470,8 @@ int SearchProvider:: } } -int SearchProvider::GetKeywordVerbatimRelevance() const { +int SearchProvider::GetKeywordVerbatimRelevance( + bool* relevance_from_server) const { // Use the suggested verbatim relevance score if it is non-negative (valid), // if inline autocomplete isn't prevented (always show verbatim on backspace), // and if it won't suppress verbatim, leaving no keyword provider matches. @@ -1435,6 +1486,8 @@ int SearchProvider::GetKeywordVerbatimRelevance() const { ((keyword_results_.verbatim_relevance > 0) || !keyword_results_.suggest_results.empty() || !keyword_results_.navigation_results.empty()); + if (relevance_from_server) + *relevance_from_server = use_server_relevance; return use_server_relevance ? keyword_results_.verbatim_relevance : CalculateRelevanceForKeywordVerbatim(keyword_input_.type(), @@ -1479,6 +1532,7 @@ int SearchProvider::CalculateRelevanceForHistory( void SearchProvider::AddMatchToMap(const string16& query_string, const string16& input_text, int relevance, + bool relevance_from_server, AutocompleteMatch::Type type, int accepted_suggestion, bool is_keyword, @@ -1487,7 +1541,7 @@ void SearchProvider::AddMatchToMap(const string16& query_string, // -- they should always use grey text if they are to autocomplete at all. So // we clamp non-verbatim results to just below the verbatim score to ensure // that none of them are inline autocompleted. - // TODO(pkasting): This shouldn't depend on instant extended. If we think + // TODO(pkasting): This shouldn't depend on Instant Extended. If we think // this change is a win, let's change the suggest server to not send // high-ranking suggest scores, and change CalculateRelevanceForHistory() to // use lower curves. This code is also buggy as-is because it can demote many @@ -1505,6 +1559,8 @@ void SearchProvider::AddMatchToMap(const string16& query_string, is_keyword, keyword, omnibox_start_margin_); if (!match.destination_url.is_valid()) return; + match.RecordAdditionalInfo(kRelevanceFromServerKey, + relevance_from_server ? kTrue : kFalse); // Try to add |match| to |map|. If a match for |query_string| is already in // |map|, replace it if |match| is more relevant. @@ -1580,17 +1636,28 @@ AutocompleteMatch SearchProvider::NavigationToMatch( match.description = navigation.description(); AutocompleteMatch::ClassifyMatchInString(input, match.description, ACMatchClassification::NONE, &match.description_class); + + match.RecordAdditionalInfo( + kRelevanceFromServerKey, + navigation.relevance_from_server() ? kTrue : kFalse); + return match; } void SearchProvider::DemoteKeywordNavigationMatchesPastTopQuery() { // First, determine the maximum score of any keyword query match (verbatim or // query suggestion). - int max_query_relevance = GetKeywordVerbatimRelevance(); + bool relevance_from_server; + int max_query_relevance = GetKeywordVerbatimRelevance(&relevance_from_server); if (!keyword_results_.suggest_results.empty()) { - max_query_relevance = - std::max(keyword_results_.suggest_results.front().relevance(), - max_query_relevance); + const SuggestResult& top_keyword = keyword_results_.suggest_results.front(); + const int suggest_relevance = top_keyword.relevance(); + if (suggest_relevance > max_query_relevance) { + max_query_relevance = suggest_relevance; + relevance_from_server = top_keyword.relevance_from_server(); + } else if (suggest_relevance == max_query_relevance) { + relevance_from_server |= top_keyword.relevance_from_server(); + } } // If no query is supposed to appear, then navigational matches cannot // be demoted past it. Get rid of suggested relevance scores for @@ -1614,6 +1681,7 @@ void SearchProvider::DemoteKeywordNavigationMatchesPastTopQuery() { return; max_query_relevance = std::max(max_query_relevance - 1, 0); it->set_relevance(max_query_relevance); + it->set_relevance_from_server(relevance_from_server); } } |