You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by jk...@apache.org on 2022/06/17 17:46:51 UTC

[unomi] branch nestedCondition created (now 2646c8312)

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

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


      at 2646c8312 UNOMI-585: introduce new nestedCondition and set profile.properties.interests as nested

This branch includes the following new commits:

     new 709c32d8b UNOMI-585: introduce new nestedCondition and set profile.properties.interests as nested
     new 2646c8312 UNOMI-585: introduce new nestedCondition and set profile.properties.interests as nested

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[unomi] 01/02: UNOMI-585: introduce new nestedCondition and set profile.properties.interests as nested

Posted by jk...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 709c32d8bb5128877c0698329e693bd955a096c1
Author: Kevan <ke...@jahia.com>
AuthorDate: Fri Jun 17 19:45:59 2022 +0200

    UNOMI-585: introduce new nestedCondition and set profile.properties.interests as nested
---
 .../unomi/itests/ConditionESQueryBuilderIT.java    |  10 +-
 .../apache/unomi/itests/ConditionEvaluatorIT.java  |  69 +++++++++++
 persistence-elasticsearch/core/pom.xml             |   3 +-
 .../resources/META-INF/cxs/mappings/profile.json   |   3 +
 .../conditions/NestedConditionESQueryBuilder.java  |  46 ++++++++
 .../conditions/NestedConditionEvaluator.java       | 129 +++++++++++++++++++++
 .../META-INF/cxs/conditions/nestedCondition.json   |  29 +++++
 .../resources/OSGI-INF/blueprint/blueprint.xml     |  25 +++-
 .../conditions/NestedConditionEvaluatorTest.java   | 110 ++++++++++++++++++
 pom.xml                                            |   1 +
 10 files changed, 419 insertions(+), 6 deletions(-)

diff --git a/itests/src/test/java/org/apache/unomi/itests/ConditionESQueryBuilderIT.java b/itests/src/test/java/org/apache/unomi/itests/ConditionESQueryBuilderIT.java
index 3e4333c96..da8dabe03 100644
--- a/itests/src/test/java/org/apache/unomi/itests/ConditionESQueryBuilderIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/ConditionESQueryBuilderIT.java
@@ -44,16 +44,24 @@ public class ConditionESQueryBuilderIT extends ConditionEvaluatorIT {
         return list.contains(item);
     }
 
+    @Override
+    protected boolean evalEmpty(Condition c) {
+        @SuppressWarnings("unchecked")
+        List<Item> list = persistenceService.query(c,null,(Class<Item>) emptyItem.getClass());
+        return list.contains(emptyItem);
+    }
+
     @Before
     public void setUp() {
         super.setUp();
         persistenceService.save(item);
+        persistenceService.save(emptyItem);
         persistenceService.refresh();
     }
 
     @After
     public void tearDown() {
         persistenceService.remove(item.getItemId(), item.getClass());
+        persistenceService.remove(emptyItem.getItemId(), emptyItem.getClass());
     }
-
 }
