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) {
provider_->RegisterDisplayedAnswers(result);
ASSERT_FALSE(provider_->answers_cache_.empty());
// Test that DoAnswersQuery retrieves data from cache.
AutocompleteInput input(base::ASCIIToUTF16("weather l"),
base::string16::npos, base::string16(), GURL(),
metrics::OmniboxEventProto::INVALID_SPEC, false,
false, true, true,
ChromeAutocompleteSchemeClassifier(&profile_));
provider_->DoAnswersQuery(input);
EXPECT_EQ(base::ASCIIToUTF16("weather los angeles"),
provider_->prefetch_data_.full_query_text);
EXPECT_EQ(base::ASCIIToUTF16("2334"), provider_->prefetch_data_.query_type);
// Without scored results, no answers will be retrieved.
AnswersQueryData answer = provider_->FindAnswersPrefetchData();
EXPECT_TRUE(answer.full_query_text.empty());
EXPECT_TRUE(answer.query_type.empty());
// Inject a scored result, which will trigger answer retrieval.
base::string16 query = base::ASCIIToUTF16("weather los angeles");
SearchSuggestionParser::SuggestResult suggest_result(
query, AutocompleteMatchType::SEARCH_HISTORY, query, base::string16(),
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) {
......
......@@ -265,7 +265,26 @@ void SearchProvider::Start(const AutocompleteInput& input,
input_ = input;
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);
UpdateMatches();
}
......@@ -519,8 +538,8 @@ void SearchProvider::DoHistoryQuery(bool minimal_changes) {
if (minimal_changes)
return;
keyword_history_results_.clear();
default_history_results_.clear();
raw_keyword_history_results_.clear();
raw_default_history_results_.clear();
if (OmniboxFieldTrial::SearchHistoryDisable(
input_.current_page_classification()))
......@@ -533,7 +552,7 @@ void SearchProvider::DoHistoryQuery(bool minimal_changes) {
// 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
// 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
// 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
......@@ -543,8 +562,10 @@ void SearchProvider::DoHistoryQuery(bool minimal_changes) {
const TemplateURL* default_url = providers_.GetDefaultProviderURL();
if (default_url) {
const base::TimeTicks start_time = base::TimeTicks::Now();
url_db->GetMostRecentKeywordSearchTerms(default_url->id(), input_.text(),
num_matches, &default_history_results_);
url_db->GetMostRecentKeywordSearchTerms(default_url->id(),
input_.text(),
num_matches,
&raw_default_history_results_);
UMA_HISTOGRAM_TIMES(
"Omnibox.SearchProvider.GetMostRecentKeywordTermsDefaultProviderTime",
base::TimeTicks::Now() - start_time);
......@@ -552,7 +573,9 @@ void SearchProvider::DoHistoryQuery(bool minimal_changes) {
const TemplateURL* keyword_url = providers_.GetKeywordProviderURL();
if (keyword_url) {
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() {
}
}
}
AddHistoryResultsToMap(keyword_history_results_, true,
did_not_accept_keyword_suggestion, &map);
AddHistoryResultsToMap(default_history_results_, false,
did_not_accept_default_suggestion, &map);
AddRawHistoryResultsToMap(true, did_not_accept_keyword_suggestion, &map);
AddRawHistoryResultsToMap(false, did_not_accept_default_suggestion, &map);
AddSuggestResultsToMap(keyword_results_.suggest_results,
keyword_results_.metadata, &map);
......@@ -960,56 +981,56 @@ void SearchProvider::AddNavigationResultsToMatches(
}
}
void SearchProvider::AddHistoryResultsToMap(const HistoryResults& results,
bool is_keyword,
int did_not_accept_suggestion,
MatchMap* map) {
if (results.empty())
void SearchProvider::AddRawHistoryResultsToMap(bool is_keyword,
int did_not_accept_suggestion,
MatchMap* map) {
const HistoryResults& raw_results =
is_keyword ? raw_keyword_history_results_ : raw_default_history_results_;
if (!OmniboxFieldTrial::EnableAnswersInSuggest() && raw_results.empty())
return;
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;
if (!prevent_inline_autocomplete && input_multiple_words) {
// ScoreHistoryResults() 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 = ScoreHistoryResults(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.
// Until Answers becomes default, scoring of history results will still happen
// here for non-Answers Chrome, to prevent scoring performance regressions
// resulting from moving the scoring code before the suggest request is sent.
// For users with Answers enabled, the history results have already been
// scored earlier, right after calling DoHistoryQuery().
SearchSuggestionParser::SuggestResults local_transformed_results;
const SearchSuggestionParser::SuggestResults* transformed_results = NULL;
if (!OmniboxFieldTrial::EnableAnswersInSuggest()) {
ScoreHistoryResults(raw_results, is_keyword, &local_transformed_results);
transformed_results = &local_transformed_results;
} else {
transformed_results = is_keyword ? &transformed_keyword_history_results_
: &transformed_default_history_results_;
}
if (scored_results.empty())
scored_results = ScoreHistoryResults(results, prevent_inline_autocomplete,
input_multiple_words, input_text,
is_keyword);
DCHECK(transformed_results);
AddTransformedHistoryResultsToMap(
*transformed_results, did_not_accept_suggestion, map);
UMA_HISTOGRAM_TIMES("Omnibox.SearchProvider.AddHistoryResultsTime",
base::TimeTicks::Now() - start_time);
}
void SearchProvider::AddTransformedHistoryResultsToMap(
const SearchSuggestionParser::SuggestResults& transformed_results,
int did_not_accept_suggestion,
MatchMap* map) {
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,
providers_.GetKeywordProviderURL() != NULL, map);
}
UMA_HISTOGRAM_TIMES("Omnibox.SearchProvider.AddHistoryResultsTime",
base::TimeTicks::Now() - start_time);
}
SearchSuggestionParser::SuggestResults SearchProvider::ScoreHistoryResults(
const HistoryResults& results,
bool base_prevent_inline_autocomplete,
bool input_multiple_words,
const base::string16& input_text,
bool is_keyword) {
SearchSuggestionParser::SuggestResults
SearchProvider::ScoreHistoryResultsHelper(const HistoryResults& results,
bool base_prevent_inline_autocomplete,
bool input_multiple_words,
const base::string16& input_text,
bool is_keyword) {
SearchSuggestionParser::SuggestResults scored_results;
// True if the user has asked this exact query previously.
bool found_what_you_typed_match = false;
......@@ -1115,6 +1136,46 @@ SearchSuggestionParser::SuggestResults SearchProvider::ScoreHistoryResults(
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(
const SearchSuggestionParser::SuggestResults& results,
const std::string& metadata,
......@@ -1356,6 +1417,24 @@ void SearchProvider::RegisterDisplayedAnswers(
answers_cache_.UpdateRecentAnswers(match->fill_into_edit, match->answer_type);
}
void SearchProvider::DoAnswersQuery(const AutocompleteInput& input) {
prefetch_data_ = answers_cache_.GetTopAnswerEntry(input.text());
AnswersQueryData SearchProvider::FindAnswersPrefetchData() {
// 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,
const SearchSuggestionParser::NavigationResults& navigation_results,
ACMatches* matches);
// Adds a match for each result in |results| to |map|. |is_keyword| indicates
// whether the results correspond to the keyword provider or default provider.
void AddHistoryResultsToMap(const HistoryResults& results,
bool is_keyword,
int did_not_accept_suggestion,
MatchMap* map);
// Adds a match for each result in |raw_default_history_results_| or
// |raw_keyword_history_results_| to |map|. |is_keyword| indicates
// which one of the two.
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,
MatchMap* map);
// Calculates relevance scores for all |results|.
SearchSuggestionParser::SuggestResults ScoreHistoryResults(
SearchSuggestionParser::SuggestResults ScoreHistoryResultsHelper(
const HistoryResults& results,
bool base_prevent_inline_autocomplete,
bool input_multiple_words,
const base::string16& input_text,
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|.
void AddSuggestResultsToMap(
const SearchSuggestionParser::SuggestResults& results,
......@@ -321,9 +335,11 @@ class SearchProvider : public BaseSearchProvider,
// Obtains a session token, regenerating if necessary.
std::string GetSessionToken();
// Answers prefetch handling - finds previously displayed answer matching the
// current |input| and sets |prefetch_data_|.
void DoAnswersQuery(const AutocompleteInput& input);
// Answers prefetch handling - finds the previously displayed answer matching
// the current top-scoring history result. If there is a previous answer,
// 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
// previous one. Non-const because some unittests modify this value.
......@@ -345,8 +361,13 @@ class SearchProvider : public BaseSearchProvider,
AutocompleteInput keyword_input_;
// Searches in the user's history that begin with the input text.
HistoryResults keyword_history_results_;
HistoryResults default_history_results_;
HistoryResults raw_keyword_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
// 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