Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(668)

Side by Side Diff: chrome/browser/autocomplete/search_provider.cc

Issue 7314018: Don't autocomplete searches of >1 word if they've only been visited once and the user has not yet... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 9 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "chrome/browser/autocomplete/search_provider.h" 5 #include "chrome/browser/autocomplete/search_provider.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cmath> 8 #include <cmath>
9 9
10 #include "base/callback.h" 10 #include "base/callback.h"
11 #include "base/i18n/break_iterator.h"
11 #include "base/i18n/case_conversion.h" 12 #include "base/i18n/case_conversion.h"
12 #include "base/i18n/icu_string_conversions.h" 13 #include "base/i18n/icu_string_conversions.h"
13 #include "base/message_loop.h" 14 #include "base/message_loop.h"
14 #include "base/string16.h" 15 #include "base/string16.h"
15 #include "base/utf_string_conversions.h" 16 #include "base/utf_string_conversions.h"
16 #include "chrome/browser/autocomplete/autocomplete_classifier.h" 17 #include "chrome/browser/autocomplete/autocomplete_classifier.h"
17 #include "chrome/browser/autocomplete/keyword_provider.h" 18 #include "chrome/browser/autocomplete/keyword_provider.h"
18 #include "chrome/browser/autocomplete/autocomplete_match.h" 19 #include "chrome/browser/autocomplete/autocomplete_match.h"
19 #include "chrome/browser/history/history.h" 20 #include "chrome/browser/history/history.h"
20 #include "chrome/browser/instant/instant_controller.h" 21 #include "chrome/browser/instant/instant_controller.h"
21 #include "chrome/browser/net/url_fixer_upper.h" 22 #include "chrome/browser/net/url_fixer_upper.h"
22 #include "chrome/browser/prefs/pref_service.h" 23 #include "chrome/browser/prefs/pref_service.h"
23 #include "chrome/browser/profiles/profile.h" 24 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/history/in_memory_database.h" 25 #include "chrome/browser/history/in_memory_database.h"
25 #include "chrome/browser/search_engines/template_url_service.h" 26 #include "chrome/browser/search_engines/template_url_service.h"
26 #include "chrome/browser/search_engines/template_url_service_factory.h" 27 #include "chrome/browser/search_engines/template_url_service_factory.h"
27 #include "chrome/common/pref_names.h" 28 #include "chrome/common/pref_names.h"
28 #include "chrome/common/url_constants.h" 29 #include "chrome/common/url_constants.h"
29 #include "content/common/json_value_serializer.h" 30 #include "content/common/json_value_serializer.h"
30 #include "googleurl/src/url_util.h" 31 #include "googleurl/src/url_util.h"
31 #include "grit/generated_resources.h" 32 #include "grit/generated_resources.h"
32 #include "net/base/escape.h" 33 #include "net/base/escape.h"
33 #include "net/http/http_response_headers.h" 34 #include "net/http/http_response_headers.h"
34 #include "net/url_request/url_request_status.h" 35 #include "net/url_request/url_request_status.h"
35 #include "ui/base/l10n/l10n_util.h" 36 #include "ui/base/l10n/l10n_util.h"
36 37
37 using base::Time; 38 using base::Time;
38 using base::TimeDelta; 39 using base::TimeDelta;
39 40
41 namespace {
42
43 bool HasMultipleWords(const string16& text) {
44 base::i18n::BreakIterator i(text, base::i18n::BreakIterator::BREAK_WORD);
45 bool found_word = false;
sky 2011/07/07 02:49:15 nit: move this inside the if.
46 if (i.Init()) {
47 while (i.Advance()) {
48 if (i.IsWord()) {
49 if (found_word)
50 return true;
51 found_word = true;
52 }
53 }
54 }
55 return false;
56 }
57
58 };
59
40 // static 60 // static
41 const int SearchProvider::kDefaultProviderURLFetcherID = 1; 61 const int SearchProvider::kDefaultProviderURLFetcherID = 1;
42 // static 62 // static
43 const int SearchProvider::kKeywordProviderURLFetcherID = 2; 63 const int SearchProvider::kKeywordProviderURLFetcherID = 2;
44 64
45 // static 65 // static
46 bool SearchProvider::query_suggest_immediately_ = false; 66 bool SearchProvider::query_suggest_immediately_ = false;
47 67
48 void SearchProvider::Providers::Set(const TemplateURL* default_provider, 68 void SearchProvider::Providers::Set(const TemplateURL* default_provider,
49 const TemplateURL* keyword_provider) { 69 const TemplateURL* keyword_provider) {
(...skipping 546 matching lines...) Expand 10 before | Expand all | Expand 10 after
596 matches_.push_back(NavigationToMatch(navigation_results.front(), 616 matches_.push_back(NavigationToMatch(navigation_results.front(),
597 CalculateRelevanceForNavigation(num_results, 0, is_keyword), 617 CalculateRelevanceForNavigation(num_results, 0, is_keyword),
598 is_keyword)); 618 is_keyword));
599 } 619 }
600 } 620 }
601 621
602 void SearchProvider::AddHistoryResultsToMap(const HistoryResults& results, 622 void SearchProvider::AddHistoryResultsToMap(const HistoryResults& results,
603 bool is_keyword, 623 bool is_keyword,
604 int did_not_accept_suggestion, 624 int did_not_accept_suggestion,
605 MatchMap* map) { 625 MatchMap* map) {
626 bool base_prevent_inline_autocomplete =
627 (input_.type() == AutocompleteInput::URL) ||
628 input_.prevent_inline_autocomplete();
629 const string16& input_text(
630 is_keyword ? keyword_input_text_ : input_.text());
631 bool input_not_multiple_words = !HasMultipleWords(input_text);
632 bool is_primary_provider = providers_.is_primary_provider(is_keyword);
633 AutocompleteClassifier* classifier = profile_->GetAutocompleteClassifier();
606 int last_relevance = 0; 634 int last_relevance = 0;
607 AutocompleteClassifier* classifier = profile_->GetAutocompleteClassifier();
608 for (HistoryResults::const_iterator i(results.begin()); i != results.end(); 635 for (HistoryResults::const_iterator i(results.begin()); i != results.end();
609 ++i) { 636 ++i) {
637 // Don't autocomplete multi-word queries that have only been seen once
638 // unless the user has typed more than one word.
639 bool prevent_inline_autocomplete = base_prevent_inline_autocomplete ||
640 (input_not_multiple_words && (i->visits < 2) &&
641 HasMultipleWords(i->term));
642
643 // Don't autocomplete search terms that would normally be treated as URLs
644 // when typed. For example, if the user searched for "google.com" and types
645 // "goog", don't autocomplete to the search term "google.com". Otherwise,
646 // the input will look like a URL but act like a search, which is confusing.
647 // NOTE: We don't check this in the following cases:
648 // * When inline autocomplete is disabled, we won't be inline
649 // autocompleting this term, so we don't need to worry about confusion as
650 // much. This also prevents calling Classify() again from inside the
651 // classifier (which will corrupt state and likely crash), since the
652 // classifier always disables inline autocomplete.
653 // * When the user has typed the whole term, the "what you typed" history
654 // match will outrank us for URL-like inputs anyway, so we need not do
655 // anything special.
656 if (!prevent_inline_autocomplete && classifier && (i->term != input_text)) {
657 AutocompleteMatch match;
658 classifier->Classify(i->term, string16(), false, false, &match, NULL);
659 prevent_inline_autocomplete = match.transition == PageTransition::TYPED;
660 }
661
662 int relevance = CalculateRelevanceForHistory(i->time, is_primary_provider,
663 prevent_inline_autocomplete);
610 // History returns results sorted for us. We force the relevance to decrease 664 // History returns results sorted for us. We force the relevance to decrease
611 // so that the sort from history is honored. We should never end up with a 665 // so that the sort from history is honored. We should never end up with a
612 // match having a relevance greater than the previous, but they might be 666 // match having a relevance greater than the previous, but they might be
613 // equal. If we didn't force the relevance to decrease and we ended up in a 667 // equal. If we didn't force the relevance to decrease and we ended up in a
614 // situation where the relevance was equal, then which was shown first would 668 // situation where the relevance was equal, then which was shown first would
615 // be random. 669 // be random.
616 // This uses >= to handle the case where 3 or more results have the same 670 // This uses >= to handle the case where 3 or more results have the same
617 // relevance. 671 // relevance.
618 bool term_looks_like_url = false;
619 // Don't autocomplete search terms that would normally be treated as URLs
620 // when typed. For example, if the user searched for google.com and types
621 // goog, don't autocomplete to the search term google.com. Otherwise, the
622 // input will look like a URL but act like a search, which is confusing.
623 // NOTE: We don't check this in the following cases:
624 // * When inline autocomplete is disabled, we won't be inline
625 // autocompleting this term, so we don't need to worry about confusion as
626 // much. This also prevents calling Classify() again from inside the
627 // classifier (which will corrupt state and likely crash), since the
628 // classifier always disabled inline autocomplete.
629 // * When the user has typed the whole term, the "what you typed" history
630 // match will outrank us for URL-like inputs anyway, so we need not do
631 // anything special.
632 if (!input_.prevent_inline_autocomplete() && classifier &&
633 i->term != input_.text()) {
634 AutocompleteMatch match;
635 classifier->Classify(i->term, string16(), false, false, &match, NULL);
636 term_looks_like_url = match.transition == PageTransition::TYPED;
637 }
638 int relevance = CalculateRelevanceForHistory(i->time, term_looks_like_url,
639 is_keyword);
640 if (i != results.begin() && relevance >= last_relevance) 672 if (i != results.begin() && relevance >= last_relevance)
641 relevance = last_relevance - 1; 673 relevance = last_relevance - 1;
642 last_relevance = relevance; 674 last_relevance = relevance;
643 AddMatchToMap(i->term, 675
644 is_keyword ? keyword_input_text_ : input_.text(), 676 AddMatchToMap(i->term, input_text, relevance,
645 relevance,
646 AutocompleteMatch::SEARCH_HISTORY, did_not_accept_suggestion, 677 AutocompleteMatch::SEARCH_HISTORY, did_not_accept_suggestion,
647 is_keyword, input_.prevent_inline_autocomplete(), 678 is_keyword, input_.prevent_inline_autocomplete(), map);
648 map);
649 } 679 }
650 } 680 }
651 681
652 void SearchProvider::AddSuggestResultsToMap( 682 void SearchProvider::AddSuggestResultsToMap(
653 const SuggestResults& suggest_results, 683 const SuggestResults& suggest_results,
654 bool is_keyword, 684 bool is_keyword,
655 int did_not_accept_suggestion, 685 int did_not_accept_suggestion,
656 MatchMap* map) { 686 MatchMap* map) {
657 for (size_t i = 0; i < suggest_results.size(); ++i) { 687 for (size_t i = 0; i < suggest_results.size(); ++i) {
658 AddMatchToMap(suggest_results[i], 688 AddMatchToMap(suggest_results[i],
(...skipping 21 matching lines...) Expand all
680 710
681 case AutocompleteInput::URL: 711 case AutocompleteInput::URL:
682 return 850; 712 return 850;
683 713
684 default: 714 default:
685 NOTREACHED(); 715 NOTREACHED();
686 return 0; 716 return 0;
687 } 717 }
688 } 718 }
689 719
690 int SearchProvider::CalculateRelevanceForHistory(const Time& time, 720 int SearchProvider::CalculateRelevanceForHistory(
691 bool looks_like_url, 721 const Time& time,
692 bool is_keyword) const { 722 bool is_primary_provider,
723 bool prevent_inline_autocomplete) const {
693 // The relevance of past searches falls off over time. There are two distinct 724 // The relevance of past searches falls off over time. There are two distinct
694 // equations used. If the first equation is used (searches to the primary 725 // equations used. If the first equation is used (searches to the primary
695 // provider with a type other than URL that don't autocomplete to a url) the 726 // provider that we want to inline autocomplete), the score starts at 1399 and
696 // score starts at 1399 and falls to 1300. If the second equation is used the 727 // falls to 1300. If the second equation is used the relevance of a search 15
697 // relevance of a search 15 minutes ago is discounted about 50 points, while 728 // minutes ago is discounted 50 points, while the relevance of a search two
698 // the relevance of a search two weeks ago is discounted about 450 points. 729 // weeks ago is discounted 450 points.
699 double elapsed_time = std::max((Time::Now() - time).InSecondsF(), 0.); 730 double elapsed_time = std::max((Time::Now() - time).InSecondsF(), 0.);
700 731 if (is_primary_provider && !prevent_inline_autocomplete) {
701 if (providers_.is_primary_provider(is_keyword) &&
702 input_.type() != AutocompleteInput::URL &&
703 !input_.prevent_inline_autocomplete() && !looks_like_url) {
704 // Searches with the past two days get a different curve. 732 // Searches with the past two days get a different curve.
705 const double autocomplete_time= 2 * 24 * 60 * 60; 733 const double autocomplete_time = 2 * 24 * 60 * 60;
706 if (elapsed_time < autocomplete_time) { 734 if (elapsed_time < autocomplete_time) {
707 return 1399 - static_cast<int>(99 * 735 return 1399 - static_cast<int>(99 *
708 std::pow(elapsed_time / autocomplete_time, 2.5)); 736 std::pow(elapsed_time / autocomplete_time, 2.5));
709 } 737 }
710 elapsed_time -= autocomplete_time; 738 elapsed_time -= autocomplete_time;
711 } 739 }
712 740
713 const int score_discount = 741 const int score_discount =
714 static_cast<int>(6.5 * std::pow(elapsed_time, 0.3)); 742 static_cast<int>(6.5 * std::pow(elapsed_time, 0.3));
715 743
716 // Don't let scores go below 0. Negative relevance scores are meaningful in 744 // Don't let scores go below 0. Negative relevance scores are meaningful in
717 // a different way. 745 // a different way.
718 int base_score; 746 int base_score;
719 if (!providers_.is_primary_provider(is_keyword)) 747 if (is_primary_provider)
748 base_score = (input_.type() == AutocompleteInput::URL) ? 750 : 1050;
749 else
720 base_score = 200; 750 base_score = 200;
721 else
722 base_score = (input_.type() == AutocompleteInput::URL) ? 750 : 1050;
723 return std::max(0, base_score - score_discount); 751 return std::max(0, base_score - score_discount);
724 } 752 }
725 753
726 int SearchProvider::CalculateRelevanceForSuggestion(size_t num_results, 754 int SearchProvider::CalculateRelevanceForSuggestion(size_t num_results,
727 size_t result_number, 755 size_t result_number,
728 bool is_keyword) const { 756 bool is_keyword) const {
729 DCHECK(result_number < num_results); 757 DCHECK(result_number < num_results);
730 int base_score; 758 int base_score;
731 if (!providers_.is_primary_provider(is_keyword)) 759 if (!providers_.is_primary_provider(is_keyword))
732 base_score = 100; 760 base_score = 100;
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
906 match.description_class.push_back( 934 match.description_class.push_back(
907 ACMatchClassification(0, ACMatchClassification::DIM)); 935 ACMatchClassification(0, ACMatchClassification::DIM));
908 // Only the first search match gets a description. 936 // Only the first search match gets a description.
909 return; 937 return;
910 938
911 default: 939 default:
912 break; 940 break;
913 } 941 }
914 } 942 }
915 } 943 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698