summaryrefslogtreecommitdiffstats
path: root/chrome/browser/omnibox
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/omnibox')
-rw-r--r--chrome/browser/omnibox/omnibox_field_trial.cc108
-rw-r--r--chrome/browser/omnibox/omnibox_field_trial.h85
-rw-r--r--chrome/browser/omnibox/omnibox_field_trial_unittest.cc58
3 files changed, 249 insertions, 2 deletions
diff --git a/chrome/browser/omnibox/omnibox_field_trial.cc b/chrome/browser/omnibox/omnibox_field_trial.cc
index 8b6de02..93ec15b 100644
--- a/chrome/browser/omnibox/omnibox_field_trial.cc
+++ b/chrome/browser/omnibox/omnibox_field_trial.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/omnibox/omnibox_field_trial.h"
+#include <cmath>
#include <string>
#include "base/metrics/field_trial.h"
@@ -11,6 +12,7 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
#include "chrome/browser/autocomplete/autocomplete_input.h"
#include "chrome/browser/search/search.h"
#include "chrome/common/metrics/variations/variation_ids.h"
@@ -19,6 +21,9 @@
namespace {
+typedef std::map<std::string, std::string> VariationParams;
+typedef HUPScoringParams::ScoreBuckets ScoreBuckets;
+
// Field trial names.
const char kHUPCullRedirectsFieldTrialName[] = "OmniboxHUPCullRedirects";
const char kHUPCreateShorterMatchFieldTrialName[] =
@@ -83,8 +88,66 @@ std::string DynamicFieldTrialName(int id) {
return base::StringPrintf("%s%d", kAutocompleteDynamicFieldTrialPrefix, id);
}
+void InitializeScoreBuckets(const VariationParams& params,
+ const char* relevance_cap_param,
+ const char* half_life_param,
+ const char* score_buckets_param,
+ ScoreBuckets* score_buckets) {
+ VariationParams::const_iterator it = params.find(relevance_cap_param);
+ if (it != params.end()) {
+ int relevance_cap;
+ if (base::StringToInt(it->second, &relevance_cap))
+ score_buckets->set_relevance_cap(relevance_cap);
+ }
+
+ it = params.find(half_life_param);
+ if (it != params.end()) {
+ int half_life_days;
+ if (base::StringToInt(it->second, &half_life_days))
+ score_buckets->set_half_life_days(half_life_days);
+ }
+
+ it = params.find(score_buckets_param);
+ if (it != params.end()) {
+ // The value of the score bucket is a comma-separated list of
+ // {DecayedCount + ":" + MaxRelevance}.
+ base::StringPairs kv_pairs;
+ if (base::SplitStringIntoKeyValuePairs(it->second, ':', ',', &kv_pairs)) {
+ for (base::StringPairs::const_iterator it = kv_pairs.begin();
+ it != kv_pairs.end(); ++it) {
+ ScoreBuckets::CountMaxRelevance bucket;
+ base::StringToDouble(it->first, &bucket.first);
+ base::StringToInt(it->second, &bucket.second);
+ score_buckets->buckets().push_back(bucket);
+ }
+ std::sort(score_buckets->buckets().begin(),
+ score_buckets->buckets().end(),
+ std::greater<ScoreBuckets::CountMaxRelevance>());
+ }
+ }
+}
+
} // namespace
+HUPScoringParams::ScoreBuckets::ScoreBuckets()
+ : relevance_cap_(-1),
+ half_life_days_(-1) {
+}
+
+HUPScoringParams::ScoreBuckets::~ScoreBuckets() {
+}
+
+double HUPScoringParams::ScoreBuckets::HalfLifeTimeDecay(
+ const base::TimeDelta& elapsed_time) const {
+ double time_ms;
+ if ((half_life_days_ <= 0) ||
+ ((time_ms = elapsed_time.InMillisecondsF()) <= 0))
+ return 1.0;
+
+ const double half_life_intervals =
+ time_ms / base::TimeDelta::FromDays(half_life_days_).InMillisecondsF();
+ return pow(2.0, -half_life_intervals);
+}
void OmniboxFieldTrial::ActivateStaticTrials() {
DCHECK(!static_field_trials_initialized);
@@ -305,6 +368,32 @@ bool OmniboxFieldTrial::ReorderForLegalDefaultMatch(
kReorderForLegalDefaultMatchRuleEnabled;
}
+void OmniboxFieldTrial::GetExperimentalHUPScoringParams(
+ HUPScoringParams* scoring_params) {
+ scoring_params->experimental_scoring_enabled = false;
+
+ VariationParams params;
+ if (!chrome_variations::GetVariationParams(kBundledExperimentFieldTrialName,
+ &params))
+ return;
+
+ VariationParams::const_iterator it = params.find(kHUPNewScoringEnabledParam);
+ if (it != params.end()) {
+ int enabled = 0;
+ if (base::StringToInt(it->second, &enabled))
+ scoring_params->experimental_scoring_enabled = (enabled != 0);
+ }
+
+ InitializeScoreBuckets(params, kHUPNewScoringTypedCountRelevanceCapParam,
+ kHUPNewScoringTypedCountHalfLifeTimeParam,
+ kHUPNewScoringTypedCountScoreBucketsParam,
+ &scoring_params->typed_count_buckets);
+ InitializeScoreBuckets(params, kHUPNewScoringVisitedCountRelevanceCapParam,
+ kHUPNewScoringVisitedCountHalfLifeTimeParam,
+ kHUPNewScoringVisitedCountScoreBucketsParam,
+ &scoring_params->visited_count_buckets);
+}
+
int OmniboxFieldTrial::HQPBookmarkValue() {
std::string bookmark_value_str = chrome_variations::
GetVariationParamValue(kBundledExperimentFieldTrialName,
@@ -356,6 +445,21 @@ const char OmniboxFieldTrial::kHQPAllowMatchInSchemeRule[] =
const char OmniboxFieldTrial::kReorderForLegalDefaultMatchRuleEnabled[] =
"ReorderForLegalDefaultMatch";
+const char OmniboxFieldTrial::kHUPNewScoringEnabledParam[] =
+ "HUPExperimentalScoringEnabled";
+const char OmniboxFieldTrial::kHUPNewScoringTypedCountRelevanceCapParam[] =
+ "TypedCountRelevanceCap";
+const char OmniboxFieldTrial::kHUPNewScoringTypedCountHalfLifeTimeParam[] =
+ "TypedCountHalfLifeTime";
+const char OmniboxFieldTrial::kHUPNewScoringTypedCountScoreBucketsParam[] =
+ "TypedCountScoreBuckets";
+const char OmniboxFieldTrial::kHUPNewScoringVisitedCountRelevanceCapParam[] =
+ "VisitedCountRelevanceCap";
+const char OmniboxFieldTrial::kHUPNewScoringVisitedCountHalfLifeTimeParam[] =
+ "VisitedCountHalfLifeTime";
+const char OmniboxFieldTrial::kHUPNewScoringVisitedCountScoreBucketsParam[] =
+ "VisitedCountScoreBuckets";
+
// Background and implementation details:
//
// Each experiment group in any field trial can come with an optional set of
@@ -392,7 +496,7 @@ const char OmniboxFieldTrial::kReorderForLegalDefaultMatchRuleEnabled[] =
std::string OmniboxFieldTrial::GetValueForRuleInContext(
const std::string& rule,
AutocompleteInput::PageClassification page_classification) {
- std::map<std::string, std::string> params;
+ VariationParams params;
if (!chrome_variations::GetVariationParams(kBundledExperimentFieldTrialName,
&params)) {
return std::string();
@@ -402,7 +506,7 @@ std::string OmniboxFieldTrial::GetValueForRuleInContext(
const std::string instant_extended =
chrome::IsInstantExtendedAPIEnabled() ? "1" : "0";
// Look up rule in this exact context.
- std::map<std::string, std::string>::iterator it = params.find(
+ VariationParams::const_iterator it = params.find(
rule + ":" + page_classification_str + ":" + instant_extended);
if (it != params.end())
return it->second;
diff --git a/chrome/browser/omnibox/omnibox_field_trial.h b/chrome/browser/omnibox/omnibox_field_trial.h
index 9e9ee55..a75eccc 100644
--- a/chrome/browser/omnibox/omnibox_field_trial.h
+++ b/chrome/browser/omnibox/omnibox_field_trial.h
@@ -15,6 +15,74 @@
#include "chrome/browser/autocomplete/autocomplete_input.h"
#include "chrome/common/autocomplete_match_type.h"
+namespace base {
+class TimeDelta;
+}
+
+// The set of parameters customizing the HUP scoring.
+struct HUPScoringParams {
+ // A set of parameters describing how to cap a given count score. First,
+ // we apply a half-life based decay of the given count and then find the
+ // maximum relevance score in the corresponding bucket list.
+ class ScoreBuckets {
+ public:
+ // (decayed_count, max_relevance) pair.
+ typedef std::pair<double, int> CountMaxRelevance;
+
+ ScoreBuckets();
+ ~ScoreBuckets();
+
+ // Computes a half-life time decay given the |elapsed_time|.
+ double HalfLifeTimeDecay(const base::TimeDelta& elapsed_time) const;
+
+ int relevance_cap() const { return relevance_cap_; }
+ void set_relevance_cap(int relevance_cap) {
+ relevance_cap_ = relevance_cap;
+ }
+
+ int half_life_days() const { return half_life_days_; }
+ void set_half_life_days(int half_life_days) {
+ half_life_days_ = half_life_days;
+ }
+
+ std::vector<CountMaxRelevance>& buckets() { return buckets_; }
+ const std::vector<CountMaxRelevance>& buckets() const { return buckets_; }
+
+ private:
+ // History matches with relevance score greater or equal to |relevance_cap_|
+ // are not affected by this experiment.
+ // Set to -1, if there is no relevance cap in place and all matches are
+ // subject to demotion.
+ int relevance_cap_;
+
+ // Half life time for a decayed count as measured since the last visit.
+ // Set to -1 if not used.
+ int half_life_days_;
+
+ // The relevance score caps for given decayed count values.
+ // Each pair (decayed_count, max_score) indicates what the maximum relevance
+ // score is of a decayed count equal or greater than decayed_count.
+ //
+ // Consider this example:
+ // [(1, 1000), (0.5, 500), (0, 100)]
+ // If decayed count is 2 (which is >= 1), the corresponding match's maximum
+ // relevance will be capped at 1000. In case of 0.5, the score is capped
+ // at 500. Anything below 0.5 is capped at 100.
+ //
+ // This list is sorted by the pair's first element in descending order.
+ std::vector<CountMaxRelevance> buckets_;
+ };
+
+ HUPScoringParams() : experimental_scoring_enabled(false) {}
+
+ bool experimental_scoring_enabled;
+
+ ScoreBuckets typed_count_buckets;
+
+ // Used only when the typed count is 0.
+ ScoreBuckets visited_count_buckets;
+};
+
// This class manages the Omnibox field trials.
class OmniboxFieldTrial {
public:
@@ -175,6 +243,14 @@ class OmniboxFieldTrial {
AutocompleteInput::PageClassification current_page_classification);
// ---------------------------------------------------------
+ // For the HistoryURL provider new scoring experiment that is part of the
+ // bundled omnibox field trial.
+
+ // Initializes the HUP |scoring_params| based on the active HUP scoring
+ // experiment. If there is no such experiment, this function simply sets
+ // |scoring_params|->experimental_scoring_enabled to false.
+ static void GetExperimentalHUPScoringParams(HUPScoringParams* scoring_params);
+
// For the HQPBookmarkValue experiment that's part of the
// bundled omnibox field trial.
@@ -228,6 +304,15 @@ class OmniboxFieldTrial {
// Rule values.
static const char kReorderForLegalDefaultMatchRuleEnabled[];
+ // Parameter names used by the HUP new scoring experiments.
+ static const char kHUPNewScoringEnabledParam[];
+ static const char kHUPNewScoringTypedCountRelevanceCapParam[];
+ static const char kHUPNewScoringTypedCountHalfLifeTimeParam[];
+ static const char kHUPNewScoringTypedCountScoreBucketsParam[];
+ static const char kHUPNewScoringVisitedCountRelevanceCapParam[];
+ static const char kHUPNewScoringVisitedCountHalfLifeTimeParam[];
+ static const char kHUPNewScoringVisitedCountScoreBucketsParam[];
+
private:
friend class OmniboxFieldTrialTest;
diff --git a/chrome/browser/omnibox/omnibox_field_trial_unittest.cc b/chrome/browser/omnibox/omnibox_field_trial_unittest.cc
index 4eda354..32e1d80 100644
--- a/chrome/browser/omnibox/omnibox_field_trial_unittest.cc
+++ b/chrome/browser/omnibox/omnibox_field_trial_unittest.cc
@@ -325,3 +325,61 @@ TEST_F(OmniboxFieldTrialTest, GetValueForRuleInContext) {
"rule5", AutocompleteInput::OTHER); // no rule at all
}
}
+
+TEST_F(OmniboxFieldTrialTest, HUPNewScoringFieldTrial) {
+ {
+ std::map<std::string, std::string> params;
+ params[std::string(OmniboxFieldTrial::kHUPNewScoringEnabledParam)] = "1";
+ params[std::string(
+ OmniboxFieldTrial::kHUPNewScoringTypedCountRelevanceCapParam)] = "56";
+ params[std::string(
+ OmniboxFieldTrial::kHUPNewScoringTypedCountHalfLifeTimeParam)] = "77";
+ params[std::string(
+ OmniboxFieldTrial::kHUPNewScoringTypedCountScoreBucketsParam)] =
+ "0.2:25,0.1:1001,2.3:777";
+ params[std::string(
+ OmniboxFieldTrial::kHUPNewScoringVisitedCountRelevanceCapParam)] = "11";
+ params[std::string(
+ OmniboxFieldTrial::kHUPNewScoringVisitedCountHalfLifeTimeParam)] = "31";
+ params[std::string(
+ OmniboxFieldTrial::kHUPNewScoringVisitedCountScoreBucketsParam)] =
+ "5:300,0:200";
+ ASSERT_TRUE(chrome_variations::AssociateVariationParams(
+ OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params));
+ }
+ base::FieldTrialList::CreateFieldTrial(
+ OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
+
+ HUPScoringParams scoring_params;
+ OmniboxFieldTrial::GetExperimentalHUPScoringParams(&scoring_params);
+ EXPECT_TRUE(scoring_params.experimental_scoring_enabled);
+ EXPECT_EQ(56, scoring_params.typed_count_buckets.relevance_cap());
+ EXPECT_EQ(77, scoring_params.typed_count_buckets.half_life_days());
+ ASSERT_EQ(3u, scoring_params.typed_count_buckets.buckets().size());
+ EXPECT_EQ(std::make_pair(2.3, 777),
+ scoring_params.typed_count_buckets.buckets()[0]);
+ EXPECT_EQ(std::make_pair(0.2, 25),
+ scoring_params.typed_count_buckets.buckets()[1]);
+ EXPECT_EQ(std::make_pair(0.1, 1001),
+ scoring_params.typed_count_buckets.buckets()[2]);
+ EXPECT_EQ(11, scoring_params.visited_count_buckets.relevance_cap());
+ EXPECT_EQ(31, scoring_params.visited_count_buckets.half_life_days());
+ ASSERT_EQ(2u, scoring_params.visited_count_buckets.buckets().size());
+ EXPECT_EQ(std::make_pair(5.0, 300),
+ scoring_params.visited_count_buckets.buckets()[0]);
+ EXPECT_EQ(std::make_pair(0.0, 200),
+ scoring_params.visited_count_buckets.buckets()[1]);
+}
+
+TEST_F(OmniboxFieldTrialTest, HalfLifeTimeDecay) {
+ HUPScoringParams::ScoreBuckets buckets;
+
+ // No decay by default.
+ EXPECT_EQ(1.0, buckets.HalfLifeTimeDecay(base::TimeDelta::FromDays(7)));
+
+ buckets.set_half_life_days(7);
+ EXPECT_EQ(0.5, buckets.HalfLifeTimeDecay(base::TimeDelta::FromDays(7)));
+ EXPECT_EQ(0.25, buckets.HalfLifeTimeDecay(base::TimeDelta::FromDays(14)));
+ EXPECT_EQ(1.0, buckets.HalfLifeTimeDecay(base::TimeDelta::FromDays(0)));
+ EXPECT_EQ(1.0, buckets.HalfLifeTimeDecay(base::TimeDelta::FromDays(-1)));
+}