Home | History | Annotate | Download | only in omnibox
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef CHROME_BROWSER_OMNIBOX_OMNIBOX_FIELD_TRIAL_H_
      6 #define CHROME_BROWSER_OMNIBOX_OMNIBOX_FIELD_TRIAL_H_
      7 
      8 #include <map>
      9 #include <string>
     10 #include <vector>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/gtest_prod_util.h"
     14 #include "chrome/common/autocomplete_match_type.h"
     15 #include "components/metrics/proto/omnibox_event.pb.h"
     16 
     17 namespace base {
     18 class TimeDelta;
     19 }
     20 
     21 // The set of parameters customizing the HUP scoring.
     22 struct HUPScoringParams {
     23   // A set of parameters describing how to cap a given count score.  First,
     24   // we apply a half-life based decay of the given count and then find the
     25   // maximum relevance score in the corresponding bucket list.
     26   class ScoreBuckets {
     27    public:
     28     // (decayed_count, max_relevance) pair.
     29     typedef std::pair<double, int> CountMaxRelevance;
     30 
     31     ScoreBuckets();
     32     ~ScoreBuckets();
     33 
     34     // Computes a half-life time decay given the |elapsed_time|.
     35     double HalfLifeTimeDecay(const base::TimeDelta& elapsed_time) const;
     36 
     37     int relevance_cap() const { return relevance_cap_; }
     38     void set_relevance_cap(int relevance_cap) {
     39       relevance_cap_ = relevance_cap;
     40     }
     41 
     42     int half_life_days() const { return half_life_days_; }
     43     void set_half_life_days(int half_life_days) {
     44       half_life_days_ = half_life_days;
     45     }
     46 
     47     std::vector<CountMaxRelevance>& buckets() { return buckets_; }
     48     const std::vector<CountMaxRelevance>& buckets() const { return buckets_; }
     49 
     50    private:
     51     // History matches with relevance score greater or equal to |relevance_cap_|
     52     // are not affected by this experiment.
     53     // Set to -1, if there is no relevance cap in place and all matches are
     54     // subject to demotion.
     55     int relevance_cap_;
     56 
     57     // Half life time for a decayed count as measured since the last visit.
     58     // Set to -1 if not used.
     59     int half_life_days_;
     60 
     61     // The relevance score caps for given decayed count values.
     62     // Each pair (decayed_count, max_score) indicates what the maximum relevance
     63     // score is of a decayed count equal or greater than decayed_count.
     64     //
     65     // Consider this example:
     66     //   [(1, 1000), (0.5, 500), (0, 100)]
     67     // If decayed count is 2 (which is >= 1), the corresponding match's maximum
     68     // relevance will be capped at 1000.  In case of 0.5, the score is capped
     69     // at 500.  Anything below 0.5 is capped at 100.
     70     //
     71     // This list is sorted by the pair's first element in descending order.
     72     std::vector<CountMaxRelevance> buckets_;
     73   };
     74 
     75   HUPScoringParams() : experimental_scoring_enabled(false) {}
     76 
     77   bool experimental_scoring_enabled;
     78 
     79   ScoreBuckets typed_count_buckets;
     80 
     81   // Used only when the typed count is 0.
     82   ScoreBuckets visited_count_buckets;
     83 };
     84 
     85 // This class manages the Omnibox field trials.
     86 class OmniboxFieldTrial {
     87  public:
     88   // A mapping that contains multipliers indicating that matches of the
     89   // specified type should have their relevance score multiplied by the
     90   // given number.  Omitted types are assumed to have multipliers of 1.0.
     91   typedef std::map<AutocompleteMatchType::Type, float> DemotionMultipliers;
     92 
     93   // Creates the static field trial groups.
     94   // *** MUST NOT BE CALLED MORE THAN ONCE. ***
     95   static void ActivateStaticTrials();
     96 
     97   // Activates all dynamic field trials.  The main difference between
     98   // the autocomplete dynamic and static field trials is that the former
     99   // don't require any code changes on the Chrome side as they are controlled
    100   // on the server side.  Chrome binary simply propagates all necessary
    101   // information through the X-Client-Data header.
    102   // This method, unlike ActivateStaticTrials(), may be called multiple times.
    103   static void ActivateDynamicTrials();
    104 
    105   // Returns a bitmap containing AutocompleteProvider::Type values
    106   // that should be disabled in AutocompleteController.
    107   // This method simply goes over all autocomplete dynamic field trial groups
    108   // and looks for group names like "ProvidersDisabled_NNN" where NNN is
    109   // an integer corresponding to a bitmap mask.  All extracted bitmaps
    110   // are OR-ed together and returned as the final result.
    111   static int GetDisabledProviderTypes();
    112 
    113   // Returns whether the user is in any dynamic field trial where the
    114   // group has a the prefix |group_prefix|.
    115   static bool HasDynamicFieldTrialGroupPrefix(const char *group_prefix);
    116 
    117   // ---------------------------------------------------------
    118   // For the suggest field trial.
    119 
    120   // Populates |field_trial_hash| with hashes of the active suggest field trial
    121   // names, if any.
    122   static void GetActiveSuggestFieldTrialHashes(
    123       std::vector<uint32>* field_trial_hash);
    124 
    125   // ---------------------------------------------------------
    126   // For the HistoryURL provider disable culling redirects field trial.
    127 
    128   // Returns whether the user is in any group for this field trial.
    129   // (Should always be true unless initialization went wrong.)
    130   static bool InHUPCullRedirectsFieldTrial();
    131 
    132   // Returns whether we should disable culling of redirects in
    133   // HistoryURL provider.
    134   static bool InHUPCullRedirectsFieldTrialExperimentGroup();
    135 
    136   // ---------------------------------------------------------
    137   // For the HistoryURL provider disable creating a shorter match
    138   // field trial.
    139 
    140   // Returns whether the user is in any group for this field trial.
    141   // (Should always be true unless initialization went wrong.)
    142   static bool InHUPCreateShorterMatchFieldTrial();
    143 
    144   // Returns whether we should disable creating a shorter match in
    145   // HistoryURL provider.
    146   static bool InHUPCreateShorterMatchFieldTrialExperimentGroup();
    147 
    148   // ---------------------------------------------------------
    149   // For the AutocompleteController "stop timer" field trial.
    150 
    151   // Returns the duration to be used for the AutocompleteController's stop
    152   // timer.  Returns the default value of 1.5 seconds if the stop timer
    153   // override experiment isn't active or if parsing the experiment-provided
    154   // duration fails.
    155   static base::TimeDelta StopTimerFieldTrialDuration();
    156 
    157   // ---------------------------------------------------------
    158   // For the ZeroSuggestProvider field trial.
    159 
    160   // Returns whether the user is in any field trial where the
    161   // ZeroSuggestProvider should be used to get suggestions when the
    162   // user clicks on the omnibox but has not typed anything yet.
    163   static bool InZeroSuggestFieldTrial();
    164 
    165   // Returns whether the user is in a ZeroSuggest field trial, but should
    166   // show most visited URL instead.  This is used to compare metrics of
    167   // ZeroSuggest and most visited suggestions.
    168   static bool InZeroSuggestMostVisitedFieldTrial();
    169 
    170   // Returns whether the user is in a ZeroSuggest field trial and URL-based
    171   // suggestions can continue to appear after the user has started typing.
    172   static bool InZeroSuggestAfterTypingFieldTrial();
    173 
    174   // Returns whether the user is in a ZeroSuggest field trial, but should
    175   // show recently searched-for queries instead.
    176   static bool InZeroSuggestPersonalizedFieldTrial();
    177 
    178   // ---------------------------------------------------------
    179   // For the ShortcutsScoringMaxRelevance experiment that's part of the
    180   // bundled omnibox field trial.
    181 
    182   // If the user is in an experiment group that, given the provided
    183   // |current_page_classification| context, changes the maximum relevance
    184   // ShortcutsProvider::CalculateScore() is supposed to assign, extract
    185   // that maximum relevance score and put in in |max_relevance|.  Returns
    186   // true on a successful extraction.  CalculateScore()'s return value is
    187   // a product of this maximum relevance score and some attenuating factors
    188   // that are all between 0 and 1.  (Note that Shortcuts results may have
    189   // their scores reduced later if the assigned score is higher than allowed
    190   // for non-inlineable results.  Shortcuts results are not allowed to be
    191   // inlined.)
    192   static bool ShortcutsScoringMaxRelevance(
    193       metrics::OmniboxEventProto::PageClassification
    194           current_page_classification,
    195       int* max_relevance);
    196 
    197   // ---------------------------------------------------------
    198   // For the SearchHistory experiment that's part of the bundled omnibox
    199   // field trial.
    200 
    201   // Returns true if the user is in the experiment group that, given the
    202   // provided |current_page_classification| context, scores search history
    203   // query suggestions less aggressively so that they don't inline.
    204   static bool SearchHistoryPreventInlining(
    205       metrics::OmniboxEventProto::PageClassification
    206           current_page_classification);
    207 
    208   // Returns true if the user is in the experiment group that, given the
    209   // provided |current_page_classification| context, disables all query
    210   // suggestions from search history.
    211   static bool SearchHistoryDisable(
    212       metrics::OmniboxEventProto::PageClassification
    213           current_page_classification);
    214 
    215   // ---------------------------------------------------------
    216   // For the DemoteByType experiment that's part of the bundled omnibox field
    217   // trial.
    218 
    219   // If the user is in an experiment group that, in the provided
    220   // |current_page_classification| context, demotes the relevance scores
    221   // of certain types of matches, populates the |demotions_by_type| map
    222   // appropriately.  Otherwise, sets |demotions_by_type| to its default
    223   // value based on the context.
    224   static void GetDemotionsByType(
    225       metrics::OmniboxEventProto::PageClassification
    226           current_page_classification,
    227       DemotionMultipliers* demotions_by_type);
    228 
    229   // ---------------------------------------------------------
    230   // For the HistoryURL provider new scoring experiment that is part of the
    231   // bundled omnibox field trial.
    232 
    233   // Initializes the HUP |scoring_params| based on the active HUP scoring
    234   // experiment.  If there is no such experiment, this function simply sets
    235   // |scoring_params|->experimental_scoring_enabled to false.
    236   static void GetExperimentalHUPScoringParams(HUPScoringParams* scoring_params);
    237 
    238   // For the HQPBookmarkValue experiment that's part of the
    239   // bundled omnibox field trial.
    240 
    241   // Returns the value an untyped visit to a bookmark should receive.
    242   // Compare this value with the default of 1 for non-bookmarked untyped
    243   // visits to pages and the default of 20 for typed visits.  Returns
    244   // 10 if the bookmark value experiment isn't active.
    245   static int HQPBookmarkValue();
    246 
    247   // ---------------------------------------------------------
    248   // For the HQPAllowMatchInTLD experiment that's part of the
    249   // bundled omnibox field trial.
    250 
    251   // Returns true if HQP should allow an input term to match in the
    252   // top level domain (e.g., .com) of a URL.  Returns false if the
    253   // allow match in TLD experiment isn't active.
    254   static bool HQPAllowMatchInTLDValue();
    255 
    256   // ---------------------------------------------------------
    257   // For the HQPAllowMatchInScheme experiment that's part of the
    258   // bundled omnibox field trial.
    259 
    260   // Returns true if HQP should allow an input term to match in the
    261   // scheme (e.g., http://) of a URL.  Returns false if the allow
    262   // match in scheme experiment isn't active.
    263   static bool HQPAllowMatchInSchemeValue();
    264 
    265   // ---------------------------------------------------------
    266   // For the BookmarksIndexURLs experiment that's part of the
    267   // bundled omnibox field trial.
    268 
    269   // Returns true if BookmarkIndex should index the URL of bookmarks
    270   // (not only the titles) and search for / mark matches in the URLs,
    271   // and BookmarkProvider should score bookmarks based on both the
    272   // matches in bookmark title and URL.  Returns false if the bookmarks
    273   // index URLs experiment isn't active.
    274   static bool BookmarksIndexURLsValue();
    275 
    276   // ---------------------------------------------------------
    277   // For the DisableInlining experiment that's part of the bundled omnibox
    278   // field trial.
    279 
    280   // Returns true if AutocompleteResult should prevent any suggestion with
    281   // a non-empty |inline_autocomplete| from being the default match.  In
    282   // other words, prevent an inline autocompletion from appearing as the
    283   // top suggestion / within the omnibox itself, reordering matches as
    284   // necessary to make this true.  Returns false if the experiment isn't
    285   // active.
    286   static bool DisableInlining();
    287 
    288   // ---------------------------------------------------------
    289   // For the AnswersInSuggest experiment that's part of the bundled omnibox
    290   // field trial.
    291 
    292   // Returns true if the AnswersInSuggest feature should be enabled causing
    293   // query responses such as current weather conditions or stock quotes
    294   // to be provided in the Omnibox suggestion list. Considers both the
    295   // field trial state as well as the overriding command-line flags.
    296   static bool EnableAnswersInSuggest();
    297 
    298   // ---------------------------------------------------------
    299   // For the AddUWYTMatchEvenIfPromotedURLs experiment that's part of the
    300   // bundled omnibox field trial.
    301 
    302   // Returns true if HistoryURL Provider should add the URL-what-you-typed match
    303   // (if valid and reasonable) even if the provider has good inline
    304   // autocompletions to offer.  Normally HistoryURL does not add the UWYT match
    305   // if there are good inline autocompletions, as the user could simply hit
    306   // backspace to delete the completion and get the what-you-typed match.
    307   // However, in the disable inlining experiment this interaction is a lot more
    308   // difficult.  The user will have to select a not-inlined suggestion and
    309   // backspace (possibly a lot) to get back to the what-you-typed match.
    310   // This mode is intended to alleviate the pain by always ensuring that
    311   // the UWYT match appears somewhere on the list of suggestions.  Returns
    312   // false if the experiment isn't active.
    313   static bool AddUWYTMatchEvenIfPromotedURLs();
    314 
    315   // ---------------------------------------------------------
    316   // Exposed publicly for the sake of unittests.
    317   static const char kBundledExperimentFieldTrialName[];
    318   // Rule names used by the bundled experiment.
    319   static const char kShortcutsScoringMaxRelevanceRule[];
    320   static const char kSearchHistoryRule[];
    321   static const char kDemoteByTypeRule[];
    322   static const char kHQPBookmarkValueRule[];
    323   static const char kHQPDiscountFrecencyWhenFewVisitsRule[];
    324   static const char kHQPAllowMatchInTLDRule[];
    325   static const char kHQPAllowMatchInSchemeRule[];
    326   static const char kZeroSuggestRule[];
    327   static const char kZeroSuggestVariantRule[];
    328   static const char kBookmarksIndexURLsRule[];
    329   static const char kDisableInliningRule[];
    330   static const char kAnswersInSuggestRule[];
    331   static const char kAddUWYTMatchEvenIfPromotedURLsRule[];
    332 
    333   // Parameter names used by the HUP new scoring experiments.
    334   static const char kHUPNewScoringEnabledParam[];
    335   static const char kHUPNewScoringTypedCountRelevanceCapParam[];
    336   static const char kHUPNewScoringTypedCountHalfLifeTimeParam[];
    337   static const char kHUPNewScoringTypedCountScoreBucketsParam[];
    338   static const char kHUPNewScoringVisitedCountRelevanceCapParam[];
    339   static const char kHUPNewScoringVisitedCountHalfLifeTimeParam[];
    340   static const char kHUPNewScoringVisitedCountScoreBucketsParam[];
    341 
    342  private:
    343   friend class OmniboxFieldTrialTest;
    344 
    345   // The bundled omnibox experiment comes with a set of parameters
    346   // (key-value pairs).  Each key indicates a certain rule that applies in
    347   // a certain context.  The value indicates what the consequences of
    348   // applying the rule are.  For example, the value of a SearchHistory rule
    349   // in the context of a search results page might indicate that we should
    350   // prevent search history matches from inlining.
    351   //
    352   // This function returns the value associated with the |rule| that applies
    353   // in the current context (which currently consists of |page_classification|
    354   // and whether Instant Extended is enabled).  If no such rule exists in the
    355   // current context, fall back to the rule in various wildcard contexts and
    356   // return its value if found.  If the rule remains unfound in the global
    357   // context, returns the empty string.  For more details, including how we
    358   // prioritize different wildcard contexts, see the implementation.  How to
    359   // interpret the value is left to the caller; this is rule-dependent.
    360   static std::string GetValueForRuleInContext(
    361       const std::string& rule,
    362       metrics::OmniboxEventProto::PageClassification page_classification);
    363 
    364   DISALLOW_IMPLICIT_CONSTRUCTORS(OmniboxFieldTrial);
    365 };
    366 
    367 #endif  // CHROME_BROWSER_OMNIBOX_OMNIBOX_FIELD_TRIAL_H_
    368