Skip to content

Commit

Permalink
New Autofill suggestion ranking formula + VCN boost
Browse files Browse the repository at this point in the history
This CL implements changes that implements a new formula for ranking profiles and cards in autofill suggestion forms. These changes also provide a ranking boost for virtual cards in card suggestion lists.

The full description of this feature is described here: go/vcn-ranking-dd.

Bug: 1281695
Change-Id: If01800d2c4ef5cdcdd75a0033f2f065d670de963
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3526079
Reviewed-by: Jared Saul <jsaul@google.com>
Reviewed-by: Matthias Körber <koerber@google.com>
Commit-Queue: Alexander Tekle <alexandertekle@google.com>
Reviewed-by: Bo Liu <boliu@chromium.org>
Reviewed-by: Siyu An <siyua@chromium.org>
Reviewed-by: Jochen Eisinger <jochen@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1001167}
  • Loading branch information
Alexander Tekle authored and Chromium LUCI CQ committed May 9, 2022
1 parent d11606a commit d46a369
Show file tree
Hide file tree
Showing 28 changed files with 444 additions and 171 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ private ProductionSupportedFlagList() {}
Flag.baseFeature(AutofillFeatures.AUTOFILL_ACROSS_IFRAMES,
"Enable Autofill for frame-transcending forms (forms whose fields live in "
+ "different frames)."),
Flag.baseFeature(AutofillFeatures.AUTOFILL_ENABLE_RANKING_FORMULA,
"Enables new autofill suggestion ranking formula"),
Flag.baseFeature(AutofillFeatures.AUTOFILL_ENABLE_SUPPORT_FOR_MORE_STRUCTURE_IN_NAMES,
"Enables support for names with a rich structure including multiple last "
+ "names."),
Expand Down
4 changes: 4 additions & 0 deletions chrome/browser/about_flags.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8486,6 +8486,10 @@ const FeatureEntry kFeatureEntries[] = {
FEATURE_VALUE_TYPE(
password_manager::features::kPasswordEditDialogWithDetails)},
#endif // BUILDFLAG(IS_ANDROID)
{"autofill-enable-ranking-formula",
flag_descriptions::kAutofillEnableRankingFormulaName,
flag_descriptions::kAutofillEnableRankingFormulaDescription, kOsAll,
FEATURE_VALUE_TYPE(autofill::features::kAutofillEnableRankingFormula)},

