summaryrefslogtreecommitdiffstats
path: root/chrome/browser/autocomplete/search_provider.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/autocomplete/search_provider.cc')
-rw-r--r--chrome/browser/autocomplete/search_provider.cc204
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);
}
}