diff --git a/itests/src/test/java/org/apache/unomi/itests/ConditionEvaluatorIT.java b/itests/src/test/java/org/apache/unomi/itests/ConditionEvaluatorIT.java
index 574c340f4..c9eb4017a 100644
--- a/itests/src/test/java/org/apache/unomi/itests/ConditionEvaluatorIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/ConditionEvaluatorIT.java
@@ -47,6 +47,7 @@ import static org.junit.Assert.*;
 public class ConditionEvaluatorIT extends BaseIT {
     protected ConditionBuilder builder;
     protected Item item;
+    protected Item emptyItem;
     protected Date lastVisit;
 
     @Inject @Filter(timeout = 600000)
@@ -58,6 +59,10 @@ public class ConditionEvaluatorIT extends BaseIT {
         return persistenceService.testMatch(c, item);
     }
 
+    protected boolean evalEmpty(Condition c) {
+        return persistenceService.testMatch(c, emptyItem);
+    }
+
     @Before
     public void setUp() {
         assertNotNull("Definition service should be available", definitionsService);
@@ -72,8 +77,21 @@ public class ConditionEvaluatorIT extends BaseIT {
         profile.setProperty("gender", "female");
         profile.setProperty("lastVisit", lastVisit);
         profile.setProperty("randomStats", 0.15);
+
+        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", 15);
+        interests.add(interest2);
+        profile.setProperty("interests", interests);
         profile.setSegments(new HashSet<>(Arrays.asList("s1", "s2", "s3")));
         item = profile;
+
+        emptyItem = new Profile("profile-" + UUID.randomUUID().toString());
     }
 
     @Test
@@ -219,4 +237,55 @@ public class ConditionEvaluatorIT extends BaseIT {
         ).build();
         assertTrue(eval(condition));
     }
+
+    @Test
+    public void testNestedConditionEvaluator() {
+        // football cars is 50 on the profile
+        assertTrue(eval(buildConditionOnNestedInterests("cars", 45, "greaterThan")));
+        assertTrue(eval(buildConditionOnNestedInterests("cars", 60, "lessThan")));
+        assertFalse(eval(buildConditionOnNestedInterests("cars", 60, "greaterThan")));
+        assertFalse(eval(buildConditionOnNestedInterests("cars", 15, "lessThan")));
+
+        // football interest is 15 on the profile
+        assertTrue(eval(buildConditionOnNestedInterests("football", 15, "equals")));
+        assertTrue(eval(buildConditionOnNestedInterests("football", 50, "notEquals")));
+        assertFalse(eval(buildConditionOnNestedInterests("football", 15, "notEquals")));
+        assertFalse(eval(buildConditionOnNestedInterests("football", 50, "equals")));
+    }
+
+    @Test
+    public void testNestedConditionEvaluator_emptyItem() {
+        // football cars is 50 on the profile
+        assertFalse(evalEmpty(buildConditionOnNestedInterests("cars", 45, "greaterThan")));
+        assertFalse(evalEmpty(buildConditionOnNestedInterests("cars", 60, "lessThan")));
+        assertFalse(evalEmpty(buildConditionOnNestedInterests("cars", 60, "greaterThan")));
+        assertFalse(evalEmpty(buildConditionOnNestedInterests("cars", 15, "lessThan")));
+
+        // football interest is 15 on the profile
+        assertFalse(evalEmpty(buildConditionOnNestedInterests("football", 15, "equals")));
+        assertFalse(evalEmpty(buildConditionOnNestedInterests("football", 50, "notEquals")));
+        assertFalse(evalEmpty(buildConditionOnNestedInterests("football", 15, "notEquals")));
+        assertFalse(evalEmpty(buildConditionOnNestedInterests("football", 50, "equals")));
+    }
+
+    protected Condition buildConditionOnNestedInterests(String interestName, Integer interestValue, String operator) {
+        Condition interestKeyCondition = new Condition(definitionsService.getConditionType("profilePropertyCondition"));
+        interestKeyCondition.setParameter("propertyName","properties.interests.key");
+        interestKeyCondition.setParameter("comparisonOperator","equals");
+        interestKeyCondition.setParameter("propertyValue", interestName);
+
+        Condition interestValueCondition = new Condition(definitionsService.getConditionType("profilePropertyCondition"));
+        interestValueCondition.setParameter("propertyName","properties.interests.value");
+        interestValueCondition.setParameter("comparisonOperator", operator);
+        interestValueCondition.setParameter("propertyValueInteger",interestValue);
+
+        Condition booleanCondition = new Condition(definitionsService.getConditionType("booleanCondition"));
+        booleanCondition.setParameter("operator", "and");
+        booleanCondition.setParameter("subConditions", Arrays.asList(interestKeyCondition, interestValueCondition));
+
+        Condition nestedCondition = new Condition(definitionsService.getConditionType("nestedCondition"));
+        nestedCondition.setParameter("path", "properties.interests");
+        nestedCondition.setParameter("subCondition", booleanCondition);
+        return nestedCondition;
+    }
 }
diff --git a/persistence-elasticsearch/core/pom.xml b/persistence-elasticsearch/core/pom.xml
index 4b7791ad5..acff5402d 100644
--- a/persistence-elasticsearch/core/pom.xml
+++ b/persistence-elasticsearch/core/pom.xml
@@ -112,7 +112,7 @@
         <dependency>
             <groupId>org.apache.lucene</groupId>
             <artifactId>lucene-test-framework</artifactId>
-            <version>8.2.0</version>
+            <version>${lucene.version}</version>
             <scope>test</scope>
             <exclusions>
                 <exclusion>
@@ -317,6 +317,7 @@
                         <Export-Package>
                             org.elasticsearch.*;version="${elasticsearch.version}",
                             org.elasticsearch.index.query.*;version="${elasticsearch.version}",
