-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Have bandit logger separate out context #5
Conversation
@@ -45,7 +45,7 @@ private Optional<EppoValue> getAssignmentValue( | |||
String subjectKey, | |||
String flagKey, | |||
EppoAttributes subjectAttributes, | |||
Map<String, EppoAttributes> assignmentOptions | |||
Map<String, EppoAttributes> actionsWithAttributes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
after coming back to it, I decided to rename this variable to be more bandit-centric and clear on what it is.
return eppoAttributes.entrySet().stream().filter(e -> !e.getValue().isNumeric() && !e.getValue().isNull() | ||
).collect(Collectors.toMap( | ||
Map.Entry::getKey, | ||
e -> e.getValue().toString()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
toString()
is used over stringValue()
because we want the string representation of non-string-typed EppoValues (e.g., Booleans)
@@ -4,5 +4,5 @@ | |||
* Assignment Logger Interface | |||
*/ | |||
public interface IBanditLogger { | |||
public void logBanditAction(BanditLogData logData); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public
is implied for interfaces 🪓
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking great! Only significant issue is parallel to the one in the previous PR, on how to handle categorical attributes that could be numeric (but aren't).
if (eppoAttributes == null) { | ||
return Map.of(); | ||
} | ||
return eppoAttributes.entrySet().stream().filter(e -> !e.getValue().isNumeric() && !e.getValue().isNull() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same considerations as in the previous PR. If my understanding is correct, we should remove the !e.getValue().isNumeric()
condition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to know if the value was initialized with a truly numeric value and use that.
String variation, | ||
String subject, | ||
String action, | ||
Float actionProbability, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this should be Double
, since computeActionWeights
returns probabilities/weights as doubles.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yes great catch!
assertEquals(0.3333, capturedBanditLog.actionProbability, 0.0002); | ||
assertEquals("cold start", capturedBanditLog.modelVersion); | ||
} | ||
|
||
@Test | ||
public void testBanditModelActionLogging() { | ||
// Note: some of the passed in attributes are not used for scoring, but we do still want to make sure they are logged |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good test! We definitely want to log "new" attributes, so that they can be used for the next model retrain.
"days_since_signup", EppoValue.valueOf(130) // note: unused for scoring (which looks for account_age) | ||
"gender_identity", EppoValue.valueOf("female"), | ||
"days_since_signup", EppoValue.valueOf(130), // unused for scoring (which looks for account_age) | ||
"is_premium", EppoValue.valueOf(false), // unused for scoring |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once we settle the question of categorical value that could cast to numeric (but are not), we should add a test to crystalize that behavior. Could be "account_tier", EppoValue.valueOf("2")
, for example.
assertEquals(Map.of("account_age", 90.0), capturedBanditLog.subjectNumericAttributes); | ||
assertEquals(Map.of("loyalty_tier", "gold", "is_account_admin", "false"), capturedBanditLog.subjectCategoricalAttributes); | ||
assertEquals(Map.of("num_past_purchases", 0.0), capturedBanditLog.actionNumericAttributes); | ||
assertEquals(Map.of("brand", "skechers", "has_promo_code", "true"), capturedBanditLog.actionCategoricalAttributes); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -441,11 +462,17 @@ public void testBanditControlAction() { | |||
|
|||
Set<String> banditActions = Set.of("option1", "option2", "option3"); | |||
|
|||
EppoAttributes subjectAttributes = new EppoAttributes(Map.of( | |||
"account_age", EppoValue.valueOf(90), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not super familiar with Java; TIL integer types are converted to double automatically
null, | ||
null | ||
null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public String action;
public Float actionProbability; --> null
public String modelVersion; --> null
What's an example of a "NonBandit" action string?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any action not selected by the bandit, such as something selected by a recommendation algorithm.
* add graceful mode by default that does not throw exceptions (FF-949) (Eppo-exp#29) * add graceful mode by default that does not throw exceptions (FF-949) * test graceful mode on and off * test all functions * remove from javadoc * Bump com.github.tomakehurst:wiremock-jre8 from 2.33.2 to 2.35.1 (Eppo-exp#28) Bumps [com.github.tomakehurst:wiremock-jre8](https://github.com/wiremock/wiremock) from 2.33.2 to 2.35.1. - [Release notes](https://github.com/wiremock/wiremock/releases) - [Commits](wiremock/wiremock@2.33.2...2.35.1) --- updated-dependencies: - dependency-name: com.github.tomakehurst:wiremock-jre8 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * add compatibility for java 8 (Eppo-exp#35) * java8 compatibility using apache httpclient * cleanup * added timeouts * add maven-gpg-plugin * test across java 8, 11, 17 * pom * remove List.of * fix test * eppo value * fix plugin * profile --------- Co-authored-by: Gaurav Arora <gauravarora@Gauravs-MacBook-Pro.local> * Bump org.apache.httpcomponents:httpclient from 4.5.10 to 4.5.13 (Eppo-exp#36) Bumps org.apache.httpcomponents:httpclient from 4.5.10 to 4.5.13. --- updated-dependencies: - dependency-name: org.apache.httpcomponents:httpclient dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * [EN-17858] FetchConfigurationsTask is more fault tolerant (#5) (Eppo-exp#32) * [EN-17858] FetchConfigurationsTask is more fault tolerant * revert change to pom.xml, thereby having a single, clean commit that can be merged back to the Eppo main repo * bump to version 2.2.0 (Eppo-exp#38) * add support for semver rule evaluation (FF-1569) (Eppo-exp#39) * add support for semver rule evaluation (FF-1569) * azul builds * adjust unit tests for semver comparison * numeric first * add back in isXXX checks * helper function for JSON string serialization * rename variation to banditKey for bandit logging * remove accidentally added junit --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Leo Romanovsky <leoromanovsky@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Gaurav Arora <gauravarora@Gauravs-MacBook-Pro.local> Co-authored-by: Simon Dale <33907262+simondale00@users.noreply.github.com>
Eppo Internal:
🎟️ Ticket: FF-1426 - Adjust bandit logger to separate context by subject and action, and numeric and categorical attributes
🗺️ Design Review: Bandits Engineering Design (Relevant Section: 1/31 Data Sync)
🗨️ Slack Thread: ...are we ok with these property names?...
Description
To simplify using context to train the bandit, we want to have the SDKs separate out context by numeric (numbers) and categorical (everything else) attributes. We also want these separated by subject and action in the off chance two things are named the same. Therefore,
BanditLogData
has been adjusted to have four fields for use by the customer's logger:The intention is for the customer to then log these in four different columns in their
bandit_assignments
table.Updated the tests in
EppoClientTest
to ensure things were sorted out correctly for bothgetStringAssignment()
andlogNonBanditAction()
.