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

jsinovassinnaik 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 a1c4f774b UNOMI-817: set pastEvents as nested and clean existing 
mapping (#659)
a1c4f774b is described below

commit a1c4f774bc0be136c3c13921f4a630eb5afd2e5c
Author: jsinovassin <[email protected]>
AuthorDate: Fri May 31 12:43:51 2024 +0200

    UNOMI-817: set pastEvents as nested and clean existing mapping (#659)
    
    * UNOMI-817: set pastEvents as flattened and clean existing mapping
    
    * UNOMI-817: transform pastEvents to nested property
---
 .../unomi/api/services/DefinitionsService.java     |  11 +++-
 .../apache/unomi/api/utils}/ConditionBuilder.java  |  36 +++++++----
 .../apache/unomi/itests/ConditionEvaluatorIT.java  |   5 +-
 .../org/apache/unomi/itests/RuleServiceIT.java     |   3 +-
 .../java/org/apache/unomi/itests/SegmentIT.java    |  10 +--
 .../unomi/itests/migration/Migrate16xTo220IT.java  |  14 +++++
 .../resources/migration/snapshots_repository.zip   | Bin 3908941 -> 7807889 
bytes
 .../ElasticSearchPersistenceServiceImpl.java       |   2 +-
 .../resources/META-INF/cxs/mappings/profile.json   |   7 +++
 .../resources/OSGI-INF/blueprint/blueprint.xml     |   7 +--
 .../actions/SetEventOccurenceCountAction.java      |  33 ++++++++--
 .../PastEventConditionESQueryBuilder.java          |  70 ++++++++++-----------
 .../conditions/PastEventConditionEvaluator.java    |  12 +++-
 .../painless/updatePastEventOccurences.painless    |  47 ++++++++++++++
 .../impl/definitions/DefinitionsServiceImpl.java   |   9 +++
 .../services/impl/profiles/ProfileServiceImpl.java |   9 ++-
 .../services/impl/segments/SegmentServiceImpl.java |  60 +++++++++---------
 ...te-2.5.0-00-cleanPastEventProfileSession.groovy |  48 ++++++++++++++
 .../2.5.0/remove_pastEvents_session.painless       |  22 +++++++
 .../2.5.0/update_pastEvents_profile.painless       |  27 ++++++++
 20 files changed, 325 insertions(+), 107 deletions(-)

diff --git 
a/api/src/main/java/org/apache/unomi/api/services/DefinitionsService.java 
b/api/src/main/java/org/apache/unomi/api/services/DefinitionsService.java
index 816f8831a..b4cf75a68 100644
--- a/api/src/main/java/org/apache/unomi/api/services/DefinitionsService.java
+++ b/api/src/main/java/org/apache/unomi/api/services/DefinitionsService.java
@@ -23,6 +23,7 @@ import org.apache.unomi.api.ValueType;
 import org.apache.unomi.api.actions.ActionType;
 import org.apache.unomi.api.conditions.Condition;
 import org.apache.unomi.api.conditions.ConditionType;
+import org.apache.unomi.api.utils.ConditionBuilder;
 
 import java.util.Collection;
 import java.util.List;
@@ -210,4 +211,12 @@ public interface DefinitionsService {
      * so it is recommended to use this in specific cases such as for example 
in integration tests.
      */
     void refresh();
-}
\ No newline at end of file
+
+
+    /**
+     * Retrieves a new instance of a ConditionBuilder to help to build 
conditions.
+     *
+     * @return a new instance of a ConditionBuilder
+     */
+    ConditionBuilder getConditionBuilder();
+}
diff --git a/itests/src/test/java/org/apache/unomi/itests/ConditionBuilder.java 
b/api/src/main/java/org/apache/unomi/api/utils/ConditionBuilder.java
similarity index 92%
rename from itests/src/test/java/org/apache/unomi/itests/ConditionBuilder.java
rename to api/src/main/java/org/apache/unomi/api/utils/ConditionBuilder.java
index 69a210fe1..aceb1ffe5 100644
--- a/itests/src/test/java/org/apache/unomi/itests/ConditionBuilder.java
+++ b/api/src/main/java/org/apache/unomi/api/utils/ConditionBuilder.java
@@ -12,34 +12,33 @@
  * 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
+ * limitations under the License.
  */
-
-package org.apache.unomi.itests;
+package org.apache.unomi.api.utils;
 
 import org.apache.unomi.api.conditions.Condition;
 import org.apache.unomi.api.services.DefinitionsService;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
+import java.util.*;
 
 /**
- * Utility class for building conditions
- *
- * @author Sergiy Shyrkov
+ * Utility class for creating various types of {@link Condition} objects.
+ * This class provides methods to easily construct conditions used for 
querying data based on specific criteria.
  */
 public class ConditionBuilder {
 
     private DefinitionsService definitionsService;
 
     /**
-     * Initializes an instance of this class.
+     * Constructs a new Builder with a specified DefinitionsService.
      *
-     * @param definitionsService an instance of the {@link DefinitionsService}
+     * @param definitionsService the DefinitionsService to use for obtaining 
condition types.
      */
     public ConditionBuilder(DefinitionsService definitionsService) {
-        super();
+        this.definitionsService = definitionsService;
+    }
+
+    public void setDefinitionsService(DefinitionsService definitionsService) {
         this.definitionsService = definitionsService;
     }
 
@@ -55,6 +54,10 @@ public class ConditionBuilder {
         return new CompoundCondition(condition1, condition2, "or");
     }
 
+    public NestedCondition nested(ConditionItem subCondition, String path) {
+        return new NestedCondition(subCondition, path);
+    }
+
     public PropertyCondition profileProperty(String propertyName) {
         return new PropertyCondition("profilePropertyCondition", propertyName, 
definitionsService);
     }
@@ -315,6 +318,14 @@ public class ConditionBuilder {
         }
     }
 
+    public class NestedCondition extends ConditionItem {
+        NestedCondition(ConditionItem subCondition, String path) {
+            super("nestedCondition", subCondition.definitionsService);
+            parameter("path", path);
+            parameter("subCondition", subCondition.build());
+        }
+    }
+
     public class ConditionItem {
 
         protected Condition condition;
@@ -359,4 +370,5 @@ public class ConditionBuilder {
         }
 
     }
+
 }
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 d74672ca3..e9dd76ca0 100644
--- a/itests/src/test/java/org/apache/unomi/itests/ConditionEvaluatorIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/ConditionEvaluatorIT.java
@@ -21,8 +21,7 @@ import org.apache.commons.lang3.time.DateUtils;
 import org.apache.unomi.api.Item;
 import org.apache.unomi.api.Profile;
 import org.apache.unomi.api.conditions.Condition;
-import org.apache.unomi.api.services.DefinitionsService;
-import org.apache.unomi.persistence.spi.PersistenceService;
+import org.apache.unomi.api.utils.ConditionBuilder;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -62,7 +61,7 @@ public class ConditionEvaluatorIT extends BaseIT {
     public void setUp() {
         assertNotNull("Definition service should be available", 
definitionsService);
         assertNotNull("Persistence service should be available", 
persistenceService);
-        builder = new ConditionBuilder(definitionsService);
+        builder = definitionsService.getConditionBuilder();
 
         lastVisit = new GregorianCalendar(2015, 
Calendar.FEBRUARY,1,20,30,0).getTime();
 
diff --git a/itests/src/test/java/org/apache/unomi/itests/RuleServiceIT.java 
b/itests/src/test/java/org/apache/unomi/itests/RuleServiceIT.java
index e605c039b..764980fe6 100644
--- a/itests/src/test/java/org/apache/unomi/itests/RuleServiceIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/RuleServiceIT.java
@@ -22,6 +22,7 @@ import org.apache.unomi.api.conditions.ConditionType;
 import org.apache.unomi.api.rules.Rule;
 import org.apache.unomi.api.services.EventService;
 import org.apache.unomi.api.services.RulesService;
+import org.apache.unomi.api.utils.ConditionBuilder;
 import org.apache.unomi.persistence.spi.CustomObjectMapper;
 import org.junit.Assert;
 import org.junit.Before;
@@ -105,7 +106,7 @@ public class RuleServiceIT extends BaseIT {
 
     @Test
     public void testRuleEventTypeOptimization() throws InterruptedException {
-        ConditionBuilder builder = new ConditionBuilder(definitionsService);
+        ConditionBuilder builder = definitionsService.getConditionBuilder();
         Rule simpleEventTypeRule = new Rule(new Metadata(TEST_SCOPE, 
"simple-event-type-rule", "Simple event type rule", "A rule with a simple 
condition to match an event type"));
         
simpleEventTypeRule.setCondition(builder.condition("eventTypeCondition").parameter("eventTypeId",
 "view").build());
         createAndWaitForRule(simpleEventTypeRule);
diff --git a/itests/src/test/java/org/apache/unomi/itests/SegmentIT.java 
b/itests/src/test/java/org/apache/unomi/itests/SegmentIT.java
index 3b3aa9314..59375b8c9 100644
--- a/itests/src/test/java/org/apache/unomi/itests/SegmentIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/SegmentIT.java
@@ -547,9 +547,8 @@ public class SegmentIT extends BaseIT {
 
         // insure the profile is engaged;
         try {
-            Assert.assertTrue("Profile should have 2 events in the scoring",
-                    (Long) ((Map) 
testEvent.getProfile().getSystemProperties().get("pastEvents"))
-                            
.get(pastEventCondition.getParameterValues().get("generatedPropertyKey")) == 2);
+            Map<String, Object> pastEvent = ((List<Map<String, 
Object>>)testEvent.getProfile().getSystemProperties().get("pastEvents")).stream().filter(profilePastEvent
 -> 
profilePastEvent.get("key").equals(pastEventCondition.getParameterValues().get("generatedPropertyKey"))).findFirst().get();
+            Assert.assertEquals("Profile should have 2 events in the scoring", 
2, (long) pastEvent.get("count"));
             Assert.assertTrue("Profile is engaged", 
testEvent.getProfile().getScores().containsKey("past-event-scoring-test")
                     && 
testEvent.getProfile().getScores().get("past-event-scoring-test") == 50);
         } catch (Exception e) {
@@ -562,8 +561,9 @@ public class SegmentIT extends BaseIT {
         // insure the profile is still engaged after recalculate;
         keepTrying("Profile should have 2 events in the scoring", () -> 
profileService.load("test_profile_id"), updatedProfile -> {
             try {
-                boolean eventCounted = (Integer) ((Map) 
updatedProfile.getSystemProperties().get("pastEvents"))
-                        
.get(pastEventCondition.getParameterValues().get("generatedPropertyKey")) == 2;
+                Map<String, Object> pastEvent = ((List<Map<String, 
Object>>)updatedProfile.getSystemProperties().get("pastEvents")).stream().filter(profilePastEvent
 -> 
profilePastEvent.get("key").equals(pastEventCondition.getParameterValues().get("generatedPropertyKey"))).findFirst().get();
+
+                boolean eventCounted = (Integer) pastEvent.get("count") == 2;
                 boolean profileEngaged = 
updatedProfile.getScores().containsKey("past-event-scoring-test")
                         && 
updatedProfile.getScores().get("past-event-scoring-test") == 50;
                 return eventCounted && profileEngaged;
diff --git 
a/itests/src/test/java/org/apache/unomi/itests/migration/Migrate16xTo220IT.java 
b/itests/src/test/java/org/apache/unomi/itests/migration/Migrate16xTo220IT.java
index cddb44f49..725f0fa4c 100644
--- 
a/itests/src/test/java/org/apache/unomi/itests/migration/Migrate16xTo220IT.java
+++ 
b/itests/src/test/java/org/apache/unomi/itests/migration/Migrate16xTo220IT.java
@@ -99,6 +99,7 @@ public class Migrate16xTo220IT extends BaseIT {
         checkEventSessionRollover2_2_0();
         checkIndexReductions2_2_0();
         checkPagePathForEventView();
+        checkPastEvents();
     }
 
     /**
@@ -342,4 +343,17 @@ public class Migrate16xTo220IT extends BaseIT {
         Assert.assertEquals(2, 
persistenceService.query("target.properties.pageInfo.pagePath", 
"/path/to/migrate/to/pageInfo", null, Event.class).size());
         Assert.assertEquals(0, persistenceService.query("properties.path", 
"/path/to/migrate/to/pageInfo", null, Event.class).size());
     }
+
+
+    /**
+     * Data set contains a profile (id: 164adad8-6885-45b6-8e9d-512bf4a7d10d) 
with a system property pastEvents that contains 5 events with key 
eventTriggeredabcdefgh
+     * This test ensures that the pastEvents have been migrated to the new 
data structure
+     */
+    private void checkPastEvents() {
+        Profile profile = 
persistenceService.load("164adad8-6885-45b6-8e9d-512bf4a7d10d", Profile.class);
+        List<Map<String, Object>> pastEvents = ((List<Map<String, 
Object>>)profile.getSystemProperties().get("pastEvents"));
+        Assert.assertEquals(1, pastEvents.size());
+        Assert.assertEquals("eventTriggeredabcdefgh", 
pastEvents.get(0).get("key"));
+        Assert.assertEquals(5, (int) pastEvents.get(0).get("count"));
+    }
 }
diff --git a/itests/src/test/resources/migration/snapshots_repository.zip 
b/itests/src/test/resources/migration/snapshots_repository.zip
index 705a6241f..675e710cc 100644
Binary files a/itests/src/test/resources/migration/snapshots_repository.zip and 
b/itests/src/test/resources/migration/snapshots_repository.zip differ
diff --git 
a/persistence-elasticsearch/core/src/main/java/org/apache/unomi/persistence/elasticsearch/ElasticSearchPersistenceServiceImpl.java
 
b/persistence-elasticsearch/core/src/main/java/org/apache/unomi/persistence/elasticsearch/ElasticSearchPersistenceServiceImpl.java
index 0da7bc14b..d2a11ed52 100644
--- 
a/persistence-elasticsearch/core/src/main/java/org/apache/unomi/persistence/elasticsearch/ElasticSearchPersistenceServiceImpl.java
+++ 
b/persistence-elasticsearch/core/src/main/java/org/apache/unomi/persistence/elasticsearch/ElasticSearchPersistenceServiceImpl.java
@@ -1063,7 +1063,7 @@ public class ElasticSearchPersistenceServiceImpl 
implements PersistenceService,
 
     @Override
     public List<String> update(final Map<Item, Map> items, final Date 
dateHint, final Class clazz) {
-        if (items.size() == 0)
+        if (items.isEmpty())
             return new ArrayList<>();
 
         List<String> result = new 
InClassLoaderExecute<List<String>>(metricsService, this.getClass().getName() + 
".updateItems", this.bundleContext, this.fatalIllegalStateErrors, 
throwExceptions) {
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 81cc14d0f..6e650a178 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
@@ -40,6 +40,13 @@
         }
       }
     },
+    "systemProperties": {
+      "properties": {
+        "pastEvents": {
+          "type": "nested"
+        }
+      }
+    },
     "consents": {
       "properties": {
         "statusDate": {
diff --git 
a/persistence-elasticsearch/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
 
b/persistence-elasticsearch/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index 32efdd022..d14235171 100644
--- 
a/persistence-elasticsearch/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ 
b/persistence-elasticsearch/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -20,12 +20,7 @@
            
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0";
            xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0";
            xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 
http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
-
-
-
-
-
-  http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0 
http://aries.apache.org/schemas/blueprint-cm/blueprint-cm-1.1.0.xsd";>
+           http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0 
http://aries.apache.org/schemas/blueprint-cm/blueprint-cm-1.1.0.xsd";>
 
     <cm:property-placeholder 
persistent-id="org.apache.unomi.persistence.elasticsearch"
                              update-strategy="reload" 
placeholder-prefix="${es.">
diff --git 
a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/SetEventOccurenceCountAction.java
 
b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/SetEventOccurenceCountAction.java
index aa269762e..cb5e78f59 100644
--- 
a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/SetEventOccurenceCountAction.java
+++ 
b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/SetEventOccurenceCountAction.java
@@ -29,10 +29,8 @@ import org.apache.unomi.persistence.spi.PropertyHelper;
 import java.time.Duration;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.LinkedHashMap;
-import java.util.Map;
+import java.util.*;
+import java.util.stream.Collectors;
 
 import javax.xml.bind.DatatypeConverter;
 
@@ -123,14 +121,37 @@ public class SetEventOccurenceCountAction implements 
ActionExecutor {
             count++;
         }
 
-        String generatedPropertyKey = (String) 
pastEventCondition.getParameter("generatedPropertyKey");
-        if (PropertyHelper.setProperty(event.getProfile(), 
"systemProperties.pastEvents." + generatedPropertyKey, count, "alwaysSet")) {
+        if (updatePastEvents(event, (String) 
pastEventCondition.getParameter("generatedPropertyKey"), count)) {
             return EventService.PROFILE_UPDATED;
         }
 
         return EventService.NO_CHANGE;
     }
 
+    private boolean updatePastEvents(Event event, String generatedPropertyKey, 
long count) {
+        List<Map<String, Object>> existingPastEvents = (List<Map<String, 
Object>>) event.getProfile().getSystemProperties().get("pastEvents");
+        if (existingPastEvents == null) {
+            existingPastEvents = new ArrayList<>();
+            event.getProfile().getSystemProperties().put("pastEvents", 
existingPastEvents);
+        }
+
+        for (Map<String, Object> pastEvent : existingPastEvents) {
+            if (generatedPropertyKey.equals(pastEvent.get("key"))) {
+                if (pastEvent.containsKey("count") && 
pastEvent.get("count").equals(count)) {
+                    return false;
+                }
+                pastEvent.put("count", count);
+                return true;
+            }
+        }
+
+        Map<String, Object> newPastEvent = new HashMap<>();
+        newPastEvent.put("key", generatedPropertyKey);
+        newPastEvent.put("count", count);
+        existingPastEvents.add(newPastEvent);
+        return true;
+    }
+
     private boolean inTimeRange(LocalDateTime eventTime, Integer numberOfDays, 
LocalDateTime fromDate, LocalDateTime toDate) {
         boolean inTimeRange = true;
 
diff --git 
a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PastEventConditionESQueryBuilder.java
 
b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PastEventConditionESQueryBuilder.java
index 4491eb678..6c40f9f87 100644
--- 
a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PastEventConditionESQueryBuilder.java
+++ 
b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PastEventConditionESQueryBuilder.java
@@ -20,9 +20,9 @@ package org.apache.unomi.plugins.baseplugin.conditions;
 import org.apache.unomi.api.Event;
 import org.apache.unomi.api.Profile;
 import org.apache.unomi.api.conditions.Condition;
-import org.apache.unomi.api.conditions.ConditionType;
 import org.apache.unomi.api.services.DefinitionsService;
 import org.apache.unomi.api.services.SegmentService;
+import org.apache.unomi.api.utils.ConditionBuilder;
 import 
org.apache.unomi.persistence.elasticsearch.conditions.ConditionContextHelper;
 import 
org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilder;
 import 
org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilderDispatcher;
@@ -88,7 +88,8 @@ public class PastEventConditionESQueryBuilder implements 
ConditionESQueryBuilder
             // TODO see for deprecation, this should not happen anymore each 
past event condition should have a generatedPropertyKey
             Condition eventCondition = getEventCondition(condition, context, 
null, definitionsService, scriptExecutor);
             Set<String> ids = getProfileIdsMatchingEventCount(eventCondition, 
minimumEventCount, maximumEventCount);
-            return dispatcher.buildFilter(getProfileIdsCondition(ids, 
eventsOccurred), context);
+            ConditionBuilder conditionBuilder = 
definitionsService.getConditionBuilder();
+            return 
dispatcher.buildFilter(conditionBuilder.condition("idsCondition").parameter("ids",
 ids).parameter("match", eventsOccurred).build(), context);
         }
     }
 
@@ -111,7 +112,8 @@ public class PastEventConditionESQueryBuilder implements 
ConditionESQueryBuilder
             }
 
             Set<String> profileIds = 
getProfileIdsMatchingEventCount(eventCondition, minimumEventCount, 
maximumEventCount);
-            return eventsOccurred ? profileIds.size() : 
persistenceService.queryCount(getProfileIdsCondition(profileIds, false), 
Profile.ITEM_TYPE);
+            ConditionBuilder conditionBuilder = 
definitionsService.getConditionBuilder();
+            return eventsOccurred ? profileIds.size() : 
persistenceService.queryCount(conditionBuilder.condition("idsCondition").parameter("ids",
 profileIds).parameter("match", false).build(), Profile.ITEM_TYPE);
         }
     }
 
@@ -122,44 +124,38 @@ public class PastEventConditionESQueryBuilder implements 
ConditionESQueryBuilder
         return operator == null || operator.equals("eventsOccurred");
     }
 
-    private Condition getProfileIdsCondition(Set<String> ids, boolean 
shouldMatch) {
-        Condition idsCondition = new Condition();
-        
idsCondition.setConditionType(definitionsService.getConditionType("idsCondition"));
-        idsCondition.setParameter("ids", ids);
-        idsCondition.setParameter("match", shouldMatch);
-        return idsCondition;
-    }
-
     private Condition getProfileConditionForCounter(String 
generatedPropertyKey, Integer minimumEventCount, Integer maximumEventCount, 
boolean eventsOccurred) {
-        String generatedPropertyName = "systemProperties.pastEvents." + 
generatedPropertyKey;
-        ConditionType profilePropertyConditionType = 
definitionsService.getConditionType("profilePropertyCondition");
         if (eventsOccurred) {
-            Condition counterIsBetweenBoundaries = new Condition();
-            
counterIsBetweenBoundaries.setConditionType(profilePropertyConditionType);
-            counterIsBetweenBoundaries.setParameter("propertyName", 
generatedPropertyName);
-            counterIsBetweenBoundaries.setParameter("comparisonOperator", 
"between");
-            counterIsBetweenBoundaries.setParameter("propertyValuesInteger", 
Arrays.asList(minimumEventCount, maximumEventCount));
-            return counterIsBetweenBoundaries;
+            return createEventOccurredCondition(generatedPropertyKey, 
minimumEventCount, maximumEventCount);
         } else {
-            Condition counterMissing = new Condition();
-            counterMissing.setConditionType(profilePropertyConditionType);
-            counterMissing.setParameter("propertyName", generatedPropertyName);
-            counterMissing.setParameter("comparisonOperator", "missing");
-
-            Condition counterZero = new Condition();
-            counterZero.setConditionType(profilePropertyConditionType);
-            counterZero.setParameter("propertyName", generatedPropertyName);
-            counterZero.setParameter("comparisonOperator", "equals");
-            counterZero.setParameter("propertyValueInteger", 0);
-
-            Condition counterCondition = new Condition();
-            
counterCondition.setConditionType(definitionsService.getConditionType("booleanCondition"));
-            counterCondition.setParameter("operator", "or");
-            counterCondition.setParameter("subConditions", 
Arrays.asList(counterMissing, counterZero));
-            return counterCondition;
+            return createEventNotOccurredCondition(generatedPropertyKey);
         }
     }
 
+    private Condition createEventOccurredCondition(String 
generatedPropertyKey, Integer minimumEventCount, Integer maximumEventCount) {
+        ConditionBuilder conditionBuilder = 
definitionsService.getConditionBuilder();
+        ConditionBuilder.ConditionItem subConditionCount = 
conditionBuilder.profileProperty("systemProperties.pastEvents.count").between(minimumEventCount,
 maximumEventCount);
+        ConditionBuilder.ConditionItem subConditionKey = 
conditionBuilder.profileProperty("systemProperties.pastEvents.key").equalTo(generatedPropertyKey);
+        ConditionBuilder.ConditionItem booleanCondition = 
conditionBuilder.and(subConditionCount, subConditionKey);
+        return conditionBuilder.nested(booleanCondition, 
"systemProperties.pastEvents").build();
+    }
+
+    private Condition createEventNotOccurredCondition(String 
generatedPropertyKey) {
+        ConditionBuilder.ConditionItem counterMissing = 
createPastEventMustNotExistCondition(generatedPropertyKey);
+        ConditionBuilder conditionBuilder = 
definitionsService.getConditionBuilder();
+        ConditionBuilder.ConditionItem counterZero = 
conditionBuilder.profileProperty("systemProperties.pastEvents.count").equalTo(0);
+        ConditionBuilder.ConditionItem keyEquals = 
conditionBuilder.profileProperty("systemProperties.pastEvents.key").equalTo(generatedPropertyKey);
+        ConditionBuilder.ConditionItem keyExistsAndCounterZero = 
conditionBuilder.and(counterZero, keyEquals);
+        ConditionBuilder.ConditionItem nestedKeyExistsAndCounterZero = 
conditionBuilder.nested(keyExistsAndCounterZero, "systemProperties.pastEvents");
+        return conditionBuilder.or(counterMissing, 
nestedKeyExistsAndCounterZero).build();
+    }
+
+    private ConditionBuilder.ConditionItem 
createPastEventMustNotExistCondition(String generatedPropertyKey) {
+        ConditionBuilder conditionBuilder = 
definitionsService.getConditionBuilder();
+        ConditionBuilder.ConditionItem keyEquals = 
conditionBuilder.profileProperty("systemProperties.pastEvents.key").equalTo(generatedPropertyKey);
+        return conditionBuilder.not(keyEquals);
+    }
+
     private Set<String> getProfileIdsMatchingEventCount(Condition 
eventCondition, int minimumEventCount, int maximumEventCount) {
         boolean noBoundaries = minimumEventCount == 1 && maximumEventCount == 
Integer.MAX_VALUE;
         if (pastEventsDisablePartitions) {
@@ -254,4 +250,6 @@ public class PastEventConditionESQueryBuilder implements 
ConditionESQueryBuilder
         endDateCondition.setParameter(propertyValueParameter, propertyValue);
         return endDateCondition;
     }
-}
\ No newline at end of file
+
+
+}
diff --git 
a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PastEventConditionEvaluator.java
 
b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PastEventConditionEvaluator.java
index 721d9a78a..f14f768f6 100644
--- 
a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PastEventConditionEvaluator.java
+++ 
b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PastEventConditionEvaluator.java
@@ -27,6 +27,8 @@ import 
org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluatorD
 import org.apache.unomi.persistence.spi.PersistenceService;
 import org.apache.unomi.scripting.ScriptExecutor;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 
 public class PastEventConditionEvaluator implements ConditionEvaluator {
@@ -55,10 +57,14 @@ public class PastEventConditionEvaluator implements 
ConditionEvaluator {
         if (parameters.containsKey("generatedPropertyKey")) {
             String key = (String) parameters.get("generatedPropertyKey");
             Profile profile = (Profile) item;
-            Map<String,Object> pastEvents = (Map<String, Object>) 
profile.getSystemProperties().get("pastEvents");
+            List<Map<String, Object>> pastEvents =  (ArrayList<Map<String, 
Object>>) profile.getSystemProperties().get("pastEvents");
             if (pastEvents != null) {
-                Number l = (Number) pastEvents.get(key);
-                count = l != null ? l.longValue() : 0L;
+                Number l = (Number) pastEvents
+                        .stream()
+                        .filter(pastEvent -> pastEvent.get("key").equals(key))
+                        .findFirst()
+                        .map(pastEvent -> pastEvent.get("count")).orElse(0L);
+                count = l.longValue();
             } else {
                 count = 0;
             }
diff --git 
a/plugins/baseplugin/src/main/resources/META-INF/cxs/painless/updatePastEventOccurences.painless
 
b/plugins/baseplugin/src/main/resources/META-INF/cxs/painless/updatePastEventOccurences.painless
new file mode 100644
index 000000000..37563e35e
--- /dev/null
+++ 
b/plugins/baseplugin/src/main/resources/META-INF/cxs/painless/updatePastEventOccurences.painless
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+if (params.containsKey(ctx._source.itemId)) {
+    Map pastEventKeyValue = params.get(ctx._source.itemId);
+    String pastEventKey = pastEventKeyValue.get('pastEventKey');
+    Long valueToAdd = (Long) pastEventKeyValue.get('valueToAdd');
+
+    if (ctx._source.systemProperties == null) {
+        ctx._source.systemProperties = new HashMap();
+    }
+
+    if (ctx._source.systemProperties.pastEvents == null) {
+        ctx._source.systemProperties.pastEvents = new ArrayList();
+    }
+
+    boolean exists = false;
+    for (pastEvent in ctx._source.systemProperties.pastEvents) {
+        if (pastEvent.get('key') == pastEventKey) {
+            pastEvent.put('count', valueToAdd);
+            exists = true;
+        }
+    }
+
+    if (!exists) {
+        Map newPastEvent = new HashMap();
+        newPastEvent.put('key', pastEventKey);
+        newPastEvent.put('count', valueToAdd);
+        ctx._source.systemProperties.pastEvents.add(newPastEvent);
+    }
+
+    ctx._source.systemProperties.put('lastUpdated', new Date());
+}
diff --git 
a/services/src/main/java/org/apache/unomi/services/impl/definitions/DefinitionsServiceImpl.java
 
b/services/src/main/java/org/apache/unomi/services/impl/definitions/DefinitionsServiceImpl.java
index 9a098b63e..32ccdfc6f 100644
--- 
a/services/src/main/java/org/apache/unomi/services/impl/definitions/DefinitionsServiceImpl.java
+++ 
b/services/src/main/java/org/apache/unomi/services/impl/definitions/DefinitionsServiceImpl.java
@@ -25,6 +25,7 @@ import org.apache.unomi.api.conditions.Condition;
 import org.apache.unomi.api.conditions.ConditionType;
 import org.apache.unomi.api.services.DefinitionsService;
 import org.apache.unomi.api.services.SchedulerService;
+import org.apache.unomi.api.utils.ConditionBuilder;
 import org.apache.unomi.persistence.spi.CustomObjectMapper;
 import org.apache.unomi.persistence.spi.PersistenceService;
 import org.apache.unomi.api.utils.ParserHelper;
@@ -67,6 +68,7 @@ public class DefinitionsServiceImpl implements 
DefinitionsService, SynchronousBu
 
     private long definitionsRefreshInterval = 10000;
 
+    private ConditionBuilder conditionBuilder;
     private BundleContext bundleContext;
     public DefinitionsServiceImpl() {
     }
@@ -101,6 +103,7 @@ public class DefinitionsServiceImpl implements 
DefinitionsService, SynchronousBu
 
         bundleContext.addBundleListener(this);
         scheduleTypeReloads();
+        conditionBuilder = new ConditionBuilder(this);
         logger.info("Definitions service initialized.");
     }
 
@@ -523,4 +526,10 @@ public class DefinitionsServiceImpl implements 
DefinitionsService, SynchronousBu
     public void refresh() {
         reloadTypes(true);
     }
+
+    @Override
+    public ConditionBuilder getConditionBuilder() {
+        return conditionBuilder;
+    }
+
 }
diff --git 
a/services/src/main/java/org/apache/unomi/services/impl/profiles/ProfileServiceImpl.java
 
b/services/src/main/java/org/apache/unomi/services/impl/profiles/ProfileServiceImpl.java
index 56bf686d8..dd30ba863 100644
--- 
a/services/src/main/java/org/apache/unomi/services/impl/profiles/ProfileServiceImpl.java
+++ 
b/services/src/main/java/org/apache/unomi/services/impl/profiles/ProfileServiceImpl.java
@@ -881,8 +881,13 @@ public class ProfileServiceImpl implements ProfileService, 
SynchronousBundleList
         if (session.getItemId() == null) {
             return null;
         }
-        if (session.getProfile() != null && 
session.getProfile().getProperties() != null) {
-            
session.getProfile().setProperties(removePersonalIdentifiersFromSessionProfile(session.getProfile().getProperties()));
+        if (session.getProfile() != null) {
+            if (session.getProfile().getProperties() != null){
+                
session.getProfile().setProperties(removePersonalIdentifiersFromSessionProfile(session.getProfile().getProperties()));
+            }
+            if (session.getProfile().getSystemProperties() != null){
+                
session.getProfile().getSystemProperties().entrySet().removeIf(entry -> 
entry.getKey().equals("pastEvents"));
+            }
         }
         return persistenceService.save(session) ? session : null;
     }
diff --git 
a/services/src/main/java/org/apache/unomi/services/impl/segments/SegmentServiceImpl.java
 
b/services/src/main/java/org/apache/unomi/services/impl/segments/SegmentServiceImpl.java
index 0aac270c6..fee5ef0fb 100644
--- 
a/services/src/main/java/org/apache/unomi/services/impl/segments/SegmentServiceImpl.java
+++ 
b/services/src/main/java/org/apache/unomi/services/impl/segments/SegmentServiceImpl.java
@@ -20,11 +20,7 @@ package org.apache.unomi.services.impl.segments;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import net.jodah.failsafe.Failsafe;
 import net.jodah.failsafe.RetryPolicy;
-import org.apache.unomi.api.Event;
-import org.apache.unomi.api.Item;
-import org.apache.unomi.api.Metadata;
-import org.apache.unomi.api.PartialList;
-import org.apache.unomi.api.Profile;
+import org.apache.unomi.api.*;
 import org.apache.unomi.api.actions.Action;
 import org.apache.unomi.api.conditions.Condition;
 import org.apache.unomi.api.conditions.ConditionType;
@@ -35,6 +31,7 @@ import org.apache.unomi.api.services.EventService;
 import org.apache.unomi.api.services.RulesService;
 import org.apache.unomi.api.services.SchedulerService;
 import org.apache.unomi.api.services.SegmentService;
+import org.apache.unomi.api.utils.ConditionBuilder;
 import org.apache.unomi.persistence.spi.CustomObjectMapper;
 import org.apache.unomi.persistence.spi.aggregate.TermsAggregate;
 import org.apache.unomi.services.impl.AbstractServiceImpl;
@@ -51,6 +48,7 @@ import org.slf4j.LoggerFactory;
 import java.io.IOException;
 import java.net.URL;
 import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.time.Duration;
 import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
@@ -801,7 +799,7 @@ public class SegmentServiceImpl extends AbstractServiceImpl 
implements SegmentSe
     private void recalculatePastEventOccurrencesOnProfiles(Condition 
eventCondition, Condition parentCondition,
                                                            boolean 
forceRefresh, boolean resetExistingProfilesNotMatching) {
         long t = System.currentTimeMillis();
-        List<Condition> l = new ArrayList<Condition>();
+        List<Condition> l = new ArrayList<>();
         Condition andCondition = new Condition();
         
andCondition.setConditionType(definitionsService.getConditionType("booleanCondition"));
         andCondition.setParameter("operator", "and");
@@ -877,25 +875,25 @@ public class SegmentServiceImpl extends 
AbstractServiceImpl implements SegmentSe
      * Return the list of profile ids, for profiles that already have an event 
count matching the generated property key
      *
      * @param generatedPropertyKey the generated property key of the generated 
rule for the given past event condition.
-     * @return the list of profile ids.
+     * @return the set of profile ids.
      */
     private Set<String> getExistingProfilesWithPastEventOccurrenceCount(String 
generatedPropertyKey) {
-        Condition countExistsCondition = new Condition();
-        
countExistsCondition.setConditionType(definitionsService.getConditionType("profilePropertyCondition"));
-        countExistsCondition.setParameter("propertyName", 
"systemProperties.pastEvents." + generatedPropertyKey);
-        countExistsCondition.setParameter("comparisonOperator", "greaterThan");
-        countExistsCondition.setParameter("propertyValueInteger", 0);
+        ConditionBuilder conditionBuilder = 
definitionsService.getConditionBuilder();
+        ConditionBuilder.ConditionItem subConditionCount = 
conditionBuilder.profileProperty("systemProperties.pastEvents.count").greaterThan(0);
+        ConditionBuilder.ConditionItem subConditionKey = 
conditionBuilder.profileProperty("systemProperties.pastEvents.key").equalTo(generatedPropertyKey);
+        ConditionBuilder.ConditionItem booleanCondition = 
conditionBuilder.and(subConditionCount, subConditionKey);
+        Condition condition = conditionBuilder.nested(booleanCondition, 
"systemProperties.pastEvents").build();
 
         Set<String> profileIds = new HashSet<>();
         if (pastEventsDisablePartitions) {
-            
profileIds.addAll(persistenceService.aggregateWithOptimizedQuery(countExistsCondition,
 new TermsAggregate("itemId"),
+            
profileIds.addAll(persistenceService.aggregateWithOptimizedQuery(condition, new 
TermsAggregate("itemId"),
                     Profile.ITEM_TYPE, maximumIdsQueryCount).keySet());
         } else {
-            Map<String, Double> m = 
persistenceService.getSingleValuesMetrics(countExistsCondition, new 
String[]{"card"}, "itemId.keyword", Profile.ITEM_TYPE);
+            Map<String, Double> m = 
persistenceService.getSingleValuesMetrics(condition, new String[]{"card"}, 
"itemId.keyword", Profile.ITEM_TYPE);
             long card = m.get("_card").longValue();
             int numParts = (int) (card / aggregateQueryBucketSize) + 2;
             for (int i = 0; i < numParts; i++) {
-                
profileIds.addAll(persistenceService.aggregateWithOptimizedQuery(countExistsCondition,
 new TermsAggregate("itemId", i, numParts),
+                
profileIds.addAll(persistenceService.aggregateWithOptimizedQuery(condition, new 
TermsAggregate("itemId", i, numParts),
                         Profile.ITEM_TYPE).keySet());
             }
         }
@@ -986,35 +984,35 @@ public class SegmentServiceImpl extends 
AbstractServiceImpl implements SegmentSe
      *
      * @param eventCountByProfile the events count per profileId map
      * @param propertyKey         the generate property key for this past 
event condition, to keep track of the count in the profile
-     * @return the list of profiles for witch the count of event occurrences 
have been updated.
+     * @return the set of profiles for witch the count of event occurrences 
have been updated.
      */
     private Set<String> updatePastEventOccurrencesOnProfiles(Map<String, Long> 
eventCountByProfile, String propertyKey) {
         Set<String> profilesUpdated = new HashSet<>();
-        Map<Item, Map> batch = new HashMap<>();
+        Set<String> batchProfilesToUpdate = new HashSet<>();
         Iterator<Map.Entry<String, Long>> entryIterator = 
eventCountByProfile.entrySet().iterator();
+        Map<String, Map<String, Object>> paramPerProfile = new HashMap<>();
+
         while (entryIterator.hasNext()) {
             Map.Entry<String, Long> entry = entryIterator.next();
             String profileId = entry.getKey();
             if (!profileId.startsWith("_")) {
-                Map<String, Long> pastEventCounts = new HashMap<>();
-                pastEventCounts.put(propertyKey, entry.getValue());
-                Map<String, Object> systemProperties = new HashMap<>();
-                systemProperties.put("pastEvents", pastEventCounts);
-                systemProperties.put("lastUpdated", new Date());
-
-                Profile profile = new Profile();
-                profile.setItemId(profileId);
-                batch.put(profile, 
Collections.singletonMap("systemProperties", systemProperties));
+                Map<String, Object> pastEventKeyValue = new HashMap<>();
+                pastEventKeyValue.put("pastEventKey", propertyKey);
+                pastEventKeyValue.put("valueToAdd", entry.getValue());
+                paramPerProfile.put(profileId, pastEventKeyValue);
                 profilesUpdated.add(profileId);
+                batchProfilesToUpdate.add(profileId);
             }
 
-            if (batch.size() == segmentUpdateBatchSize || 
(!entryIterator.hasNext() && batch.size() > 0)) {
+            if (batchProfilesToUpdate.size() == segmentUpdateBatchSize || 
(!entryIterator.hasNext() && !batchProfilesToUpdate.isEmpty())) {
                 try {
-                    persistenceService.update(batch, Profile.class);
+                    Condition profileIdCondition = 
definitionsService.getConditionBuilder().condition("idsCondition").parameter("ids",
 batchProfilesToUpdate).parameter("match", true).build();
+                    
persistenceService.updateWithQueryAndStoredScript(Profile.class, new 
String[]{"updatePastEventOccurences"}, new Map[]{paramPerProfile}, new 
Condition[]{profileIdCondition});
                 } catch (Exception e) {
-                    logger.error("Error updating {} profiles for past event 
system properties", batch.size(), e);
+                    logger.error("Error updating {} profiles for past event 
system properties", paramPerProfile.size(), e);
                 } finally {
-                    batch.clear();
+                    paramPerProfile.clear();
+                    batchProfilesToUpdate.clear();
                 }
             }
         }
@@ -1030,7 +1028,7 @@ public class SegmentServiceImpl extends 
AbstractServiceImpl implements SegmentSe
                 sb.append(Integer.toHexString((array[i] & 0xFF) | 
0x100).substring(1, 3));
             }
             return sb.toString();
-        } catch (java.security.NoSuchAlgorithmException e) {
+        } catch (NoSuchAlgorithmException e) {
             throw new RuntimeException(e);
         }
     }
diff --git 
a/tools/shell-commands/src/main/resources/META-INF/cxs/migration/migrate-2.5.0-00-cleanPastEventProfileSession.groovy
 
b/tools/shell-commands/src/main/resources/META-INF/cxs/migration/migrate-2.5.0-00-cleanPastEventProfileSession.groovy
new file mode 100644
index 000000000..7b519ce47
--- /dev/null
+++ 
b/tools/shell-commands/src/main/resources/META-INF/cxs/migration/migrate-2.5.0-00-cleanPastEventProfileSession.groovy
@@ -0,0 +1,48 @@
+import org.apache.unomi.shell.migration.service.MigrationContext
+import org.apache.unomi.shell.migration.utils.HttpUtils
+import org.apache.unomi.shell.migration.utils.MigrationUtils
+import org.osgi.framework.BundleContext
+import org.osgi.framework.Bundle
+
+/*
+ * 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.
+ */
+
+MigrationContext context = migrationContext
+String esAddress = context.getConfigString("esAddress")
+String indexPrefix = context.getConfigString("indexPrefix")
+String rolloverPolicyName = indexPrefix + "-unomi-rollover-policy"
+String rolloverEventAlias = indexPrefix + "-session"
+
+context.performMigrationStep("2.5.0-clean-profile-mapping", () -> {
+    String baseSettings = MigrationUtils.resourceAsString(bundleContext, 
"requestBody/2.0.0/base_index_mapping.json")
+    String updatePastEventScript = 
MigrationUtils.getFileWithoutComments(bundleContext, 
"requestBody/2.5.0/update_pastEvents_profile.painless")
+    String mapping = MigrationUtils.extractMappingFromBundles(bundleContext, 
"profile.json")
+    String newIndexSettings = 
MigrationUtils.buildIndexCreationRequest(baseSettings, mapping, context, false)
+    MigrationUtils.reIndex(context.getHttpClient(), bundleContext, esAddress, 
indexPrefix + "-profile", newIndexSettings, updatePastEventScript, context)
+})
+
+context.performMigrationStep("2.5.0-clean-session-mapping", () -> {
+    String baseSettings = MigrationUtils.resourceAsString(bundleContext, 
"requestBody/2.2.0/base_index_withRollover_request.json")
+    String cleanPastEventScript = 
MigrationUtils.getFileWithoutComments(bundleContext, 
"requestBody/2.5.0/remove_pastEvents_session.painless")
+    String mapping = MigrationUtils.extractMappingFromBundles(bundleContext, 
"session.json")
+    String newIndexSettings = 
MigrationUtils.buildIndexCreationRequestWithRollover(baseSettings, mapping, 
context, rolloverPolicyName, rolloverEventAlias)
+    Set<String> sessionIndices = 
MigrationUtils.getIndexesPrefixedBy(context.getHttpClient(), esAddress, 
"${indexPrefix}-session-")
+
+    sessionIndices.each { sessionIndex ->
+        MigrationUtils.reIndex(context.getHttpClient(), bundleContext, 
esAddress, sessionIndex, newIndexSettings, cleanPastEventScript, context)
+    }
+})
diff --git 
a/tools/shell-commands/src/main/resources/requestBody/2.5.0/remove_pastEvents_session.painless
 
b/tools/shell-commands/src/main/resources/requestBody/2.5.0/remove_pastEvents_session.painless
new file mode 100644
index 000000000..6e3b6d248
--- /dev/null
+++ 
b/tools/shell-commands/src/main/resources/requestBody/2.5.0/remove_pastEvents_session.painless
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+if (ctx._source.profile != null) {
+    if (ctx._source.profile.systemProperties != null && 
ctx._source.profile.systemProperties.pastEvents != null) {
+         ctx._source.profile.systemProperties.remove('pastEvents');
+    }
+}
diff --git 
a/tools/shell-commands/src/main/resources/requestBody/2.5.0/update_pastEvents_profile.painless
 
b/tools/shell-commands/src/main/resources/requestBody/2.5.0/update_pastEvents_profile.painless
new file mode 100644
index 000000000..9c6768084
--- /dev/null
+++ 
b/tools/shell-commands/src/main/resources/requestBody/2.5.0/update_pastEvents_profile.painless
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+if (ctx._source.systemProperties != null && 
ctx._source.systemProperties.pastEvents != null && 
ctx._source.systemProperties.pastEvents instanceof Map) {
+    List listOfPastEvent = new ArrayList();
+    for (pastEventKey in ctx._source.systemProperties.pastEvents.keySet()) {
+        Map pastEvent = new HashMap();
+        pastEvent.put('key', pastEventKey);
+        pastEvent.put('count', 
ctx._source.systemProperties.pastEvents.get(pastEventKey));
+        listOfPastEvent.add(pastEvent);
+    }
+    ctx._source.systemProperties.pastEvents = listOfPastEvent;
+}

Reply via email to