You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by sh...@apache.org on 2022/02/03 17:07:34 UTC
[unomi] 01/01: - Change percentage to 0-100 base - Fix problem with class cast exceptions
This is an automated email from the ASF dual-hosted git repository.
shuber pushed a commit to branch UNOMI-537-fix-control-groups
in repository https://gitbox.apache.org/repos/asf/unomi.git
commit 3ce4cce48ebbe7a00041c57f6aed237874821d75
Author: Serge Huber <sh...@jahia.com>
AuthorDate: Thu Feb 3 18:07:21 2022 +0100
- Change percentage to 0-100 base
- Fix problem with class cast exceptions
---
.../resources/personalization-controlgroup.json | 2 +-
.../src/main/asciidoc/samples/twitter-sample.adoc | 4 ++--
.../impl/personalization/ControlGroup.java | 23 ++++++++++++++++++++
.../PersonalizationServiceImpl.java | 25 ++++++++++++++++------
4 files changed, 45 insertions(+), 9 deletions(-)
diff --git a/itests/src/test/resources/personalization-controlgroup.json b/itests/src/test/resources/personalization-controlgroup.json
index 8a931d7..8b8c74f 100644
--- a/itests/src/test/resources/personalization-controlgroup.json
+++ b/itests/src/test/resources/personalization-controlgroup.json
@@ -22,7 +22,7 @@
"strategyOptions": {
"threshold": -1,
"controlGroup" : {
- "percentage" : 1.0,
+ "percentage" : 100.0,
"displayName" : "First perso",
"path" : "/home/perso1.html",
"storeInSession" : ###storeInSession###
diff --git a/manual/src/main/asciidoc/samples/twitter-sample.adoc b/manual/src/main/asciidoc/samples/twitter-sample.adoc
index 7d7eeba..861708e 100644
--- a/manual/src/main/asciidoc/samples/twitter-sample.adoc
+++ b/manual/src/main/asciidoc/samples/twitter-sample.adoc
@@ -298,7 +298,7 @@ curl --location --request POST 'http://localhost:8181/context.json' \
"strategyOptions": {
"fallback": "var2",
"controlGroup" : {
- "percentage" : 0.1,
+ "percentage" : 10.0,
"displayName" : "Gender test control group",
"path" : "/gender-test",
"storeInSession" : true
@@ -339,7 +339,7 @@ curl --location --request POST 'http://localhost:8181/context.json' \
In the above example, we basically setup two variants : `var1` and `var2` and setup the `var2` to be the fallback variant
in case no variant is matched. We could of course specify more than a variant. The `strategy` indicates to the
-personalization service how to calculate the "winning" variant. In this case the strategy `matching-first` will return variants that match the current profile. We also use the `controlGroups` option to specify that we want to have a control group for this personalization. The `0.1` percentage value represents 10% (0 to 1) of traffic that will be assigned randomly to the control group. The control group will be stored in the profile and the session of the visitors if they were assigned to [...]
+personalization service how to calculate the "winning" variant. In this case the strategy `matching-first` will return variants that match the current profile. We also use the `controlGroups` option to specify that we want to have a control group for this personalization. The `10.0` percentage value represents 10% (0.0 to 100.0) of traffic that will be assigned randomly to the control group. The control group will be stored in the profile and the session of the visitors if they were assi [...]
Currently the following strategies are available:
diff --git a/services/src/main/java/org/apache/unomi/services/impl/personalization/ControlGroup.java b/services/src/main/java/org/apache/unomi/services/impl/personalization/ControlGroup.java
index d6435d0..01cbd9c 100644
--- a/services/src/main/java/org/apache/unomi/services/impl/personalization/ControlGroup.java
+++ b/services/src/main/java/org/apache/unomi/services/impl/personalization/ControlGroup.java
@@ -16,12 +16,21 @@
*/
package org.apache.unomi.services.impl.personalization;
+import org.apache.unomi.persistence.spi.CustomObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.text.ParseException;
import java.util.Date;
+import java.util.Map;
/**
* Represents a personalization control group, stored in a profile and/or a session
*/
public class ControlGroup {
+
+ private static final Logger logger = LoggerFactory.getLogger(ControlGroup.class.getName());
+
String id;
String displayName;
String path;
@@ -34,6 +43,20 @@ public class ControlGroup {
this.timeStamp = timeStamp;
}
+ public static ControlGroup fromMap(Map<String,Object> map) {
+ String id = (String) map.get("id");
+ String displayName = (String) map.get("displayName");
+ String path = (String) map.get("path");
+ String dateStr = (String) map.get("timeStamp");
+ Date date = null;
+ try {
+ date = CustomObjectMapper.getObjectMapper().getDateFormat().parse(dateStr);
+ } catch (ParseException e) {
+ logger.error("Error parsing control group date", e);
+ }
+ return new ControlGroup(id, displayName, path, date);
+ }
+
public String getId() {
return id;
}
diff --git a/services/src/main/java/org/apache/unomi/services/impl/personalization/PersonalizationServiceImpl.java b/services/src/main/java/org/apache/unomi/services/impl/personalization/PersonalizationServiceImpl.java
index eeef772..b5b24cd 100644
--- a/services/src/main/java/org/apache/unomi/services/impl/personalization/PersonalizationServiceImpl.java
+++ b/services/src/main/java/org/apache/unomi/services/impl/personalization/PersonalizationServiceImpl.java
@@ -34,6 +34,7 @@ import java.util.stream.Collectors;
public class PersonalizationServiceImpl implements PersonalizationService {
+ public static final String CONTROL_GROUPS_PROPERTY_NAME = "unomiControlGroups";
private BundleContext bundleContext;
private ProfileService profileService;
@@ -103,9 +104,13 @@ public class PersonalizationServiceImpl implements PersonalizationService {
List<ControlGroup> controlGroups = null;
if (storeInSession) {
- controlGroups = (List<ControlGroup>) session.getProperty("unomiControlGroups");
+ if (session.getProperty(CONTROL_GROUPS_PROPERTY_NAME) != null) {
+ controlGroups = ((List<Map<String, Object>>) session.getProperty(CONTROL_GROUPS_PROPERTY_NAME)).stream().map(ControlGroup::fromMap).collect(Collectors.toList());
+ }
} else {
- controlGroups = (List<ControlGroup>) profile.getProperty("unomiControlGroups");
+ if (profile.getProperty(CONTROL_GROUPS_PROPERTY_NAME) != null) {
+ controlGroups = ((List<Map<String, Object>>) profile.getProperty(CONTROL_GROUPS_PROPERTY_NAME)).stream().map(ControlGroup::fromMap).collect(Collectors.toList());
+ }
}
if (controlGroups == null) {
controlGroups = new ArrayList<>();
@@ -115,8 +120,16 @@ public class PersonalizationServiceImpl implements PersonalizationService {
// we already have an entry for this personalization so this means the profile is in the control group
profileInControlGroup = true;
} else {
- double randomDouble = controlGroupRandom.nextDouble();
- Double controlGroupPercentage = (Double) controlGroupMap.get("percentage");
+ double randomDouble = controlGroupRandom.nextDouble() * 100.0;
+ Object percentageObject = controlGroupMap.get("percentage");
+ Double controlGroupPercentage = null;
+ if (percentageObject != null) {
+ if (percentageObject instanceof Double) {
+ controlGroupPercentage = (Double) percentageObject;
+ } else if (percentageObject instanceof Integer) {
+ controlGroupPercentage = ((Integer) percentageObject).doubleValue();
+ }
+ }
if (randomDouble <= controlGroupPercentage) {
// Profile is elected to be in control group
@@ -127,10 +140,10 @@ public class PersonalizationServiceImpl implements PersonalizationService {
new Date());
controlGroups.add(controlGroup);
if (storeInSession) {
- session.setProperty("unomiControlGroups", controlGroups);
+ session.setProperty(CONTROL_GROUPS_PROPERTY_NAME, controlGroups);
changeType = EventService.SESSION_UPDATED;
} else {
- profile.setProperty("unomiControlGroups", controlGroups);
+ profile.setProperty(CONTROL_GROUPS_PROPERTY_NAME, controlGroups);
changeType = EventService.PROFILE_UPDATED;
}
}