Skip to content
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

Merged
merged 21 commits into from
Feb 15, 2024

Conversation

aarsilv
Copy link
Collaborator

@aarsilv aarsilv commented Feb 13, 2024

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:

Map<String, Double> subjectNumericAttributes,
Map<String, String> subjectCategoricalAttributes,
Map<String, Double> actionNumericAttributes,
Map<String, String> actionCategoricalAttributes

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 both getStringAssignment() and logNonBanditAction().

@@ -45,7 +45,7 @@ private Optional<EppoValue> getAssignmentValue(
String subjectKey,
String flagKey,
EppoAttributes subjectAttributes,
Map<String, EppoAttributes> assignmentOptions
Map<String, EppoAttributes> actionsWithAttributes
Copy link
Collaborator Author

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())
Copy link
Collaborator Author

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);
Copy link
Collaborator Author

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 🪓

@aarsilv aarsilv marked this pull request as ready for review February 13, 2024 21:19
Copy link

@giorgiomartini0 giorgiomartini0 left a 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()

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.

Copy link
Collaborator Author

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,

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.

Copy link
Collaborator Author

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

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

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.

@aarsilv aarsilv assigned aarsilv and unassigned giorgiomartini0 Feb 13, 2024
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);

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),

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,

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?

Copy link
Collaborator Author

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.

Base automatically changed from aaron/ff-1535/use-bandit-parameters to main February 15, 2024 22:11
@aarsilv aarsilv merged commit 7fcf0a5 into main Feb 15, 2024
1 check passed
@aarsilv aarsilv deleted the aaron/ff-1546/separate-logger-context branch February 15, 2024 22:46
aarsilv pushed a commit that referenced this pull request Mar 22, 2024
…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
aarsilv added a commit that referenced this pull request Mar 22, 2024
* 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants