This is an automated email from the ASF dual-hosted git repository.

jkevan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/unomi.git


The following commit(s) were added to refs/heads/master by this push:
     new aa4dde9d6 UNOMI-666: fix personalization that use score sorting and 
interests (new interests data structure) (#503)
aa4dde9d6 is described below

commit aa4dde9d6115e2dd708cabd69461d3ae3dc09e3e
Author: kevan Jahanshahi <ke...@jahia.com>
AuthorDate: Mon Sep 19 09:10:52 2022 +0200

    UNOMI-666: fix personalization that use score sorting and interests (new 
interests data structure) (#503)
---
 .../org/apache/unomi/itests/ContextServletIT.java  |  69 ++++++++
 .../resources/personalization-score-interests.json | 178 +++++++++++++++++++++
 .../unomi/rest/endpoints/ContextJsonEndpoint.java  |   2 -
 .../sorts/ScorePersonalizationStrategy.java        |  15 +-
 4 files changed, 257 insertions(+), 7 deletions(-)

diff --git a/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java 
b/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
index 6559c4660..cfa9275cd 100644
--- a/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
@@ -550,6 +550,75 @@ public class ContextServletIT extends BaseIT {
         assertEquals("Invalid response code", 200, response.getStatusCode());
     }
 
+    @Test
+    public void testScorePersonalizationStrategy_Interests() throws Exception {
+        // Test request before adding interests to current profile.
+        HttpPost request = new HttpPost(getFullUrl(CONTEXT_URL));
+        request.setEntity(new 
StringEntity(getValidatedBundleJSON("personalization-score-interests.json", 
null), ContentType.APPLICATION_JSON));
+        TestUtils.RequestResponse response = 
TestUtils.executeContextJSONRequest(request);
+        ContextResponse contextResponse = response.getContextResponse();
+        List<String> variants = 
contextResponse.getPersonalizations().get("perso-by-interest");
+        assertEquals("Invalid response code", 200, response.getStatusCode());
+        assertEquals("Perso should be empty, profile is empty", 0, 
variants.size());
+
+        // set profile for matching
+        Profile profile = profileService.load(TEST_PROFILE_ID);
+        profile.setProperty("age", 30);
+        profileService.save(profile);
+        keepTrying("Profile " + TEST_PROFILE_ID + " not found in the required 
time", () -> profileService.load(TEST_PROFILE_ID),
+                savedProfile -> (savedProfile != null && 
savedProfile.getProperty("age").equals(30)), DEFAULT_TRYING_TIMEOUT, 
DEFAULT_TRYING_TRIES);
+
+        // check results of the perso now
+        request = new HttpPost(getFullUrl(CONTEXT_URL));
+        request.setEntity(new 
StringEntity(getValidatedBundleJSON("personalization-score-interests.json", 
null), ContentType.APPLICATION_JSON));
+        response = TestUtils.executeContextJSONRequest(request);
+        contextResponse = response.getContextResponse();
+        variants = 
contextResponse.getPersonalizations().get("perso-by-interest");
+        assertEquals("Invalid response code", 200, response.getStatusCode());
+        assertEquals("Perso should contains the good number of variants", 1, 
variants.size());
+        assertEquals("Variant is not the expected one", 
"matching-fishing-interests-custom-score-100-variant-expected-score-120", 
variants.get(0));
+
+        // modify profile to add interests
+        profile = profileService.load(TEST_PROFILE_ID);
+        List<Map<String, Object>> interests = new ArrayList<>();
+        Map<String, Object> interest1 = new HashMap<>();
+        interest1.put("key", "cars");
+        interest1.put("value", 50);
+        interests.add(interest1);
+        Map<String, Object> interest2 = new HashMap<>();
+        interest2.put("key", "football");
+        interest2.put("value", 40);
+        interests.add(interest2);
+        Map<String, Object> interest3 = new HashMap<>();
+        interest3.put("key", "tennis");
+        interest3.put("value", 30);
+        interests.add(interest3);
+        Map<String, Object> interest4 = new HashMap<>();
+        interest4.put("key", "fishing");
+        interest4.put("value", 20);
+        interests.add(interest4);
+        profile.setProperty("interests", interests);
+        profileService.save(profile);
+        keepTrying("Profile " + TEST_PROFILE_ID + " not found in the required 
time", () -> profileService.load(TEST_PROFILE_ID),
+                savedProfile -> (savedProfile != null && 
savedProfile.getProperty("interests") != null), DEFAULT_TRYING_TIMEOUT, 
DEFAULT_TRYING_TRIES);
+
+        // re test now that profiles has interests
+        request = new HttpPost(getFullUrl(CONTEXT_URL));
+        request.setEntity(new 
StringEntity(getValidatedBundleJSON("personalization-score-interests.json", 
null), ContentType.APPLICATION_JSON));
+        response = TestUtils.executeContextJSONRequest(request);
+        contextResponse = response.getContextResponse();
+        variants = 
contextResponse.getPersonalizations().get("perso-by-interest");
+        assertEquals("Invalid response code", 200, response.getStatusCode());
+        assertEquals("Perso should contains the good number of variants", 7, 
variants.size());
+        assertEquals("Variant is not the expected one", 
"matching-fishing-interests-custom-score-100-variant-expected-score-120", 
variants.get(0));
+        assertEquals("Variant is not the expected one", 
"matching-football-cars-interests-variant-expected-score-91", variants.get(1));
+        assertEquals("Variant is not the expected one", 
"not-matching-football-cars-interests-variant-expected-score-90", 
variants.get(2));
+        assertEquals("Variant is not the expected one", 
"not-matching-tennis-fishing-interests-variant-expected-score-50", 
variants.get(3));
+        assertEquals("Variant is not the expected one", 
"matching-football-interests-variant-expected-score-51", variants.get(4));
+        assertEquals("Variant is not the expected one", 
"matching-tennis-interests-variant-expected-score-31", variants.get(5));
+        assertEquals("Variant is not the expected one", 
"not-matching-tennis-interests-custom-score-100-variant-expected-score-30", 
variants.get(6));
+    }
+
     @Test
     public void testPersonalizationWithControlGroup() throws Exception {
 
diff --git a/itests/src/test/resources/personalization-score-interests.json 
b/itests/src/test/resources/personalization-score-interests.json
new file mode 100644
index 000000000..0f19d62a5
--- /dev/null
+++ b/itests/src/test/resources/personalization-score-interests.json
@@ -0,0 +1,178 @@
+{
+  "source": {
+    "itemId": "CMSServer",
+    "itemType": "custom",
+    "scope": "acme",
+    "properties": {}
+  },
+  "requireSegments": true,
+  "requiredProfileProperties": [
+    "*"
+  ],
+  "requiredSessionProperties": [
+    "*"
+  ],
+  "personalizations": [
+    {
+      "id": "perso-by-interest",
+      "strategy": "score-sorted",
+      "strategyOptions": {
+        "threshold": 25
+      },
+      "contents": [
+        {
+          "id": "matching-football-cars-interests-variant-expected-score-91",
+          "filters": [
+            {
+              "condition": {
+                "type": "profilePropertyCondition",
+                "parameterValues": {
+                  "propertyName": "properties.age",
+                  "propertyValueInteger": "25",
+                  "comparisonOperator": "greaterThan"
+                }
+              }
+            }
+          ],
+          "properties": {
+            "interests": "football cars"
+          }
+        },
+        {
+          "id": 
"not-matching-football-cars-interests-variant-expected-score-90",
+          "filters": [
+            {
+              "condition": {
+                "type": "profilePropertyCondition",
+                "parameterValues": {
+                  "propertyName": "properties.age",
+                  "propertyValueInteger": "35",
+                  "comparisonOperator": "greaterThan"
+                }
+              }
+            }
+          ],
+          "properties": {
+            "interests": "football cars"
+          }
+        },
+        {
+          "id": "matching-football-interests-variant-expected-score-51",
+          "filters": [
+            {
+              "condition": {
+                "type": "profilePropertyCondition",
+                "parameterValues": {
+                  "propertyName": "properties.age",
+                  "propertyValueInteger": "25",
+                  "comparisonOperator": "greaterThan"
+                }
+              }
+            }
+          ],
+          "properties": {
+            "interests": "football"
+          }
+        },
+        {
+          "id": "less-threshold-fishing-interests-variant-expected-score-21",
+          "filters": [
+            {
+              "condition": {
+                "type": "profilePropertyCondition",
+                "parameterValues": {
+                  "propertyName": "properties.age",
+                  "propertyValueInteger": "25",
+                  "comparisonOperator": "greaterThan"
+                }
+              }
+            }
+          ],
+          "properties": {
+            "interests": "fishing"
+          }
+        },
+        {
+          "id": "matching-tennis-interests-variant-expected-score-31",
+          "filters": [
+            {
+              "condition": {
+                "type": "profilePropertyCondition",
+                "parameterValues": {
+                  "propertyName": "properties.age",
+                  "propertyValueInteger": "25",
+                  "comparisonOperator": "greaterThan"
+                }
+              }
+            }
+          ],
+          "properties": {
+            "interests": "tennis"
+          }
+        },
+        {
+          "id": 
"not-matching-tennis-fishing-interests-variant-expected-score-50",
+          "filters": [
+            {
+              "condition": {
+                "type": "profilePropertyCondition",
+                "parameterValues": {
+                  "propertyName": "properties.age",
+                  "propertyValueInteger": "35",
+                  "comparisonOperator": "greaterThan"
+                }
+              }
+            }
+          ],
+          "properties": {
+            "interests": "tennis fishing"
+          }
+        },
+        {
+          "id": 
"not-matching-tennis-interests-custom-score-100-variant-expected-score-30",
+          "filters": [
+            {
+              "condition": {
+                "type": "profilePropertyCondition",
+                "parameterValues": {
+                  "propertyName": "properties.age",
+                  "propertyValueInteger": "35",
+                  "comparisonOperator": "greaterThan"
+                }
+              },
+              "properties": {
+                "score": 100
+              }
+            }
+          ],
+          "properties": {
+            "interests": "tennis"
+          }
+        },
+        {
+          "id": 
"matching-fishing-interests-custom-score-100-variant-expected-score-120",
+          "filters": [
+            {
+              "condition": {
+                "type": "profilePropertyCondition",
+                "parameterValues": {
+                  "propertyName": "properties.age",
+                  "propertyValueInteger": "25",
+                  "comparisonOperator": "greaterThan"
+                }
+              },
+              "properties": {
+                "score": 100
+              }
+            }
+          ],
+          "properties": {
+            "interests": "fishing"
+          }
+        }
+      ]
+    }
+  ],
+  "sessionId": "dummy-session",
+  "profileId": "test-profile-id"
+}
\ No newline at end of file
diff --git 
a/rest/src/main/java/org/apache/unomi/rest/endpoints/ContextJsonEndpoint.java 
b/rest/src/main/java/org/apache/unomi/rest/endpoints/ContextJsonEndpoint.java
index 9d2a3c661..6207845f8 100644
--- 
a/rest/src/main/java/org/apache/unomi/rest/endpoints/ContextJsonEndpoint.java
+++ 
b/rest/src/main/java/org/apache/unomi/rest/endpoints/ContextJsonEndpoint.java
@@ -157,12 +157,10 @@ public class ContextJsonEndpoint {
         // init ids
         String profileId = null;
         String scope = null;
-        List<Event> events = null;
         if (contextRequest != null) {
             scope = contextRequest.getSource() != null ? 
contextRequest.getSource().getScope() : scope;
             sessionId = contextRequest.getSessionId() != null ? 
contextRequest.getSessionId() : sessionId;
             profileId = contextRequest.getProfileId();
-            events = contextRequest.getEvents();
         }
 
         // build public context, profile + session creation/anonymous etc ...
diff --git 
a/services/src/main/java/org/apache/unomi/services/sorts/ScorePersonalizationStrategy.java
 
b/services/src/main/java/org/apache/unomi/services/sorts/ScorePersonalizationStrategy.java
index 7e636d32f..82bcc165b 100644
--- 
a/services/src/main/java/org/apache/unomi/services/sorts/ScorePersonalizationStrategy.java
+++ 
b/services/src/main/java/org/apache/unomi/services/sorts/ScorePersonalizationStrategy.java
@@ -49,10 +49,15 @@ public class ScorePersonalizationStrategy implements 
PersonalizationStrategy {
 
             String interestList = (String) 
(personalizedContent.getProperties() != null ? 
personalizedContent.getProperties().get("interests") : null);
             if (interestList != null) {
-                Map<String,Integer> interestValues = (Map<String, Integer>) 
profile.getProperties().get("interests");
-                for (String interest : interestList.split(" ")) {
-                    if (interestValues != null && interestValues.get(interest) 
!= null) {
-                        score += interestValues.get(interest);
+                List<Map<String, Object>> profileInterests = (List<Map<String, 
Object>>) profile.getProperties().get("interests");
+                if (profileInterests != null) {
+                    for (String interest : interestList.split(" ")) {
+                        for (Map<String, Object> profileInterest : 
profileInterests) {
+                            if (profileInterest.get("key").equals(interest)){
+                                score += ((Number) 
profileInterest.get("value")).intValue();
+                                break;
+                            }
+                        }
                     }
                 }
             }
@@ -74,7 +79,7 @@ public class ScorePersonalizationStrategy implements 
PersonalizationStrategy {
                     Condition condition = filter.getCondition();
                     if (condition != null && condition.getConditionTypeId() != 
null) {
                         if (profileService.matchCondition(condition, profile, 
session)) {
-                            if (filter.getProperties().get("score") != null) {
+                            if (filter.getProperties() != null && 
filter.getProperties().get("score") != null) {
                                 score += (int) 
filter.getProperties().get("score");
                             } else {
                                 score += 1;

Reply via email to