+                            org.apache.lucene.search.join.*;version="${lucene.version}",
                             org.apache.unomi.persistence.elasticsearch.conditions;version="${project.version}"
                         </Export-Package>
                         <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
diff --git a/persistence-elasticsearch/core/src/main/resources/META-INF/cxs/mappings/profile.json b/persistence-elasticsearch/core/src/main/resources/META-INF/cxs/mappings/profile.json
index a484d9103..81cc14d0f 100644
--- a/persistence-elasticsearch/core/src/main/resources/META-INF/cxs/mappings/profile.json
+++ b/persistence-elasticsearch/core/src/main/resources/META-INF/cxs/mappings/profile.json
@@ -34,6 +34,9 @@
         },
         "nbOfVisits": {
           "type": "long"
+        },
+        "interests": {
+          "type": "nested"
         }
       }
     },
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/NestedConditionESQueryBuilder.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/NestedConditionESQueryBuilder.java
new file mode 100644
index 000000000..e8c3701eb
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/NestedConditionESQueryBuilder.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.unomi.plugins.baseplugin.conditions;
+
+import org.apache.lucene.search.join.ScoreMode;
+import org.apache.unomi.api.conditions.Condition;
+import org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilder;
+import org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilderDispatcher;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+
+import java.util.Map;
+
+public class NestedConditionESQueryBuilder implements ConditionESQueryBuilder {
+    @Override
+    public QueryBuilder buildQuery(Condition condition, Map<String, Object> context, ConditionESQueryBuilderDispatcher dispatcher) {
+        String path = (String) condition.getParameter("path");
+        Condition subCondition = (Condition) condition.getParameter("subCondition");
+
+        if (subCondition == null || path == null) {
+            throw new IllegalArgumentException("Impossible to build Nested query, subCondition and path properties should be provided");
+        }
+
+        QueryBuilder nestedQueryBuilder = dispatcher.buildFilter(subCondition, context);
+        if (nestedQueryBuilder != null) {
+            return QueryBuilders.nestedQuery(path, nestedQueryBuilder, ScoreMode.Avg);
+        } else {
+            throw new IllegalArgumentException("Impossible to build Nested query due to subCondition filter null");
+        }
+    }
+}
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/NestedConditionEvaluator.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/NestedConditionEvaluator.java
new file mode 100644
index 000000000..1bbba6358
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/NestedConditionEvaluator.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.unomi.plugins.baseplugin.conditions;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.unomi.api.Item;
+import org.apache.unomi.api.Profile;
+import org.apache.unomi.api.Session;
+import org.apache.unomi.api.conditions.Condition;
+import org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluator;
+import org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluatorDispatcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+public class NestedConditionEvaluator implements ConditionEvaluator {
+
+    private static final Logger logger = LoggerFactory.getLogger(NestedConditionEvaluator.class.getName());
+
+    PropertyConditionEvaluator propertyConditionEvaluator;
+
+    public void setPropertyConditionEvaluator(PropertyConditionEvaluator propertyConditionEvaluator) {
+        this.propertyConditionEvaluator = propertyConditionEvaluator;
+    }
+
+    @Override
+    public boolean eval(Condition condition, Item item, Map<String, Object> context, ConditionEvaluatorDispatcher dispatcher) {
+        String path = (String) condition.getParameter("path");
+        Condition subCondition = (Condition) condition.getParameter("subCondition");
+
+        if (subCondition == null || path == null) {
+            throw new IllegalArgumentException("Impossible to build Nested evaluator, subCondition and path properties should be provided");
+        }
+
+
+        try {
+            // Get list of nested items to be evaluated
+            Object nestedItems = propertyConditionEvaluator.getPropertyValue(item, path);
+            if (nestedItems instanceof List) {
+
+                // Evaluated each nested items until one match the nested condition
+                for (Object nestedItem : (List<Object>) nestedItems) {
+                    if (nestedItem instanceof Map) {
+                        Map<String, Object> flattenedNestedItem = flattenNestedItem(path, (Map<String, Object>) nestedItem);
+                        Item finalNestedItem = createFinalNestedItemForEvaluation(item, path, flattenedNestedItem);
+                        if (finalNestedItem != null && dispatcher.eval(subCondition, finalNestedItem, context)) {
+                            // We found at least one nested item matching
+                            return true;
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.error("Failed to evaluated nested condition", e);
+            return false;
+        }
+        return false;
+    }
+
+    protected Map<String, Object> flattenNestedItem(String path, Map<String, Object> nestedItem) {
+        Map<String, Object> flattenNestedItem = new HashMap<>();
+
+        // Merge the nested Item in flat properties
+        if (StringUtils.isNotEmpty(path)) {
+            // substring to keep only the part after "properties".
+            // For example in case of "properties.interests", we only want to keep "interests"
+            String propertyPath = StringUtils.substringAfter(path, ".");
+            if (StringUtils.isNotEmpty(propertyPath)) {
+                String[] propertyKeys = propertyPath.split("\\.");
+                Iterator<String> propertyKeysIterator = Arrays.stream(propertyKeys).iterator();
+
+                Map<String, Object> currentPropertiesLevel = flattenNestedItem;
+                while (propertyKeysIterator.hasNext()) {
+                    String propertyKey = propertyKeysIterator.next();
+                    if (!propertyKeysIterator.hasNext()) {
+                        // last property, we set the nested Item
+                        currentPropertiesLevel.put(propertyKey, nestedItem);
+                    } else {
+                        // new level of prop
+                        Map<String, Object> subLevel = new HashMap<>();
+                        currentPropertiesLevel.put(propertyKey, subLevel);
+                        currentPropertiesLevel = subLevel;
+                    }
+                }
+            }
+        }
+
+        return flattenNestedItem;
+    }
+
+    protected Item createFinalNestedItemForEvaluation(Item parentItem, String path, Map<String, Object> flattenedNestedItem) {
+        // Build a basic Item with merged properties
+        if (parentItem instanceof Profile) {
+            Profile profile = new Profile(parentItem.getItemId());
+            if (path.startsWith("properties.")) {
+                profile.setProperties(flattenedNestedItem);
+            } else if (path.startsWith("systemProperties.")) {
+                profile.setSystemProperties(flattenedNestedItem);
+            }
+            return profile;
+        } else if (parentItem instanceof Session) {
+            Session session = new Session();
+            if (path.startsWith("properties.")) {
+                session.setProperties(flattenedNestedItem);
+            } else if (path.startsWith("systemProperties.")) {
+                session.setSystemProperties(flattenedNestedItem);
+            }
+            return session;
+        }
+
+        return null;
+    }
+}
diff --git a/plugins/baseplugin/src/main/resources/META-INF/cxs/conditions/nestedCondition.json b/plugins/baseplugin/src/main/resources/META-INF/cxs/conditions/nestedCondition.json
new file mode 100644
index 000000000..6fd44ac9d
--- /dev/null
+++ b/plugins/baseplugin/src/main/resources/META-INF/cxs/conditions/nestedCondition.json
@@ -0,0 +1,29 @@
+{
+  "metadata": {
+    "id": "nestedCondition",
+    "name": "nestedCondition",
+    "description": "",
+    "systemTags": [
+      "profileTags",
+      "logical",
+      "condition",
+      "profileCondition",
+      "sessionCondition"
+    ],
+    "readOnly": true
+  },
+  "conditionEvaluator": "nestedConditionEvaluator",
+  "queryBuilder": "nestedConditionESQueryBuilder",
+  "parameters": [
+    {
+      "id": "path",
+      "type": "String",
+      "multivalued": false
+    },
+    {
+      "id": "subCondition",
+      "type": "Condition",
+      "multivalued": false
+    }
+  ]
+}
\ No newline at end of file
diff --git a/plugins/baseplugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/plugins/baseplugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index b80f250e0..15f6766b6 100644
--- a/plugins/baseplugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/plugins/baseplugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -131,6 +131,14 @@
         </bean>
     </service>
 
+    <service
+            interface="org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilder">
+        <service-properties>
+            <entry key="queryBuilderId" value="nestedConditionESQueryBuilder"/>
+        </service-properties>
+        <bean class="org.apache.unomi.plugins.baseplugin.conditions.NestedConditionESQueryBuilder"/>
+    </service>
+
 
     <!-- Condition evaluators -->
     <service interface="org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluator">
@@ -154,13 +162,13 @@
         <bean class="org.apache.unomi.plugins.baseplugin.conditions.NotConditionEvaluator"/>
     </service>
 
-    <service interface="org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluator">
+    <bean id="propertyConditionEvaluator" class="org.apache.unomi.plugins.baseplugin.conditions.PropertyConditionEvaluator">
+        <property name="usePropertyConditionOptimizations" value="${base.usePropertyConditionOptimizations}"/>
+    </bean>
+    <service  interface="org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluator" ref="propertyConditionEvaluator">
         <service-properties>
             <entry key="conditionEvaluatorId" value="propertyConditionEvaluator"/>
         </service-properties>
-        <bean class="org.apache.unomi.plugins.baseplugin.conditions.PropertyConditionEvaluator">
-            <property name="usePropertyConditionOptimizations" value="${base.usePropertyConditionOptimizations}"/>
-        </bean>
     </service>
 
     <service interface="org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluator">
@@ -198,6 +206,15 @@
         </bean>
     </service>
 
+    <service interface="org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluator">
+        <service-properties>
+            <entry key="conditionEvaluatorId" value="nestedConditionEvaluator"/>
+        </service-properties>
+        <bean class="org.apache.unomi.plugins.baseplugin.conditions.NestedConditionEvaluator">
+            <property name="propertyConditionEvaluator" ref="propertyConditionEvaluator"/>
+        </bean>
+    </service>
+
 
     <!-- Action executors -->
 
diff --git a/plugins/baseplugin/src/test/java/org/apache/unomi/plugins/baseplugin/conditions/NestedConditionEvaluatorTest.java b/plugins/baseplugin/src/test/java/org/apache/unomi/plugins/baseplugin/conditions/NestedConditionEvaluatorTest.java
new file mode 100644
index 000000000..434aa219e
--- /dev/null
+++ b/plugins/baseplugin/src/test/java/org/apache/unomi/plugins/baseplugin/conditions/NestedConditionEvaluatorTest.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.plugins.baseplugin.conditions;
+
+import org.apache.unomi.api.Event;
+import org.apache.unomi.api.Profile;
+import org.apache.unomi.api.Session;
+import org.apache.unomi.api.segments.Segment;
+import org.junit.Test;
+
+import java.util.*;
+
+import static junit.framework.TestCase.*;
+
+public class NestedConditionEvaluatorTest {
+    private final NestedConditionEvaluator nestedConditionEvaluator = new NestedConditionEvaluator();
+
+    @Test
+    public void testFlattenedNestedItem_singleLevel() {
+        Map<String, Object> result = nestedConditionEvaluator.flattenNestedItem("properties.interests", buildNestedInterest("football", 15));
+        Map<String, Object> mergeResultProperties = (Map<String, Object>) result.get("interests");
+
+        assertEquals("The interest should have been flattened in the profile", "football", mergeResultProperties.get("key"));
+        assertEquals("The interest should have been flattened in the profile", 15, mergeResultProperties.get("value"));
+    }
+
+    @Test
+    public void testFlattenedNestedItem_multipleLevel() {
+        Map<String, Object> result = nestedConditionEvaluator.flattenNestedItem("properties.subLevel.subLevel2.interests", buildNestedInterest("football", 15));
+        Map<String, Object> subLevelResult = (Map<String, Object>) result.get("subLevel");
+        Map<String, Object> subLevel2Result = (Map<String, Object>) subLevelResult.get("subLevel2");
+        Map<String, Object> interestsResult = (Map<String, Object>) subLevel2Result.get("interests");
+
+        assertEquals("The interest should have been flattened in the profile", "football", interestsResult.get("key"));
+        assertEquals("The interest should have been flattened in the profile", 15, interestsResult.get("value"));
+    }
+
+    @Test
+    public void testFlattenedNestedItem_invalidPaths() {
+        assertTrue(nestedConditionEvaluator.flattenNestedItem("properties.", buildNestedInterest("football", 15)).isEmpty());
+        assertTrue(nestedConditionEvaluator.flattenNestedItem("", buildNestedInterest("football", 15)).isEmpty());
+        assertTrue(nestedConditionEvaluator.flattenNestedItem(null, buildNestedInterest("football", 15)).isEmpty());
+    }
+
+    @Test
+    public void testCreateFinalNestedItem_Profile() {
+        Map<String, Object> testMap = new HashMap<>();
+        testMap.put("foo", "bar");
+        
+        Profile profile = (Profile) nestedConditionEvaluator.createFinalNestedItemForEvaluation(new Profile(), "properties.test", testMap);
+        assertEquals("bar", profile.getProperties().get("foo"));
+        assertTrue(profile.getSystemProperties().isEmpty());
+
+        profile = (Profile) nestedConditionEvaluator.createFinalNestedItemForEvaluation(new Profile(), "systemProperties.test", testMap);
+        assertEquals("bar", profile.getSystemProperties().get("foo"));
+        assertTrue(profile.getProperties().isEmpty());
+
+        profile = (Profile) nestedConditionEvaluator.createFinalNestedItemForEvaluation(new Profile(), "invalidPath", testMap);
+        assertTrue(profile.getSystemProperties().isEmpty());
+        assertTrue(profile.getProperties().isEmpty());
+    }
+
+    @Test
+    public void testCreateFinalNestedItem_Session() {
+        Map<String, Object> testMap = new HashMap<>();
+        testMap.put("foo", "bar");
+
+        Session session = (Session) nestedConditionEvaluator.createFinalNestedItemForEvaluation(new Session(), "properties.test", testMap);
+        assertEquals("bar", session.getProperties().get("foo"));
+        assertTrue(session.getSystemProperties().isEmpty());
+
+        session = (Session) nestedConditionEvaluator.createFinalNestedItemForEvaluation(new Session(), "systemProperties.test", testMap);
+        assertEquals("bar", session.getSystemProperties().get("foo"));
+        assertTrue(session.getProperties().isEmpty());
+
+        session = (Session) nestedConditionEvaluator.createFinalNestedItemForEvaluation(new Session(), "invalidPath", testMap);
+        assertTrue(session.getSystemProperties().isEmpty());
+        assertTrue(session.getProperties().isEmpty());
+    }
+
+    @Test
+    public void testCreateFinalNestedItem_unsupportedType() {
+        Map<String, Object> testMap = new HashMap<>();
+        testMap.put("foo", "bar");
+
+        Event segment = (Event) nestedConditionEvaluator.createFinalNestedItemForEvaluation(new Event(), "properties.test", testMap);
+        assertNull(segment);
+    }
+
+    private Map<String, Object> buildNestedInterest(String key, Object value) {
+        Map<String, Object> nestedInterest = new HashMap<>();
+        nestedInterest.put("key", key);
+        nestedInterest.put("value", value);
+        return nestedInterest;
+    }
+}
diff --git a/pom.xml b/pom.xml
index ee5abe5f9..f9d867ca9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -73,6 +73,7 @@
         <version.pax.exam>4.13.1</version.pax.exam>
         <elasticsearch.version>7.4.2</elasticsearch.version>
         <elasticsearch.test.version>7.11.0</elasticsearch.test.version>
+        <lucene.version>8.2.0</lucene.version>
         <groovy.version>3.0.3</groovy.version>
         <networknt.version>1.0.49</networknt.version>
         <bean.validation.version>1.1.0.Final</bean.validation.version>


[unomi] 02/02: UNOMI-585: introduce new nestedCondition and set profile.properties.interests as nested

Posted by jk...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 2646c83124832bb868bb173cc3eaffbc57a5f571
Author: Kevan <ke...@jahia.com>
AuthorDate: Fri Jun 17 19:46:24 2022 +0200

    UNOMI-585: introduce new nestedCondition and set profile.properties.interests as nested
---
 .../plugins/baseplugin/conditions/NestedConditionEvaluatorTest.java      | 1 -
 1 file changed, 1 deletion(-)

diff --git a/plugins/baseplugin/src/test/java/org/apache/unomi/plugins/baseplugin/conditions/NestedConditionEvaluatorTest.java b/plugins/baseplugin/src/test/java/org/apache/unomi/plugins/baseplugin/conditions/NestedConditionEvaluatorTest.java
index 434aa219e..227a46071 100644
--- a/plugins/baseplugin/src/test/java/org/apache/unomi/plugins/baseplugin/conditions/NestedConditionEvaluatorTest.java
+++ b/plugins/baseplugin/src/test/java/org/apache/unomi/plugins/baseplugin/conditions/NestedConditionEvaluatorTest.java
@@ -19,7 +19,6 @@ package org.apache.unomi.plugins.baseplugin.conditions;
 import org.apache.unomi.api.Event;
 import org.apache.unomi.api.Profile;
 import org.apache.unomi.api.Session;
-import org.apache.unomi.api.segments.Segment;
 import org.junit.Test;
 
 import java.util.*;