Commit e5fcee48 authored by groby's avatar groby Committed by Commit bot

[AiS] Use top local result for prefetch.

For answers prefetching, Chrome needs to know what the top search history
result for the current input is - _before_ issuing a search engine query
for that same input

BUG=406588

Review URL: https://codereview.chromium.org/470313004

Cr-Commit-Position: refs/heads/master@{#296873}
parent 83d08a29
...@@ -3409,16 +3409,22 @@ TEST_F(SearchProviderTest, AnswersCache) { ...@@ -3409,16 +3409,22 @@ TEST_F(SearchProviderTest, AnswersCache) {
provider_->RegisterDisplayedAnswers(result); provider_->RegisterDisplayedAnswers(result);
ASSERT_FALSE(provider_->answers_cache_.empty()); ASSERT_FALSE(provider_->answers_cache_.empty());
// Test that DoAnswersQuery retrieves data from cache. // Without scored results, no answers will be retrieved.
AutocompleteInput input(base::ASCIIToUTF16("weather l"), AnswersQueryData answer = provider_->FindAnswersPrefetchData();
base::string16::npos, base::string16(), GURL(), EXPECT_TRUE(answer.full_query_text.empty());
metrics::OmniboxEventProto::INVALID_SPEC, false, EXPECT_TRUE(answer.query_type.empty());
false, true, true,
ChromeAutocompleteSchemeClassifier(&profile_)); // Inject a scored result, which will trigger answer retrieval.
provider_->DoAnswersQuery(input); base::string16 query = base::ASCIIToUTF16("weather los angeles");
EXPECT_EQ(base::ASCIIToUTF16("weather los angeles"), SearchSuggestionParser::SuggestResult suggest_result(
provider_->prefetch_data_.full_query_text); query, AutocompleteMatchType::SEARCH_HISTORY, query, base::string16(),
EXPECT_EQ(base::ASCIIToUTF16("2334"), provider_->prefetch_data_.query_type); base::string16(), base::string16(), base::string16(), std::string(),
std::string(), false, 1200, false, false, query);
QueryForInput(ASCIIToUTF16("weather l"), false, false);
provider_->transformed_default_history_results_.push_back(suggest_result);
answer = provider_->FindAnswersPrefetchData();
EXPECT_EQ(base::ASCIIToUTF16("weather los angeles"), answer.full_query_text);
EXPECT_EQ(base::ASCIIToUTF16("2334"), answer.query_type);
} }
TEST_F(SearchProviderTest, RemoveExtraAnswers) { TEST_F(SearchProviderTest, RemoveExtraAnswers) {
......
...@@ -265,7 +265,26 @@ void SearchProvider::Start(const AutocompleteInput& input, ...@@ -265,7 +265,26 @@ void SearchProvider::Start(const AutocompleteInput& input,
input_ = input; input_ = input;
DoHistoryQuery(minimal_changes); DoHistoryQuery(minimal_changes);
DoAnswersQuery(input); // Answers needs scored history results before any suggest query has been
// started, since the query for answer-bearing results needs additional
// prefetch information based on the highest-scored local history result.
if (OmniboxFieldTrial::EnableAnswersInSuggest()) {
ScoreHistoryResults(raw_default_history_results_,
false,
&transformed_default_history_results_);
ScoreHistoryResults(raw_keyword_history_results_,
true,
&transformed_keyword_history_results_);
prefetch_data_ = FindAnswersPrefetchData();
// Raw results are not needed any more.
raw_default_history_results_.clear();
raw_keyword_history_results_.clear();
} else {
transformed_default_history_results_.clear();
transformed_keyword_history_results_.clear();
}
StartOrStopSuggestQuery(minimal_changes); StartOrStopSuggestQuery(minimal_changes);
UpdateMatches(); UpdateMatches();
} }
...@@ -519,8 +538,8 @@ void SearchProvider::DoHistoryQuery(bool minimal_changes) { ...@@ -519,8 +538,8 @@ void SearchProvider::DoHistoryQuery(bool minimal_changes) {
if (minimal_changes) if (minimal_changes)
return; return;
keyword_history_results_.clear(); raw_keyword_history_results_.clear();
default_history_results_.clear(); raw_default_history_results_.clear();
if (OmniboxFieldTrial::SearchHistoryDisable( if (OmniboxFieldTrial::SearchHistoryDisable(
input_.current_page_classification())) input_.current_page_classification()))
...@@ -533,7 +552,7 @@ void SearchProvider::DoHistoryQuery(bool minimal_changes) { ...@@ -533,7 +552,7 @@ void SearchProvider::DoHistoryQuery(bool minimal_changes) {
// Request history for both the keyword and default provider. We grab many // Request history for both the keyword and default provider. We grab many
// more matches than we'll ultimately clamp to so that if there are several // more matches than we'll ultimately clamp to so that if there are several
// recent multi-word matches who scores are lowered (see // recent multi-word matches who scores are lowered (see
// AddHistoryResultsToMap()), they won't crowd out older, higher-scoring // ScoreHistoryResults()), they won't crowd out older, higher-scoring
// matches. Note that this doesn't fix the problem entirely, but merely // matches. Note that this doesn't fix the problem entirely, but merely
// limits it to cases with a very large number of such multi-word matches; for // limits it to cases with a very large number of such multi-word matches; for
// now, this seems OK compared with the complexity of a real fix, which would // now, this seems OK compared with the complexity of a real fix, which would
...@@ -543,8 +562,10 @@ void SearchProvider::DoHistoryQuery(bool minimal_changes) { ...@@ -543,8 +562,10 @@ void SearchProvider::DoHistoryQuery(bool minimal_changes) {
const TemplateURL* default_url = providers_.GetDefaultProviderURL(); const TemplateURL* default_url = providers_.GetDefaultProviderURL();
if (default_url) { if (default_url) {
const base::TimeTicks start_time = base::TimeTicks::Now(); const base::TimeTicks start_time = base::TimeTicks::Now();
url_db->GetMostRecentKeywordSearchTerms(default_url->id(), input_.text(), url_db->GetMostRecentKeywordSearchTerms(default_url->id(),
num_matches, &default_history_results_); input_.text(),
num_matches,
&raw_default_history_results_);
UMA_HISTOGRAM_TIMES( UMA_HISTOGRAM_TIMES(
"Omnibox.SearchProvider.GetMostRecentKeywordTermsDefaultProviderTime", "Omnibox.SearchProvider.GetMostRecentKeywordTermsDefaultProviderTime",
base::TimeTicks::Now() - start_time); base::TimeTicks::Now() - start_time);
...@@ -552,7 +573,9 @@ void SearchProvider::DoHistoryQuery(bool minimal_changes) { ...@@ -552,7 +573,9 @@ void SearchProvider::DoHistoryQuery(bool minimal_changes) {
const TemplateURL* keyword_url = providers_.GetKeywordProviderURL(); const TemplateURL* keyword_url = providers_.GetKeywordProviderURL();
if (keyword_url) { if (keyword_url) {
url_db->GetMostRecentKeywordSearchTerms(keyword_url->id(), url_db->GetMostRecentKeywordSearchTerms(keyword_url->id(),
keyword_input_.text(), num_matches, &keyword_history_results_); keyword_input_.text(),
num_matches,
&raw_keyword_history_results_);
} }
} }
...@@ -844,10 +867,8 @@ void SearchProvider::ConvertResultsToAutocompleteMatches() { ...@@ -844,10 +867,8 @@ void SearchProvider::ConvertResultsToAutocompleteMatches() {
} }
} }
} }
AddHistoryResultsToMap(keyword_history_results_, true, AddRawHistoryResultsToMap(true, did_not_accept_keyword_suggestion, &map);
did_not_accept_keyword_suggestion, &map); AddRawHistoryResultsToMap(false, did_not_accept_default_suggestion, &map);
AddHistoryResultsToMap(default_history_results_, false,
did_not_accept_default_suggestion, &map);
AddSuggestResultsToMap(keyword_results_.suggest_results, AddSuggestResultsToMap(keyword_results_.suggest_results,
keyword_results_.metadata, &map); keyword_results_.metadata, &map);
...@@ -960,52 +981,52 @@ void SearchProvider::AddNavigationResultsToMatches( ...@@ -960,52 +981,52 @@ void SearchProvider::AddNavigationResultsToMatches(
} }
} }
void SearchProvider::AddHistoryResultsToMap(const HistoryResults& results, void SearchProvider::AddRawHistoryResultsToMap(bool is_keyword,
bool is_keyword,
int did_not_accept_suggestion, int did_not_accept_suggestion,
MatchMap* map) { MatchMap* map) {
if (results.empty()) const HistoryResults& raw_results =
is_keyword ? raw_keyword_history_results_ : raw_default_history_results_;
if (!OmniboxFieldTrial::EnableAnswersInSuggest() && raw_results.empty())
return; return;
base::TimeTicks start_time(base::TimeTicks::Now()); base::TimeTicks start_time(base::TimeTicks::Now());
bool prevent_inline_autocomplete = input_.prevent_inline_autocomplete() ||
(input_.type() == metrics::OmniboxInputType::URL);
const base::string16& input_text =
is_keyword ? keyword_input_.text() : input_.text();
bool input_multiple_words = HasMultipleWords(input_text);
SearchSuggestionParser::SuggestResults scored_results; // Until Answers becomes default, scoring of history results will still happen
if (!prevent_inline_autocomplete && input_multiple_words) { // here for non-Answers Chrome, to prevent scoring performance regressions
// ScoreHistoryResults() allows autocompletion of multi-word, 1-visit // resulting from moving the scoring code before the suggest request is sent.
// queries if the input also has multiple words. But if we were already // For users with Answers enabled, the history results have already been
// scoring a multi-word, multi-visit query aggressively, and the current // scored earlier, right after calling DoHistoryQuery().
// input is still a prefix of it, then changing the suggestion suddenly SearchSuggestionParser::SuggestResults local_transformed_results;
// feels wrong. To detect this case, first score as if only one word has const SearchSuggestionParser::SuggestResults* transformed_results = NULL;
// been typed, then check if the best result came from aggressive search if (!OmniboxFieldTrial::EnableAnswersInSuggest()) {
// history scoring. If it did, then just keep that score set. This ScoreHistoryResults(raw_results, is_keyword, &local_transformed_results);
// 1200 the lowest possible score in CalculateRelevanceForHistory()'s transformed_results = &local_transformed_results;
// aggressive-scoring curve. } else {
scored_results = ScoreHistoryResults(results, prevent_inline_autocomplete, transformed_results = is_keyword ? &transformed_keyword_history_results_
false, input_text, is_keyword); : &transformed_default_history_results_;
if ((scored_results.front().relevance() < 1200) || }
!HasMultipleWords(scored_results.front().suggestion())) DCHECK(transformed_results);
scored_results.clear(); // Didn't detect the case above, score normally. AddTransformedHistoryResultsToMap(
} *transformed_results, did_not_accept_suggestion, map);
if (scored_results.empty()) UMA_HISTOGRAM_TIMES("Omnibox.SearchProvider.AddHistoryResultsTime",
scored_results = ScoreHistoryResults(results, prevent_inline_autocomplete, base::TimeTicks::Now() - start_time);
input_multiple_words, input_text, }
is_keyword);
void SearchProvider::AddTransformedHistoryResultsToMap(
const SearchSuggestionParser::SuggestResults& transformed_results,
int did_not_accept_suggestion,
MatchMap* map) {
for (SearchSuggestionParser::SuggestResults::const_iterator i( for (SearchSuggestionParser::SuggestResults::const_iterator i(
scored_results.begin()); i != scored_results.end(); ++i) { transformed_results.begin());
i != transformed_results.end();
++i) {
AddMatchToMap(*i, std::string(), did_not_accept_suggestion, true, AddMatchToMap(*i, std::string(), did_not_accept_suggestion, true,
providers_.GetKeywordProviderURL() != NULL, map); providers_.GetKeywordProviderURL() != NULL, map);
} }
UMA_HISTOGRAM_TIMES("Omnibox.SearchProvider.AddHistoryResultsTime",
base::TimeTicks::Now() - start_time);
} }
SearchSuggestionParser::SuggestResults SearchProvider::ScoreHistoryResults( SearchSuggestionParser::SuggestResults
const HistoryResults& results, SearchProvider::ScoreHistoryResultsHelper(const HistoryResults& results,
bool base_prevent_inline_autocomplete, bool base_prevent_inline_autocomplete,
bool input_multiple_words, bool input_multiple_words,
const base::string16& input_text, const base::string16& input_text,
...@@ -1115,6 +1136,46 @@ SearchSuggestionParser::SuggestResults SearchProvider::ScoreHistoryResults( ...@@ -1115,6 +1136,46 @@ SearchSuggestionParser::SuggestResults SearchProvider::ScoreHistoryResults(
return scored_results; return scored_results;
} }
void SearchProvider::ScoreHistoryResults(
const HistoryResults& results,
bool is_keyword,
SearchSuggestionParser::SuggestResults* scored_results) {
DCHECK(scored_results);
if (results.empty()) {
scored_results->clear();
return;
}
bool prevent_inline_autocomplete = input_.prevent_inline_autocomplete() ||
(input_.type() == metrics::OmniboxInputType::URL);
const base::string16 input_text = GetInput(is_keyword).text();
bool input_multiple_words = HasMultipleWords(input_text);
if (!prevent_inline_autocomplete && input_multiple_words) {
// ScoreHistoryResultsHelper() allows autocompletion of multi-word, 1-visit
// queries if the input also has multiple words. But if we were already
// scoring a multi-word, multi-visit query aggressively, and the current
// input is still a prefix of it, then changing the suggestion suddenly
// feels wrong. To detect this case, first score as if only one word has
// been typed, then check if the best result came from aggressive search
// history scoring. If it did, then just keep that score set. This
// 1200 the lowest possible score in CalculateRelevanceForHistory()'s
// aggressive-scoring curve.
*scored_results = ScoreHistoryResultsHelper(
results, prevent_inline_autocomplete, false, input_text, is_keyword);
if ((scored_results->front().relevance() < 1200) ||
!HasMultipleWords(scored_results->front().suggestion()))
scored_results->clear(); // Didn't detect the case above, score normally.
}
if (scored_results->empty()) {
*scored_results = ScoreHistoryResultsHelper(results,
prevent_inline_autocomplete,
input_multiple_words,
input_text,
is_keyword);
}
}
void SearchProvider::AddSuggestResultsToMap( void SearchProvider::AddSuggestResultsToMap(
const SearchSuggestionParser::SuggestResults& results, const SearchSuggestionParser::SuggestResults& results,
const std::string& metadata, const std::string& metadata,
...@@ -1356,6 +1417,24 @@ void SearchProvider::RegisterDisplayedAnswers( ...@@ -1356,6 +1417,24 @@ void SearchProvider::RegisterDisplayedAnswers(
answers_cache_.UpdateRecentAnswers(match->fill_into_edit, match->answer_type); answers_cache_.UpdateRecentAnswers(match->fill_into_edit, match->answer_type);
} }
void SearchProvider::DoAnswersQuery(const AutocompleteInput& input) { AnswersQueryData SearchProvider::FindAnswersPrefetchData() {
prefetch_data_ = answers_cache_.GetTopAnswerEntry(input.text()); // Retrieve the top entry from scored history results.
MatchMap map;
AddTransformedHistoryResultsToMap(transformed_keyword_history_results_,
TemplateURLRef::NO_SUGGESTIONS_AVAILABLE,
&map);
AddTransformedHistoryResultsToMap(transformed_default_history_results_,
TemplateURLRef::NO_SUGGESTIONS_AVAILABLE,
&map);
ACMatches matches;
for (MatchMap::const_iterator i(map.begin()); i != map.end(); ++i)
matches.push_back(i->second);
std::sort(matches.begin(), matches.end(), &AutocompleteMatch::MoreRelevant);
// If there is a top scoring entry, find the corresponding answer.
if (!matches.empty())
return answers_cache_.GetTopAnswerEntry(matches[0].contents);
return AnswersQueryData();
} }
...@@ -254,21 +254,35 @@ class SearchProvider : public BaseSearchProvider, ...@@ -254,21 +254,35 @@ class SearchProvider : public BaseSearchProvider,
const SearchSuggestionParser::NavigationResults& navigation_results, const SearchSuggestionParser::NavigationResults& navigation_results,
ACMatches* matches); ACMatches* matches);
// Adds a match for each result in |results| to |map|. |is_keyword| indicates // Adds a match for each result in |raw_default_history_results_| or
// whether the results correspond to the keyword provider or default provider. // |raw_keyword_history_results_| to |map|. |is_keyword| indicates
void AddHistoryResultsToMap(const HistoryResults& results, // which one of the two.
bool is_keyword, void AddRawHistoryResultsToMap(bool is_keyword,
int did_not_accept_suggestion,
MatchMap* map);
// Adds a match for each transformed result in |results| to |map|.
void AddTransformedHistoryResultsToMap(
const SearchSuggestionParser::SuggestResults& results,
int did_not_accept_suggestion, int did_not_accept_suggestion,
MatchMap* map); MatchMap* map);
// Calculates relevance scores for all |results|. // Calculates relevance scores for all |results|.
SearchSuggestionParser::SuggestResults ScoreHistoryResults( SearchSuggestionParser::SuggestResults ScoreHistoryResultsHelper(
const HistoryResults& results, const HistoryResults& results,
bool base_prevent_inline_autocomplete, bool base_prevent_inline_autocomplete,
bool input_multiple_words, bool input_multiple_words,
const base::string16& input_text, const base::string16& input_text,
bool is_keyword); bool is_keyword);
// Calculates relevance scores for |results|, adjusting for boundary
// conditions around multi-word queries. (See inline comments in function
// definition for more details.)
void ScoreHistoryResults(
const HistoryResults& results,
bool is_keyword,
SearchSuggestionParser::SuggestResults* scored_results);
// Adds matches for |results| to |map|. // Adds matches for |results| to |map|.
void AddSuggestResultsToMap( void AddSuggestResultsToMap(
const SearchSuggestionParser::SuggestResults& results, const SearchSuggestionParser::SuggestResults& results,
...@@ -321,9 +335,11 @@ class SearchProvider : public BaseSearchProvider, ...@@ -321,9 +335,11 @@ class SearchProvider : public BaseSearchProvider,
// Obtains a session token, regenerating if necessary. // Obtains a session token, regenerating if necessary.
std::string GetSessionToken(); std::string GetSessionToken();
// Answers prefetch handling - finds previously displayed answer matching the // Answers prefetch handling - finds the previously displayed answer matching
// current |input| and sets |prefetch_data_|. // the current top-scoring history result. If there is a previous answer,
void DoAnswersQuery(const AutocompleteInput& input); // returns the query data associated with it. Otherwise, returns an empty
// AnswersQueryData.
AnswersQueryData FindAnswersPrefetchData();
// The amount of time to wait before sending a new suggest request after the // The amount of time to wait before sending a new suggest request after the
// previous one. Non-const because some unittests modify this value. // previous one. Non-const because some unittests modify this value.
...@@ -345,8 +361,13 @@ class SearchProvider : public BaseSearchProvider, ...@@ -345,8 +361,13 @@ class SearchProvider : public BaseSearchProvider,
AutocompleteInput keyword_input_; AutocompleteInput keyword_input_;
// Searches in the user's history that begin with the input text. // Searches in the user's history that begin with the input text.
HistoryResults keyword_history_results_; HistoryResults raw_keyword_history_results_;
HistoryResults default_history_results_; HistoryResults raw_default_history_results_;
// Scored searches in the user's history - based on |keyword_history_results_|
// or |default_history_results_| as appropriate.
SearchSuggestionParser::SuggestResults transformed_keyword_history_results_;
SearchSuggestionParser::SuggestResults transformed_default_history_results_;
// A timer to start a query to the suggest server after the user has stopped // A timer to start a query to the suggest server after the user has stopped
// typing for long enough. // typing for long enough.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment