You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by dr...@apache.org on 2017/11/02 13:46:03 UTC

incubator-unomi git commit: UNOMI-134 : Added personalized sorts in request, with sort services and customizable sort strategies

Repository: incubator-unomi
Updated Branches:
  refs/heads/scores-filters [created] d85a8ae81


UNOMI-134 : Added personalized sorts in request, with sort services and customizable sort strategies


Project: http://git-wip-us.apache.org/repos/asf/incubator-unomi/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-unomi/commit/d85a8ae8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-unomi/tree/d85a8ae8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-unomi/diff/d85a8ae8

Branch: refs/heads/scores-filters
Commit: d85a8ae81199868e712e9cf4fc1080583ac1b434
Parents: b1f5951
Author: Thomas Draier <dr...@apache.org>
Authored: Thu Nov 2 14:44:51 2017 +0100
Committer: Thomas Draier <dr...@apache.org>
Committed: Thu Nov 2 14:44:51 2017 +0100

----------------------------------------------------------------------
 .../org/apache/unomi/api/ContextRequest.java    |  69 +++++++++++++
 .../org/apache/unomi/api/ContextResponse.java   |  11 ++
 .../java/org/apache/unomi/api/SortStrategy.java |  24 +++++
 .../apache/unomi/api/services/SortService.java  |  30 ++++++
 .../services/services/SortServiceImpl.java      |  65 ++++++++++++
 .../services/sorts/FilterSortStrategy.java      |  59 +++++++++++
 .../services/sorts/RandomSortStrategy.java      |  35 +++++++
 .../unomi/services/sorts/ScoreSortStrategy.java | 101 +++++++++++++++++++
 .../resources/OSGI-INF/blueprint/blueprint.xml  |  41 ++++++++
 .../org/apache/unomi/web/ContextServlet.java    |  17 +++-
 .../resources/OSGI-INF/blueprint/blueprint.xml  |   2 +
 11 files changed, 453 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/d85a8ae8/api/src/main/java/org/apache/unomi/api/ContextRequest.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/unomi/api/ContextRequest.java b/api/src/main/java/org/apache/unomi/api/ContextRequest.java