{"autofill-enable-virtual-card-fido-enrollment",
flag_descriptions::kAutofillEnableVirtualCardFidoEnrollmentName,
Expand Down
5 changes: 5 additions & 0 deletions chrome/browser/flag-metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,11 @@
"owners": [ "siyua", "siashah@google.com" ],
"expiry_milestone": 106
},
{
"name": "autofill-enable-ranking-formula",
"owners": [ "alexandertekle@google.com", "koerber@google.com" ],
"expiry_milestone": 109
},
{
"name": "autofill-enable-sending-bcn-in-get-upload-details",
"owners": [
Expand Down
6 changes: 6 additions & 0 deletions chrome/browser/flag_descriptions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,12 @@ const char kAutofillEnableOffersInClankKeyboardAccessoryDescription[] =
"When enabled, offers will be displayed in the keyboard accessory when "
"available.";

const char kAutofillEnableRankingFormulaName[] =
"Enable new Autofill suggestion ranking formula";
const char kAutofillEnableRankingFormulaDescription[] =
"When enabled, Autofill will use a new ranking formula to rank Autofill "
"data model suggestions such as credit cards or profiles.";

const char kAutofillEnableSendingBcnInGetUploadDetailsName[] =
"Enable sending billing customer number in GetUploadDetails";
const char kAutofillEnableSendingBcnInGetUploadDetailsDescription[] =
Expand Down
3 changes: 3 additions & 0 deletions chrome/browser/flag_descriptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ extern const char kAutofillEnableOfferNotificationForPromoCodesDescription[];
extern const char kAutofillEnableOffersInClankKeyboardAccessoryName[];
extern const char kAutofillEnableOffersInClankKeyboardAccessoryDescription[];

extern const char kAutofillEnableRankingFormulaName[];
extern const char kAutofillEnableRankingFormulaDescription[];

extern const char kAutofillEnableSendingBcnInGetUploadDetailsName[];
extern const char kAutofillEnableSendingBcnInGetUploadDetailsDescription[];

Expand Down
2 changes: 2 additions & 0 deletions components/autofill/core/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,8 @@ static_library("test_support") {
"autofill_form_test_utils.h",
"autofill_test_utils.cc",
"autofill_test_utils.h",
"data_model/test_autofill_data_model.cc",
"data_model/test_autofill_data_model.h",
"geo/alternative_state_name_map_test_utils.cc",
"geo/alternative_state_name_map_test_utils.h",
"geo/mock_alternative_state_name_map_updater.cc",
Expand Down
2 changes: 2 additions & 0 deletions components/autofill/core/browser/autofill_test_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,8 @@ CreditCard GetVirtualCard() {
"5555555555554444", // Mastercard
"10", test::NextYear().c_str(), "1");
credit_card.set_record_type(CreditCard::RecordType::VIRTUAL_CARD);
credit_card.set_virtual_card_enrollment_state(
CreditCard::VirtualCardEnrollmentState::ENROLLED);
CreditCardTestApi(&credit_card).set_network_for_virtual_card(kMasterCard);
return credit_card;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1993,8 +1993,8 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
external_delegate_->CheckNoSuggestions(kDefaultPageID);
}

// Test that expired cards are ordered by frecency and are always suggested
// after non expired cards even if they have a higher frecency score.
// Test that expired cards are ordered by their ranking score and are always
// suggested after non expired cards even if they have a higher ranking score.
TEST_P(BrowserAutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_ExpiredCards) {
personal_data().ClearCreditCards();
Expand All @@ -2008,7 +2008,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
credit_card0.set_guid("00000000-0000-0000-0000-000000000001");
personal_data().AddCreditCard(credit_card0);

// Add an expired card with a higher frecency score.
// Add an expired card with a higher ranking score.
CreditCard credit_card1("287151C8-6AB1-487C-9095-28E80BE5DA15",
test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card1, "Clyde Barrow",
Expand All @@ -2019,7 +2019,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
credit_card1.set_use_date(AutofillClock::Now() - base::Days(10));
personal_data().AddCreditCard(credit_card1);

// Add an expired card with a lower frecency score.
// Add an expired card with a lower ranking score.
CreditCard credit_card2("1141084B-72D7-4B73-90CF-3D6AC154673B",
test::kEmptyOrigin);
credit_card2.set_use_count(3);
Expand Down
37 changes: 24 additions & 13 deletions components/autofill/core/browser/data_model/autofill_data_model.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "components/autofill/core/browser/data_model/autofill_metadata.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_features.h"
#include "url/gurl.h"

namespace autofill {
Expand All @@ -22,10 +23,30 @@ AutofillDataModel::AutofillDataModel(const std::string& guid,
}
AutofillDataModel::~AutofillDataModel() {}

int AutofillDataModel::GetDaysSinceLastUse(base::Time current_time) const {
DCHECK(current_time >= use_date_);

return (current_time - use_date_).InDays();
}

bool AutofillDataModel::IsVerified() const {
return !origin_.empty() && !GURL(origin_).is_valid();
}

double AutofillDataModel::GetRankingScore(base::Time current_time) const {
if (base::FeatureList::IsEnabled(features::kAutofillEnableRankingFormula)) {
// Exponentially decay the use count by the days since the data model was
// last used.
return log10(use_count_ + 1) *
exp(-GetDaysSinceLastUse(current_time) /
features::kAutofillRankingFormulaUsageHalfLife.Get());
}

// Default to legacy frecency scoring.
return -log(static_cast<double>(GetDaysSinceLastUse(current_time)) + 2) /
log(use_count_ + 1);
}

// TODO(crbug.com/629507): Add support for injected mock clock for testing.
void AutofillDataModel::RecordUse() {
++use_count_;
Expand All @@ -37,11 +58,11 @@ bool AutofillDataModel::UseDateEqualsInSeconds(
return !((other->use_date() - use_date()).InSeconds());
}

bool AutofillDataModel::HasGreaterFrecencyThan(
bool AutofillDataModel::HasGreaterRankingThan(
const AutofillDataModel* other,
base::Time comparison_time) const {
double score = GetFrecencyScore(comparison_time);
double other_score = other->GetFrecencyScore(comparison_time);
double score = GetRankingScore(comparison_time);
double other_score = other->GetRankingScore(comparison_time);

// Ties are broken by MRU, then by GUID comparison.
const double kEpsilon = 0.00001;
Expand All @@ -67,16 +88,6 @@ bool AutofillDataModel::SetMetadata(const AutofillMetadata metadata) {
return true;
}

double AutofillDataModel::GetFrecencyScore(base::Time time) const {
// The formula calculates a score based on both the frequency and the recency
// of the profile and leveraging the properties of the logarithmic function.
// DaysSinceLastUse() and |use_count_| are offset because their minimum values
// are respectively 0 and 1 but the formula requires at least a value of 2.
// Please update getFrecencyScore in ChromePaymentRequestService.java as well
// if below formula needs update.
return -log((time - use_date_).InDays() + 2) / log(use_count_ + 1);
}

bool AutofillDataModel::IsDeletable() const {
return IsAutofillEntryWithUseDateDeletable(use_date_);
}
Expand Down
27 changes: 15 additions & 12 deletions components/autofill/core/browser/data_model/autofill_data_model.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ class AutofillDataModel : public FormGroup {
AutofillDataModel(const std::string& guid, const std::string& origin);
~AutofillDataModel() override;

// Calculates the number of days since the model was last used by subtracting
// the model's last recent |use_date_| from the |current_time|.
int GetDaysSinceLastUse(base::Time current_time) const;

// Returns true if the data in this model was entered directly by the user,
// rather than automatically aggregated.
bool IsVerified() const;
Expand Down Expand Up @@ -71,12 +75,13 @@ class AutofillDataModel : public FormGroup {
modification_date_ = time;
}

// Compares two data models according to their frecency score. The score uses
// a combination of frequency and recency to determine the relevance of the
// profile. |comparison_time_| allows consistent sorting throughout the
// comparisons.
bool HasGreaterFrecencyThan(const AutofillDataModel* other,
base::Time comparison_time) const;
// Compares two data models according to their ranking score. The score uses
// a combination of use count and days since last use to determine the
// relevance of the profile. |comparison_time_| allows consistent sorting
// throughout the comparisons. A greater ranking score corresponds to a higher
// ranking on the suggestion list.
bool HasGreaterRankingThan(const AutofillDataModel* other,
base::Time comparison_time) const;

// Gets the metadata associated with this autofill data model.
virtual AutofillMetadata GetMetadata() const;
Expand All @@ -90,16 +95,14 @@ class AutofillDataModel : public FormGroup {
virtual bool IsDeletable() const;

protected:
// Calculate the ranking score of a card or profile depending on their use
// count and most recent use date.
virtual double GetRankingScore(base::Time current_time) const;

// Called to update |use_count_| and |use_date_| when this data model is
// the subject of user interaction (usually, when it's used to fill a form).
void RecordUse();

// Returns a score based on both the recency (relative to |time|) and
// frequency for the model. The score is a negative number where a higher
// value is more relevant. |time| is passed as a parameter to ensure
// consistent results.
double GetFrecencyScore(base::Time time) const;

private:
// A globally unique ID for this object.
std::string guid_;
Expand Down

0 comments on commit d46a369

Please sign in to comment.