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;
                         }
                     }