index f273907..21c7f00 100644
--- a/api/src/main/java/org/apache/unomi/api/ContextRequest.java
+++ b/api/src/main/java/org/apache/unomi/api/ContextRequest.java
@@ -55,6 +55,7 @@ public class ContextRequest {
     private List<String> requiredSessionProperties;
     private List<Event> events;
     private List<FilteredContent> filters;
+    private List<SortRequest> sorts;
 
     // the following overrides make it possible to override temporarily the current profile segments, properties or
     // even session properties. This is useful for building UIs to temporarily override one of these parameters to
@@ -159,6 +160,14 @@ public class ContextRequest {
         this.filters = filters;
     }
 
+    public List<SortRequest> getSorts() {
+        return sorts;
+    }
+
+    public void setSorts(List<SortRequest> sorts) {
+        this.sorts = sorts;
+    }
+
     /**
      * Retrieves the events that the client has generated as part of its processes and wishes the context server to process.
      *
@@ -215,11 +224,54 @@ public class ContextRequest {
     }
 
     /**
+     *
+     */
+    public static class SortRequest {
+        private String id;
+        private String strategy;
+        private Map<String, Object> strategyOptions;
+        private List<FilteredContent> contents;
+
+        public String getId() {
+            return id;
+        }
+
+        public void setId(String id) {
+            this.id = id;
+        }
+
+        public String getStrategy() {
+            return strategy;
+        }
+
+        public void setStrategy(String strategy) {
+            this.strategy = strategy;
+        }
+
+        public List<FilteredContent> getContents() {
+            return contents;
+        }
+
+        public void setContents(List<FilteredContent> contents) {
+            this.contents = contents;
+        }
+
+        public Map<String, Object> getStrategyOptions() {
+            return strategyOptions;
+        }
+
+        public void setStrategyOptions(Map<String, Object> strategyOptions) {
+            this.strategyOptions = strategyOptions;
+        }
+    }
+
+    /**
      * A content filtering definition.
      */
     public static class FilteredContent {
         private String filterid;
         private List<Filter> filters;
+        private Map<String,Object> properties;
 
         /**
          * Retrieves the filter identifier associated with this content filtering definition.
@@ -256,6 +308,14 @@ public class ContextRequest {
         public void setFilters(List<Filter> filters) {
             this.filters = filters;
         }
+
+        public Map<String, Object> getProperties() {
+            return properties;
+        }
+
+        public void setProperties(Map<String, Object> properties) {
+            this.properties = properties;
+        }
     }
 
     /**
@@ -264,6 +324,7 @@ public class ContextRequest {
     public static class Filter {
         private List<Target> appliesOn;
         private Condition condition;
+        private Map<String,Object> properties;
 
         /**
          * Retrieves the list of targets this filter applies on.
@@ -300,6 +361,14 @@ public class ContextRequest {
         public void setCondition(Condition condition) {
             this.condition = condition;
         }
+
+        public Map<String, Object> getProperties() {
+            return properties;
+        }
+
+        public void setProperties(Map<String, Object> properties) {
+            this.properties = properties;
+        }
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/d85a8ae8/api/src/main/java/org/apache/unomi/api/ContextResponse.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/unomi/api/ContextResponse.java b/api/src/main/java/org/apache/unomi/api/ContextResponse.java
index 58bcadd..5ef4d06 100644
--- a/api/src/main/java/org/apache/unomi/api/ContextResponse.java
+++ b/api/src/main/java/org/apache/unomi/api/ContextResponse.java
@@ -21,6 +21,7 @@ import org.apache.unomi.api.conditions.Condition;
 import org.apache.unomi.api.services.RulesService;
 
 import java.io.Serializable;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -46,6 +47,8 @@ public class ContextResponse implements Serializable {
 
     private Map<String, Boolean> filteringResults;
 
+    private Map<String, List<String>> sortResults;
+
     private Set<Condition> trackedConditions;
 
     private boolean anonymousBrowsing;
@@ -163,6 +166,14 @@ public class ContextResponse implements Serializable {
         this.filteringResults = filteringResults;
     }
 
+    public Map<String, List<String>> getSortResults() {
+        return sortResults;
+    }
+
+    public void setSortResults(Map<String, List<String>> sortResults) {
+        this.sortResults = sortResults;
+    }
+
     /**
      * Retrieves the tracked conditions, if any, associated with the source of the context request that resulted in this ContextResponse. Upon evaluating the incoming request,
      * the context server will determine if there are any rules marked with the "trackedCondition" tag and which source condition matches the source of the incoming request and

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/d85a8ae8/api/src/main/java/org/apache/unomi/api/SortStrategy.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/unomi/api/SortStrategy.java b/api/src/main/java/org/apache/unomi/api/SortStrategy.java
new file mode 100644
index 0000000..c5d5acb
--- /dev/null
+++ b/api/src/main/java/org/apache/unomi/api/SortStrategy.java
@@ -0,0 +1,24 @@
+/*
+ * 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.api;
+
+import java.util.List;
+
+public interface SortStrategy {
+
+    List<String> sort(Profile profile, Session session, ContextRequest.SortRequest sortRequest);
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/d85a8ae8/api/src/main/java/org/apache/unomi/api/services/SortService.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/unomi/api/services/SortService.java b/api/src/main/java/org/apache/unomi/api/services/SortService.java
new file mode 100644
index 0000000..e169df7
--- /dev/null
+++ b/api/src/main/java/org/apache/unomi/api/services/SortService.java
@@ -0,0 +1,30 @@
+/*
+ * 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.api.services;
+
+import org.apache.unomi.api.ContextRequest;
+import org.apache.unomi.api.Profile;
+import org.apache.unomi.api.Session;
+
+import java.util.List;
+
+public interface SortService {
+
+    List<String> sort(Profile profile, Session session, ContextRequest.SortRequest sortRequest);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/d85a8ae8/services/src/main/java/org/apache/unomi/services/services/SortServiceImpl.java
----------------------------------------------------------------------
diff --git a/services/src/main/java/org/apache/unomi/services/services/SortServiceImpl.java b/services/src/main/java/org/apache/unomi/services/services/SortServiceImpl.java
new file mode 100644
index 0000000..ac9b3e1
--- /dev/null
+++ b/services/src/main/java/org/apache/unomi/services/services/SortServiceImpl.java
@@ -0,0 +1,65 @@
+/*
+ * 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.services.services;
+
+import org.apache.unomi.api.ContextRequest;
+import org.apache.unomi.api.Profile;
+import org.apache.unomi.api.Session;
+import org.apache.unomi.api.SortStrategy;
+import org.apache.unomi.api.services.SortService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class SortServiceImpl implements SortService {
+
+    private BundleContext bundleContext;
+
+    private Map<String, SortStrategy> sortStrategies = new ConcurrentHashMap<>();
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public void addSortStrategy(ServiceReference<SortStrategy> sortStrategyRef) {
+        SortStrategy sortStrategy = bundleContext.getService(sortStrategyRef);
+        sortStrategies.put(sortStrategyRef.getProperty("sortStrategyId").toString(), sortStrategy);
+    }
+
+    public void removeSortStrategy(ServiceReference<SortStrategy> sortStrategyRef) {
+        if (sortStrategyRef == null) {
+            return;
+        }
+        sortStrategies.remove(sortStrategyRef.getProperty("sortStrategyId").toString());
+    }
+
+
+    @Override
+    public List<String> sort(Profile profile, Session session, ContextRequest.SortRequest sortRequest) {
+        SortStrategy strategy = sortStrategies.get(sortRequest.getStrategy());
+
+        if (strategy != null) {
+            return strategy.sort(profile, session, sortRequest);
+        }
+
+        throw new IllegalArgumentException("Unknown strategy : "+sortRequest.getStrategy());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/d85a8ae8/services/src/main/java/org/apache/unomi/services/sorts/FilterSortStrategy.java
----------------------------------------------------------------------
diff --git a/services/src/main/java/org/apache/unomi/services/sorts/FilterSortStrategy.java b/services/src/main/java/org/apache/unomi/services/sorts/FilterSortStrategy.java
new file mode 100644
index 0000000..5036bf5
--- /dev/null
+++ b/services/src/main/java/org/apache/unomi/services/sorts/FilterSortStrategy.java
@@ -0,0 +1,59 @@
+/*
+ * 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.services.sorts;
+
+import org.apache.unomi.api.ContextRequest;
+import org.apache.unomi.api.Profile;
+import org.apache.unomi.api.Session;
+import org.apache.unomi.api.SortStrategy;
+import org.apache.unomi.api.conditions.Condition;
+import org.apache.unomi.api.services.ProfileService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FilterSortStrategy implements SortStrategy {
+
+    private ProfileService profileService;
+
+    public void setProfileService(ProfileService profileService) {
+        this.profileService = profileService;
+    }
+
+    @Override
+    public List<String> sort(Profile profile, Session session, ContextRequest.SortRequest sortRequest) {
+        List<String> sortedContent = new ArrayList<>();
+        for (ContextRequest.FilteredContent filteredContent : sortRequest.getContents()) {
+            boolean result = true;
+            for (ContextRequest.Filter filter : filteredContent.getFilters()) {
+                Condition condition = filter.getCondition();
+                result &= profileService.matchCondition(condition, profile, session);
+            }
+            if (result) {
+                sortedContent.add(filteredContent.getFilterid());
+            }
+        }
+
+        String fallback = (String) sortRequest.getStrategyOptions().get("fallback");
+        if (fallback != null && !sortedContent.contains(fallback)) {
+            sortedContent.add(fallback);
+        }
+
+        return sortedContent;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/d85a8ae8/services/src/main/java/org/apache/unomi/services/sorts/RandomSortStrategy.java
----------------------------------------------------------------------
diff --git a/services/src/main/java/org/apache/unomi/services/sorts/RandomSortStrategy.java b/services/src/main/java/org/apache/unomi/services/sorts/RandomSortStrategy.java
new file mode 100644
index 0000000..ee25af0
--- /dev/null
+++ b/services/src/main/java/org/apache/unomi/services/sorts/RandomSortStrategy.java
@@ -0,0 +1,35 @@
+/*
+ * 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.services.sorts;
+
+import org.apache.unomi.api.ContextRequest;
+import org.apache.unomi.api.Profile;
+import org.apache.unomi.api.Session;
+
+import java.util.Collections;
+import java.util.List;
+
+public class RandomSortStrategy extends FilterSortStrategy {
+
+    @Override
+    public List<String> sort(Profile profile, Session session, ContextRequest.SortRequest sortRequest) {
+        List<String> r = super.sort(profile, session, sortRequest);
+        Collections.shuffle(r);
+        return r;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/d85a8ae8/services/src/main/java/org/apache/unomi/services/sorts/ScoreSortStrategy.java
----------------------------------------------------------------------
diff --git a/services/src/main/java/org/apache/unomi/services/sorts/ScoreSortStrategy.java b/services/src/main/java/org/apache/unomi/services/sorts/ScoreSortStrategy.java
new file mode 100644
index 0000000..65c99ea
--- /dev/null
+++ b/services/src/main/java/org/apache/unomi/services/sorts/ScoreSortStrategy.java
@@ -0,0 +1,101 @@
+/*
+ * 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.services.sorts;
+
+import org.apache.unomi.api.ContextRequest;
+import org.apache.unomi.api.Profile;
+import org.apache.unomi.api.Session;
+import org.apache.unomi.api.SortStrategy;
+import org.apache.unomi.api.conditions.Condition;
+import org.apache.unomi.api.services.ProfileService;
+
+import java.util.*;
+
+public class ScoreSortStrategy implements SortStrategy {
+
+    private ProfileService profileService;
+
+    public void setProfileService(ProfileService profileService) {
+        this.profileService = profileService;
+    }
+
+    @Override
+    public List<String> sort(Profile profile, Session session, ContextRequest.SortRequest sortRequest) {
+        List<String> sortedContent = new ArrayList<>();
+        final Map<String,Integer> t = new HashMap<>();
+
+        Integer threshold = (Integer) sortRequest.getStrategyOptions().get("threshold");
+        if (threshold == null) {
+            threshold = 0;
+        }
+
+        for (ContextRequest.FilteredContent filteredContent : sortRequest.getContents()) {
+            int score = 0;
+
+            String interestList = (String) (filteredContent.getProperties() != null ? filteredContent.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.get(interest) != null) {
+                        score += interestValues.get(interest);
+                    }
+                }
+            }
+
+            String scoringPlanList = (String) (filteredContent.getProperties() != null ? filteredContent.getProperties().get("scoringPlans") : null);
+            if (scoringPlanList != null) {
+                Map<String,Integer> scoreValues = (Map<String, Integer>) profile.getScores();
+                for (String scoringPlan : scoringPlanList.split(" ")) {
+                    if (scoreValues.get(scoringPlan) != null) {
+                        score += scoreValues.get(scoringPlan);
+                    }
+                }
+            }
+
+            for (ContextRequest.Filter filter : filteredContent.getFilters()) {
+                Condition condition = filter.getCondition();
+                if (condition.getConditionType() != null) {
+                    if (profileService.matchCondition(condition, profile, session)) {
+                        if (filter.getProperties().get("score") != null) {
+                            score += (int) filter.getProperties().get("score");
+                        } else {
+                            score += 1;
+                        }
+                    }
+                }
+            }
+            if (score >= threshold) {
+                t.put(filteredContent.getFilterid(), score);
+                sortedContent.add(filteredContent.getFilterid());
+            }
+        }
+        Collections.sort(sortedContent, new Comparator<String>() {
+            @Override
+            public int compare(String o1, String o2) {
+                return t.get(o2) - t.get(o1);
+            }
+        });
+
+        String fallback = (String) sortRequest.getStrategyOptions().get("fallback");
+        if (fallback != null && !sortedContent.contains(fallback)) {
+            sortedContent.add(fallback);
+        }
+
+        return sortedContent;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/d85a8ae8/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
----------------------------------------------------------------------
diff --git a/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index f317e96..a5e788a 100644
--- a/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -171,6 +171,12 @@
     </bean>
     <service id="clusterService" ref="clusterServiceImpl" auto-export="interfaces"/>
 
+
+    <bean id="sortServiceImpl" class="org.apache.unomi.services.services.SortServiceImpl">
+        <property name="bundleContext" ref="blueprintBundleContext"/>
+    </bean>
+    <service id="sortService" ref="sortServiceImpl" auto-export="interfaces"/>
+
     <!-- We use a listener here because using the list directly for listening to proxies coming from the same bundle didn't seem to work -->
     <reference-list id="eventListenerServices"
                     interface="org.apache.unomi.api.services.EventListenerService"
@@ -186,6 +192,13 @@
                 bind-method="bindExecutor" unbind-method="unbindExecutor" ref="rulesServiceImpl"/>
     </reference-list>
 
+    <reference-list id="sortStrategies"
+                    interface="org.apache.unomi.api.SortStrategy"
+                    availability="optional">
+        <reference-listener
+                bind-method="addSortStrategy" unbind-method="removeSortStrategy" ref="sortServiceImpl"/>
+    </reference-list>
+
     <!-- Property merge strategy executors -->
 
     <service auto-export="interfaces">
@@ -228,6 +241,34 @@
         </bean>
     </service>
 
+    <service auto-export="interfaces">
+        <service-properties>
+            <entry key="sortStrategyId" value="matching-first"/>
+        </service-properties>
+        <bean class="org.apache.unomi.services.sorts.FilterSortStrategy">
+            <property name="profileService" ref="profileServiceImpl"/>
+        </bean>
+    </service>
+
+    <service auto-export="interfaces">
+        <service-properties>
+            <entry key="sortStrategyId" value="random"/>
+        </service-properties>
+        <bean class="org.apache.unomi.services.sorts.RandomSortStrategy">
+            <property name="profileService" ref="profileServiceImpl"/>
+        </bean>
+    </service>
+
+    <service auto-export="interfaces">
+        <service-properties>
+            <entry key="sortStrategyId" value="score-sorted"/>
+        </service-properties>
+        <bean class="org.apache.unomi.services.sorts.ScoreSortStrategy">
+            <property name="profileService" ref="profileServiceImpl"/>
+        </bean>
+    </service>
+
+
     <bean id="configSharingServiceImpl" class="org.apache.unomi.services.services.ConfigSharingServiceImpl" destroy-method="preDestroy">
         <property name="configProperties">
             <map>

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/d85a8ae8/wab/src/main/java/org/apache/unomi/web/ContextServlet.java
----------------------------------------------------------------------
diff --git a/wab/src/main/java/org/apache/unomi/web/ContextServlet.java b/wab/src/main/java/org/apache/unomi/web/ContextServlet.java
index 245dc94..1519a01 100644
--- a/wab/src/main/java/org/apache/unomi/web/ContextServlet.java
+++ b/wab/src/main/java/org/apache/unomi/web/ContextServlet.java
@@ -53,6 +53,7 @@ public class ContextServlet extends HttpServlet {
     private EventService eventService;
     private RulesService rulesService;
     private PrivacyService privacyService;
+    private SortService sortService;
     private ConfigSharingService configSharingService;
 
     private String profileIdCookieName = "context-profile-id";
@@ -360,12 +361,22 @@ public class ContextServlet extends HttpServlet {
                 boolean result = true;
                 for (ContextRequest.Filter filter : filteredContent.getFilters()) {
                     Condition condition = filter.getCondition();
-                    result &= profileService.matchCondition(condition, profile, session);
+                    if (condition.getConditionType() != null) {
+                        result &= profileService.matchCondition(condition, profile, session);
+                    }
                 }
                 data.getFilteringResults().put(filteredContent.getFilterid(), result);
             }
         }
 
+        List<ContextRequest.SortRequest> sorts = contextRequest.getSorts();
+        if (sorts != null) {
+            data.setSortResults(new HashMap<String, List<String>>());
+            for (ContextRequest.SortRequest sort : sorts) {
+                data.getSortResults().put(sort.getId(), sortService.sort(profile, session, sort));
+            }
+        }
+
         if(!(profile instanceof Persona)) {
             data.setTrackedConditions(rulesService.getTrackedConditions(contextRequest.getSource()));
         } else {
@@ -450,6 +461,10 @@ public class ContextServlet extends HttpServlet {
         this.privacyService = privacyService;
     }
 
+    public void setSortService(SortService sortService) {
+        this.sortService = sortService;
+    }
+
     public void setConfigSharingService(ConfigSharingService configSharingService) {
         this.configSharingService = configSharingService;
     }

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/d85a8ae8/wab/src/main/resources/OSGI-INF/blueprint/blueprint.xml
----------------------------------------------------------------------
diff --git a/wab/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/wab/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index b38a97a..295ff99 100644
--- a/wab/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/wab/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -26,6 +26,7 @@
     <reference id="eventService" interface="org.apache.unomi.api.services.EventService"/>
     <reference id="rulesService" interface="org.apache.unomi.api.services.RulesService"/>
     <reference id="privacyService" interface="org.apache.unomi.api.services.PrivacyService"/>
+    <reference id="sortService" interface="org.apache.unomi.api.services.SortService"/>
     <reference id="configSharingService" interface="org.apache.unomi.api.services.ConfigSharingService" />
 
     <cm:property-placeholder persistent-id="org.apache.unomi.web"
@@ -43,6 +44,7 @@
         <property name="eventService" ref="eventService"/>
         <property name="rulesService" ref="rulesService"/>
         <property name="privacyService" ref="privacyService" />
+        <property name="sortService" ref="sortService"/>
         <property name="configSharingService" ref="configSharingService"/>
         <property name="profileIdCookieDomain" value="${web.contextserver.domain}" />
         <property name="profileIdCookieName" value="${web.contextserver.profileIdCookieName}"/>