| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/omnibox/omnibox_field_trial.h" | 5 #include "chrome/browser/omnibox/omnibox_field_trial.h" |
| 6 | 6 |
| 7 #include <cmath> | 7 #include <cmath> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/metrics/field_trial.h" | 10 #include "base/metrics/field_trial.h" |
| 11 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
| 12 #include "base/strings/string_split.h" | 12 #include "base/strings/string_split.h" |
| 13 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
| 14 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
| 15 #include "base/time/time.h" | 15 #include "base/time/time.h" |
| 16 #include "chrome/browser/autocomplete/autocomplete_input.h" | |
| 17 #include "chrome/browser/search/search.h" | 16 #include "chrome/browser/search/search.h" |
| 18 #include "chrome/common/variations/variation_ids.h" | 17 #include "chrome/common/variations/variation_ids.h" |
| 18 #include "components/metrics/proto/omnibox_event.pb.h" |
| 19 #include "components/variations/active_field_trials.h" | 19 #include "components/variations/active_field_trials.h" |
| 20 #include "components/variations/metrics_util.h" | 20 #include "components/variations/metrics_util.h" |
| 21 #include "components/variations/variations_associated_data.h" | 21 #include "components/variations/variations_associated_data.h" |
| 22 | 22 |
| 23 using metrics::OmniboxEventProto; |
| 24 |
| 23 namespace { | 25 namespace { |
| 24 | 26 |
| 25 typedef std::map<std::string, std::string> VariationParams; | 27 typedef std::map<std::string, std::string> VariationParams; |
| 26 typedef HUPScoringParams::ScoreBuckets ScoreBuckets; | 28 typedef HUPScoringParams::ScoreBuckets ScoreBuckets; |
| 27 | 29 |
| 28 // Field trial names. | 30 // Field trial names. |
| 29 const char kHUPCullRedirectsFieldTrialName[] = "OmniboxHUPCullRedirects"; | 31 const char kHUPCullRedirectsFieldTrialName[] = "OmniboxHUPCullRedirects"; |
| 30 const char kHUPCreateShorterMatchFieldTrialName[] = | 32 const char kHUPCreateShorterMatchFieldTrialName[] = |
| 31 "OmniboxHUPCreateShorterMatch"; | 33 "OmniboxHUPCreateShorterMatch"; |
| 32 const char kStopTimerFieldTrialName[] = "OmniboxStopTimer"; | 34 const char kStopTimerFieldTrialName[] = "OmniboxStopTimer"; |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 | 301 |
| 300 bool OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial() { | 302 bool OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial() { |
| 301 return HasDynamicFieldTrialGroupPrefix( | 303 return HasDynamicFieldTrialGroupPrefix( |
| 302 kEnableZeroSuggestPersonalizedGroupPrefix) || | 304 kEnableZeroSuggestPersonalizedGroupPrefix) || |
| 303 chrome_variations::GetVariationParamValue( | 305 chrome_variations::GetVariationParamValue( |
| 304 kBundledExperimentFieldTrialName, | 306 kBundledExperimentFieldTrialName, |
| 305 kZeroSuggestVariantRule) == "Personalized"; | 307 kZeroSuggestVariantRule) == "Personalized"; |
| 306 } | 308 } |
| 307 | 309 |
| 308 bool OmniboxFieldTrial::ShortcutsScoringMaxRelevance( | 310 bool OmniboxFieldTrial::ShortcutsScoringMaxRelevance( |
| 309 AutocompleteInput::PageClassification current_page_classification, | 311 OmniboxEventProto::PageClassification current_page_classification, |
| 310 int* max_relevance) { | 312 int* max_relevance) { |
| 311 // The value of the rule is a string that encodes an integer containing | 313 // The value of the rule is a string that encodes an integer containing |
| 312 // the max relevance. | 314 // the max relevance. |
| 313 const std::string& max_relevance_str = | 315 const std::string& max_relevance_str = |
| 314 OmniboxFieldTrial::GetValueForRuleInContext( | 316 OmniboxFieldTrial::GetValueForRuleInContext( |
| 315 kShortcutsScoringMaxRelevanceRule, current_page_classification); | 317 kShortcutsScoringMaxRelevanceRule, current_page_classification); |
| 316 if (max_relevance_str.empty()) | 318 if (max_relevance_str.empty()) |
| 317 return false; | 319 return false; |
| 318 if (!base::StringToInt(max_relevance_str, max_relevance)) | 320 if (!base::StringToInt(max_relevance_str, max_relevance)) |
| 319 return false; | 321 return false; |
| 320 return true; | 322 return true; |
| 321 } | 323 } |
| 322 | 324 |
| 323 bool OmniboxFieldTrial::SearchHistoryPreventInlining( | 325 bool OmniboxFieldTrial::SearchHistoryPreventInlining( |
| 324 AutocompleteInput::PageClassification current_page_classification) { | 326 OmniboxEventProto::PageClassification current_page_classification) { |
| 325 return OmniboxFieldTrial::GetValueForRuleInContext( | 327 return OmniboxFieldTrial::GetValueForRuleInContext( |
| 326 kSearchHistoryRule, current_page_classification) == "PreventInlining"; | 328 kSearchHistoryRule, current_page_classification) == "PreventInlining"; |
| 327 } | 329 } |
| 328 | 330 |
| 329 bool OmniboxFieldTrial::SearchHistoryDisable( | 331 bool OmniboxFieldTrial::SearchHistoryDisable( |
| 330 AutocompleteInput::PageClassification current_page_classification) { | 332 OmniboxEventProto::PageClassification current_page_classification) { |
| 331 return OmniboxFieldTrial::GetValueForRuleInContext( | 333 return OmniboxFieldTrial::GetValueForRuleInContext( |
| 332 kSearchHistoryRule, current_page_classification) == "Disable"; | 334 kSearchHistoryRule, current_page_classification) == "Disable"; |
| 333 } | 335 } |
| 334 | 336 |
| 335 void OmniboxFieldTrial::GetDemotionsByType( | 337 void OmniboxFieldTrial::GetDemotionsByType( |
| 336 AutocompleteInput::PageClassification current_page_classification, | 338 OmniboxEventProto::PageClassification current_page_classification, |
| 337 DemotionMultipliers* demotions_by_type) { | 339 DemotionMultipliers* demotions_by_type) { |
| 338 demotions_by_type->clear(); | 340 demotions_by_type->clear(); |
| 339 std::string demotion_rule = OmniboxFieldTrial::GetValueForRuleInContext( | 341 std::string demotion_rule = OmniboxFieldTrial::GetValueForRuleInContext( |
| 340 kDemoteByTypeRule, current_page_classification); | 342 kDemoteByTypeRule, current_page_classification); |
| 341 // If there is no demotion rule for this context, then use the default | 343 // If there is no demotion rule for this context, then use the default |
| 342 // value for that context. At the moment the default value is non-empty | 344 // value for that context. At the moment the default value is non-empty |
| 343 // only for the fakebox-focus context. | 345 // only for the fakebox-focus context. |
| 344 if (demotion_rule.empty() && | 346 if (demotion_rule.empty() && |
| 345 (current_page_classification == | 347 (current_page_classification == |
| 346 AutocompleteInput::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS)) | 348 OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS)) |
| 347 demotion_rule = "1:61,2:61,3:61,4:61,12:61"; | 349 demotion_rule = "1:61,2:61,3:61,4:61,12:61"; |
| 348 | 350 |
| 349 // The value of the DemoteByType rule is a comma-separated list of | 351 // The value of the DemoteByType rule is a comma-separated list of |
| 350 // {ResultType + ":" + Number} where ResultType is an AutocompleteMatchType:: | 352 // {ResultType + ":" + Number} where ResultType is an AutocompleteMatchType:: |
| 351 // Type enum represented as an integer and Number is an integer number | 353 // Type enum represented as an integer and Number is an integer number |
| 352 // between 0 and 100 inclusive. Relevance scores of matches of that result | 354 // between 0 and 100 inclusive. Relevance scores of matches of that result |
| 353 // type are multiplied by Number / 100. 100 means no change. | 355 // type are multiplied by Number / 100. 100 means no change. |
| 354 base::StringPairs kv_pairs; | 356 base::StringPairs kv_pairs; |
| 355 if (base::SplitStringIntoKeyValuePairs(demotion_rule, ':', ',', &kv_pairs)) { | 357 if (base::SplitStringIntoKeyValuePairs(demotion_rule, ':', ',', &kv_pairs)) { |
| 356 for (base::StringPairs::const_iterator it = kv_pairs.begin(); | 358 for (base::StringPairs::const_iterator it = kv_pairs.begin(); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 462 const char OmniboxFieldTrial::kHUPNewScoringVisitedCountScoreBucketsParam[] = | 464 const char OmniboxFieldTrial::kHUPNewScoringVisitedCountScoreBucketsParam[] = |
| 463 "VisitedCountScoreBuckets"; | 465 "VisitedCountScoreBuckets"; |
| 464 | 466 |
| 465 // Background and implementation details: | 467 // Background and implementation details: |
| 466 // | 468 // |
| 467 // Each experiment group in any field trial can come with an optional set of | 469 // Each experiment group in any field trial can come with an optional set of |
| 468 // parameters (key-value pairs). In the bundled omnibox experiment | 470 // parameters (key-value pairs). In the bundled omnibox experiment |
| 469 // (kBundledExperimentFieldTrialName), each experiment group comes with a | 471 // (kBundledExperimentFieldTrialName), each experiment group comes with a |
| 470 // list of parameters in the form: | 472 // list of parameters in the form: |
| 471 // key=<Rule>: | 473 // key=<Rule>: |
| 472 // <AutocompleteInput::PageClassification (as an int)>: | 474 // <OmniboxEventProto::PageClassification (as an int)>: |
| 473 // <whether Instant Extended is enabled (as a 1 or 0)> | 475 // <whether Instant Extended is enabled (as a 1 or 0)> |
| 474 // (note that there are no linebreaks in keys; this format is for | 476 // (note that there are no linebreaks in keys; this format is for |
| 475 // presentation only> | 477 // presentation only> |
| 476 // value=<arbitrary string> | 478 // value=<arbitrary string> |
| 477 // Both the AutocompleteInput::PageClassification and the Instant Extended | 479 // Both the OmniboxEventProto::PageClassification and the Instant Extended |
| 478 // entries can be "*", which means this rule applies for all values of the | 480 // entries can be "*", which means this rule applies for all values of the |
| 479 // matching portion of the context. | 481 // matching portion of the context. |
| 480 // One example parameter is | 482 // One example parameter is |
| 481 // key=SearchHistory:6:1 | 483 // key=SearchHistory:6:1 |
| 482 // value=PreventInlining | 484 // value=PreventInlining |
| 483 // This means in page classification context 6 (a search result page doing | 485 // This means in page classification context 6 (a search result page doing |
| 484 // search term replacement) with Instant Extended enabled, the SearchHistory | 486 // search term replacement) with Instant Extended enabled, the SearchHistory |
| 485 // experiment should PreventInlining. | 487 // experiment should PreventInlining. |
| 486 // | 488 // |
| 487 // When an exact match to the rule in the current context is missing, we | 489 // When an exact match to the rule in the current context is missing, we |
| 488 // give preference to a wildcard rule that matches the instant extended | 490 // give preference to a wildcard rule that matches the instant extended |
| 489 // context over a wildcard rule that matches the page classification | 491 // context over a wildcard rule that matches the page classification |
| 490 // context. Hopefully, though, users will write their field trial configs | 492 // context. Hopefully, though, users will write their field trial configs |
| 491 // so as not to rely on this fall back order. | 493 // so as not to rely on this fall back order. |
| 492 // | 494 // |
| 493 // In short, this function tries to find the value associated with key | 495 // In short, this function tries to find the value associated with key |
| 494 // |rule|:|page_classification|:|instant_extended|, failing that it looks up | 496 // |rule|:|page_classification|:|instant_extended|, failing that it looks up |
| 495 // |rule|:*:|instant_extended|, failing that it looks up | 497 // |rule|:*:|instant_extended|, failing that it looks up |
| 496 // |rule|:|page_classification|:*, failing that it looks up |rule|:*:*, | 498 // |rule|:|page_classification|:*, failing that it looks up |rule|:*:*, |
| 497 // and failing that it returns the empty string. | 499 // and failing that it returns the empty string. |
| 498 std::string OmniboxFieldTrial::GetValueForRuleInContext( | 500 std::string OmniboxFieldTrial::GetValueForRuleInContext( |
| 499 const std::string& rule, | 501 const std::string& rule, |
| 500 AutocompleteInput::PageClassification page_classification) { | 502 OmniboxEventProto::PageClassification page_classification) { |
| 501 VariationParams params; | 503 VariationParams params; |
| 502 if (!chrome_variations::GetVariationParams(kBundledExperimentFieldTrialName, | 504 if (!chrome_variations::GetVariationParams(kBundledExperimentFieldTrialName, |
| 503 ¶ms)) { | 505 ¶ms)) { |
| 504 return std::string(); | 506 return std::string(); |
| 505 } | 507 } |
| 506 const std::string page_classification_str = | 508 const std::string page_classification_str = |
| 507 base::IntToString(static_cast<int>(page_classification)); | 509 base::IntToString(static_cast<int>(page_classification)); |
| 508 const std::string instant_extended = | 510 const std::string instant_extended = |
| 509 chrome::IsInstantExtendedAPIEnabled() ? "1" : "0"; | 511 chrome::IsInstantExtendedAPIEnabled() ? "1" : "0"; |
| 510 // Look up rule in this exact context. | 512 // Look up rule in this exact context. |
| 511 VariationParams::const_iterator it = params.find( | 513 VariationParams::const_iterator it = params.find( |
| 512 rule + ":" + page_classification_str + ":" + instant_extended); | 514 rule + ":" + page_classification_str + ":" + instant_extended); |
| 513 if (it != params.end()) | 515 if (it != params.end()) |
| 514 return it->second; | 516 return it->second; |
| 515 // Fall back to the global page classification context. | 517 // Fall back to the global page classification context. |
| 516 it = params.find(rule + ":*:" + instant_extended); | 518 it = params.find(rule + ":*:" + instant_extended); |
| 517 if (it != params.end()) | 519 if (it != params.end()) |
| 518 return it->second; | 520 return it->second; |
| 519 // Fall back to the global instant extended context. | 521 // Fall back to the global instant extended context. |
| 520 it = params.find(rule + ":" + page_classification_str + ":*"); | 522 it = params.find(rule + ":" + page_classification_str + ":*"); |
| 521 if (it != params.end()) | 523 if (it != params.end()) |
| 522 return it->second; | 524 return it->second; |
| 523 // Look up rule in the global context. | 525 // Look up rule in the global context. |
| 524 it = params.find(rule + ":*:*"); | 526 it = params.find(rule + ":*:*"); |
| 525 return (it != params.end()) ? it->second : std::string(); | 527 return (it != params.end()) ? it->second : std::string(); |
| 526 } | 528 } |
| OLD | NEW |