OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "components/ntp_snippets/category_rankers/click_based_category_ranker.h
" | 5 #include "components/ntp_snippets/category_rankers/click_based_category_ranker.h
" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/memory/ptr_util.h" | 9 #include "base/memory/ptr_util.h" |
10 #include "base/values.h" | 10 #include "base/values.h" |
11 #include "components/ntp_snippets/category_rankers/constant_category_ranker.h" | 11 #include "components/ntp_snippets/category_rankers/constant_category_ranker.h" |
| 12 #include "components/ntp_snippets/features.h" |
12 #include "components/ntp_snippets/pref_names.h" | 13 #include "components/ntp_snippets/pref_names.h" |
13 #include "components/prefs/pref_registry_simple.h" | 14 #include "components/prefs/pref_registry_simple.h" |
14 #include "components/prefs/pref_service.h" | 15 #include "components/prefs/pref_service.h" |
| 16 #include "components/variations/variations_associated_data.h" |
15 | 17 |
16 namespace ntp_snippets { | 18 namespace ntp_snippets { |
17 | 19 |
18 namespace { | 20 namespace { |
19 | 21 |
20 // In order to increase stability and predictability of the order, an extra | 22 // In order to increase stability and predictability of the order, an extra |
21 // level of "confidence" is required before moving a category upwards. In other | 23 // level of "confidence" is required before moving a category upwards. In other |
22 // words, the category is moved not when it reaches the previous one, but rather | 24 // words, the category is moved not when it reaches the previous one, but rather |
23 // when it leads by some amount. We refer to this required extra "confidence" as | 25 // when it leads by some amount. We refer to this required extra "confidence" as |
24 // a passing margin. Each position has its own passing margin. The category is | 26 // a passing margin. Each position has its own passing margin. The category is |
(...skipping 24 matching lines...) Expand all Loading... |
49 const base::TimeDelta kTimeBetweenDecays = base::TimeDelta::FromDays(1); | 51 const base::TimeDelta kTimeBetweenDecays = base::TimeDelta::FromDays(1); |
50 | 52 |
51 // Decay factor as a fraction. The current value approximates the seventh root | 53 // Decay factor as a fraction. The current value approximates the seventh root |
52 // of 0.5. This yields a 50% decay per seven decays. Seven weak decays are used | 54 // of 0.5. This yields a 50% decay per seven decays. Seven weak decays are used |
53 // instead of one 50% decay in order to decrease difference of click weight in | 55 // instead of one 50% decay in order to decrease difference of click weight in |
54 // time. | 56 // time. |
55 const int kDecayFactorNumerator = 91; | 57 const int kDecayFactorNumerator = 91; |
56 const int kDecayFactorDenominator = 100; // pow(0.91, 7) = 0.517 | 58 const int kDecayFactorDenominator = 100; // pow(0.91, 7) = 0.517 |
57 | 59 |
58 // Number of positions by which a dismissed category is downgraded. | 60 // Number of positions by which a dismissed category is downgraded. |
59 const int kDismissedCategoryPenalty = 1; | 61 const int kDefaultDismissedCategoryPenalty = 1; |
| 62 const char* kDismissedCategoryPenaltyParamName = |
| 63 "click_based_category_ranker-dismissed_category_penalty"; |
60 | 64 |
61 const char kCategoryIdKey[] = "category"; | 65 const char kCategoryIdKey[] = "category"; |
62 const char kClicksKey[] = "clicks"; | 66 const char kClicksKey[] = "clicks"; |
63 | 67 |
| 68 int GetDismissedCategoryPenaltyVariationValue() { |
| 69 return variations::GetVariationParamByFeatureAsInt( |
| 70 kCategoryRanker, kDismissedCategoryPenaltyParamName, |
| 71 kDefaultDismissedCategoryPenalty); |
| 72 } |
| 73 |
64 } // namespace | 74 } // namespace |
65 | 75 |
66 ClickBasedCategoryRanker::ClickBasedCategoryRanker( | 76 ClickBasedCategoryRanker::ClickBasedCategoryRanker( |
67 PrefService* pref_service, | 77 PrefService* pref_service, |
68 std::unique_ptr<base::Clock> clock) | 78 std::unique_ptr<base::Clock> clock) |
69 : pref_service_(pref_service), clock_(std::move(clock)) { | 79 : pref_service_(pref_service), clock_(std::move(clock)) { |
70 if (!ReadOrderFromPrefs(&ordered_categories_)) { | 80 if (!ReadOrderFromPrefs(&ordered_categories_)) { |
71 // TODO(crbug.com/676273): Handle adding new hardcoded KnownCategories to | 81 // TODO(crbug.com/676273): Handle adding new hardcoded KnownCategories to |
72 // existing order from prefs. Currently such new category is completely | 82 // existing order from prefs. Currently such new category is completely |
73 // ignored and may be never shown. | 83 // ignored and may be never shown. |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 StoreOrderToPrefs(ordered_categories_); | 191 StoreOrderToPrefs(ordered_categories_); |
182 } | 192 } |
183 | 193 |
184 void ClickBasedCategoryRanker::OnCategoryDismissed(Category category) { | 194 void ClickBasedCategoryRanker::OnCategoryDismissed(Category category) { |
185 if (!ContainsCategory(category)) { | 195 if (!ContainsCategory(category)) { |
186 LOG(DFATAL) << "The category with ID " << category.id() | 196 LOG(DFATAL) << "The category with ID " << category.id() |
187 << " has not been added using AppendCategoryIfNecessary."; | 197 << " has not been added using AppendCategoryIfNecessary."; |
188 return; | 198 return; |
189 } | 199 } |
190 | 200 |
| 201 const int penalty = GetDismissedCategoryPenaltyVariationValue(); |
| 202 if (penalty == 0) { |
| 203 // The dismissed category penalty is turned off, the call is ignored. |
| 204 return; |
| 205 } |
| 206 |
191 std::vector<RankedCategory>::iterator current = FindCategory(category); | 207 std::vector<RankedCategory>::iterator current = FindCategory(category); |
192 for (int downgrade = 0; downgrade < kDismissedCategoryPenalty; ++downgrade) { | 208 for (int downgrade = 0; downgrade < penalty; ++downgrade) { |
193 std::vector<RankedCategory>::iterator next = current + 1; | 209 std::vector<RankedCategory>::iterator next = current + 1; |
194 if (next == ordered_categories_.end()) { | 210 if (next == ordered_categories_.end()) { |
195 break; | 211 break; |
196 } | 212 } |
197 std::swap(*current, *next); | 213 std::swap(*current, *next); |
198 current = next; | 214 current = next; |
199 } | 215 } |
200 | 216 |
201 DCHECK(current != ordered_categories_.begin()); | 217 DCHECK(current != ordered_categories_.begin()); |
202 std::vector<RankedCategory>::iterator previous = current - 1; | 218 std::vector<RankedCategory>::iterator previous = current - 1; |
(...skipping 22 matching lines...) Expand all Loading... |
225 return kPassingMargin; | 241 return kPassingMargin; |
226 } | 242 } |
227 | 243 |
228 // static | 244 // static |
229 int ClickBasedCategoryRanker::GetNumTopCategoriesWithExtraMargin() { | 245 int ClickBasedCategoryRanker::GetNumTopCategoriesWithExtraMargin() { |
230 return kNumTopCategoriesWithExtraMargin; | 246 return kNumTopCategoriesWithExtraMargin; |
231 } | 247 } |
232 | 248 |
233 // static | 249 // static |
234 int ClickBasedCategoryRanker::GetDismissedCategoryPenalty() { | 250 int ClickBasedCategoryRanker::GetDismissedCategoryPenalty() { |
235 return kDismissedCategoryPenalty; | 251 return GetDismissedCategoryPenaltyVariationValue(); |
236 } | 252 } |
237 | 253 |
238 ClickBasedCategoryRanker::RankedCategory::RankedCategory(Category category, | 254 ClickBasedCategoryRanker::RankedCategory::RankedCategory(Category category, |
239 int clicks) | 255 int clicks) |
240 : category(category), clicks(clicks) {} | 256 : category(category), clicks(clicks) {} |
241 | 257 |
242 // Returns passing margin for a given position taking into account whether it is | 258 // Returns passing margin for a given position taking into account whether it is |
243 // a top category. | 259 // a top category. |
244 int ClickBasedCategoryRanker::GetPositionPassingMargin( | 260 int ClickBasedCategoryRanker::GetPositionPassingMargin( |
245 std::vector<RankedCategory>::const_iterator category_position) const { | 261 std::vector<RankedCategory>::const_iterator category_position) const { |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 num_pending_decays * kTimeBetweenDecays); | 398 num_pending_decays * kTimeBetweenDecays); |
383 | 399 |
384 if (executed_decays > 0) { | 400 if (executed_decays > 0) { |
385 StoreOrderToPrefs(ordered_categories_); | 401 StoreOrderToPrefs(ordered_categories_); |
386 return true; | 402 return true; |
387 } | 403 } |
388 return false; | 404 return false; |
389 } | 405 } |
390 | 406 |
391 } // namespace ntp_snippets | 407 } // namespace ntp_snippets |
OLD | NEW |