This is an automated email from the ASF dual-hosted git repository. shuber pushed a commit to branch UNOMI-520-add-require-scores in repository https://gitbox.apache.org/repos/asf/unomi.git
commit ef20ee0270d4e3e73d68a3459ee25aa58d4c916e Author: Serge Huber <[email protected]> AuthorDate: Sat Nov 13 09:39:54 2021 +0100 Add possibility to use a "requiresScores" parameter in the ContextRequest. - Implement new ContextRequest parameter - Add integration tests that tests with and without the parameter. - Update documentation to surface the new parameter --- .../java/org/apache/unomi/api/ContextRequest.java | 18 +++++++++ .../java/org/apache/unomi/api/ContextResponse.java | 18 +++++++++ .../test/java/org/apache/unomi/itests/BasicIT.java | 2 +- .../org/apache/unomi/itests/ContextServletIT.java | 44 ++++++++++++++++++++++ itests/src/test/resources/score1.json | 17 +++++++++ itests/src/test/resources/withRequireScores.json | 5 +++ .../src/test/resources/withoutRequireScores.json | 4 ++ manual/src/main/asciidoc/recipes.adoc | 5 ++- manual/src/main/asciidoc/request-examples.adoc | 6 ++- .../unomi/rest/endpoints/ContextJsonEndpoint.java | 3 ++ 10 files changed, 117 insertions(+), 5 deletions(-) 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 78c4720..319afd0 100644 --- a/api/src/main/java/org/apache/unomi/api/ContextRequest.java +++ b/api/src/main/java/org/apache/unomi/api/ContextRequest.java @@ -57,6 +57,7 @@ public class ContextRequest { private boolean requireSegments; private List<String> requiredProfileProperties; private List<String> requiredSessionProperties; + private boolean requireScores; private List<Event> events; private List<PersonalizationService.PersonalizedContent> filters; private List<PersonalizationService.PersonalizationRequest> personalizations; @@ -151,6 +152,23 @@ public class ContextRequest { } /** + * Specifies whether the profiles scores should be part of the ContextResponse. + * @return a boolean indicating if the scores should be part of the response. + */ + public boolean isRequireScores() { + return requireScores; + } + + /** + * Setting this value to true indicates that the profile scores should be included in the response. By default this + * value is false. + * @param requireScores set to true if you want the scores to be part of the context response + */ + public void setRequireScores(boolean requireScores) { + this.requireScores = requireScores; + } + + /** * Retrieves the filters aimed at content personalization that should be evaluated for the given session and/or profile so that the context server can tell the client * whether the content associated with the filter should be activated for this profile/session. The filter identifier is used in the {@link ContextResponse} with the * associated evaluation result. 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 632d1b7..b7467e0 100644 --- a/api/src/main/java/org/apache/unomi/api/ContextResponse.java +++ b/api/src/main/java/org/apache/unomi/api/ContextResponse.java @@ -46,6 +46,8 @@ public class ContextResponse implements Serializable { private Set<String> profileSegments; + private Map<String,Integer> profileScores; + private Map<String, Boolean> filteringResults; private int processedEvents; @@ -153,6 +155,22 @@ public class ContextResponse implements Serializable { } /** + * Retrieve the current scores for the profile if they were requested in the request using the requireScores boolean. + * @return a map that contains the score identifier as the key and the score value as the value + */ + public Map<String, Integer> getProfileScores() { + return profileScores; + } + + /** + * Stores the scores for the current profile if requested using the requireScores boolean in the request. + * @param profileScores a map that contains the score identifier as the key and the score value as the value + */ + public void setProfileScores(Map<String, Integer> profileScores) { + this.profileScores = profileScores; + } + + /** * Retrieves the results of the evaluation content filtering definitions and whether individual definitions match with the associated profile (potentially modified by * overridden values). * diff --git a/itests/src/test/java/org/apache/unomi/itests/BasicIT.java b/itests/src/test/java/org/apache/unomi/itests/BasicIT.java index d7a2387..dd95038 100644 --- a/itests/src/test/java/org/apache/unomi/itests/BasicIT.java +++ b/itests/src/test/java/org/apache/unomi/itests/BasicIT.java @@ -59,7 +59,7 @@ import java.util.*; public class BasicIT extends BaseIT { private final static Logger LOGGER = LoggerFactory.getLogger(BasicIT.class); - private ObjectMapper objectMapper = new ObjectMapper(); + private final ObjectMapper objectMapper = new ObjectMapper(); private static final String SESSION_ID_0 = "aa3b04bd-8f4d-4a07-8e96-d33ffa04d3d0"; private static final String SESSION_ID_1 = "aa3b04bd-8f4d-4a07-8e96-d33ffa04d3d1"; diff --git a/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java b/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java index 4ebcfad..c3e2b3d 100644 --- a/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java +++ b/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java @@ -23,11 +23,14 @@ import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.unomi.api.*; import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.api.segments.Scoring; +import org.apache.unomi.api.segments.ScoringElement; import org.apache.unomi.api.segments.Segment; import org.apache.unomi.api.services.DefinitionsService; import org.apache.unomi.api.services.EventService; import org.apache.unomi.api.services.ProfileService; import org.apache.unomi.api.services.SegmentService; +import org.apache.unomi.persistence.spi.CustomObjectMapper; import org.apache.unomi.persistence.spi.PersistenceService; import org.junit.After; import org.junit.Before; @@ -555,4 +558,45 @@ public class ContextServletIT extends BaseIT { Thread.sleep(2000); //Making sure event is updated in DB } + + @Test + public void testRequireScoring() throws IOException, InterruptedException { + + Map<String,String> parameters = new HashMap<>(); + String scoringSource = getValidatedBundleJSON("score1.json", parameters); + Scoring scoring = CustomObjectMapper.getObjectMapper().readValue(scoringSource, Scoring.class); + segmentService.setScoringDefinition(scoring); + refreshPersistence(); + + // first let's make sure everything works without the requireScoring parameter + parameters = new HashMap<>(); + HttpPost request = new HttpPost(URL + CONTEXT_URL); + request.setEntity(new StringEntity(getValidatedBundleJSON("withoutRequireScores.json", parameters), ContentType.create("application/json"))); + TestUtils.RequestResponse response = TestUtils.executeContextJSONRequest(request); + assertEquals("Invalid response code", 200, response.getStatusCode()); + refreshPersistence(); + Thread.sleep(2000); //Making sure event is updated in DB + + assertNotNull("Context response should not be null", response.getContextResponse()); + Map<String,Integer> scores = response.getContextResponse().getProfileScores(); + assertNull("Context response should not contain scores", scores); + + // now let's test adding it. + parameters = new HashMap<>(); + request = new HttpPost(URL + CONTEXT_URL); + request.setEntity(new StringEntity(getValidatedBundleJSON("withRequireScores.json", parameters), ContentType.create("application/json"))); + response = TestUtils.executeContextJSONRequest(request); + assertEquals("Invalid response code", 200, response.getStatusCode()); + refreshPersistence(); + Thread.sleep(2000); //Making sure event is updated in DB + + assertNotNull("Context response should not be null", response.getContextResponse()); + scores = response.getContextResponse().getProfileScores(); + assertNotNull("Context response should contain scores", scores); + assertNotNull("score1 not found in profile scores", scores.get("score1")); + assertEquals("score1 does not have expected value", 1, scores.get("score1").intValue()); + + segmentService.removeScoringDefinition(scoring.getItemId(), false); + } + } diff --git a/itests/src/test/resources/score1.json b/itests/src/test/resources/score1.json new file mode 100644 index 0000000..a8fd0fc --- /dev/null +++ b/itests/src/test/resources/score1.json @@ -0,0 +1,17 @@ +{ + "itemId" : "score1", + "metadata" : { + "id" : "score1", + "name" : "Score 1", + "enabled" : true + }, + "elements" : [ + { + "condition" : { + "type" : "matchAllCondition", + "parameterValues" : {} + }, + "value" : 1 + } + ] +} \ No newline at end of file diff --git a/itests/src/test/resources/withRequireScores.json b/itests/src/test/resources/withRequireScores.json new file mode 100644 index 0000000..22eac30 --- /dev/null +++ b/itests/src/test/resources/withRequireScores.json @@ -0,0 +1,5 @@ +{ + "requireScores": true, + "profileId": "test-profile-id", + "sessionId": "test-session-id" +} \ No newline at end of file diff --git a/itests/src/test/resources/withoutRequireScores.json b/itests/src/test/resources/withoutRequireScores.json new file mode 100644 index 0000000..67925a1 --- /dev/null +++ b/itests/src/test/resources/withoutRequireScores.json @@ -0,0 +1,4 @@ +{ + "profileId": "test-profile-id", + "sessionId": "test-session-id" +} \ No newline at end of file diff --git a/manual/src/main/asciidoc/recipes.adoc b/manual/src/main/asciidoc/recipes.adoc index f8bf2db..e878bfd 100644 --- a/manual/src/main/asciidoc/recipes.adoc +++ b/manual/src/main/asciidoc/recipes.adoc @@ -23,7 +23,7 @@ Apache Unomi. The simplest way to retrieve profile data for the current profile is to simply send a request to the /cxs/context.json endpoint. However you will need to send a body along with that request. Here's an example: -Here is an example that will retrieve all the session and profile properties. +Here is an example that will retrieve all the session and profile properties, as well as the profile's segments and scores [source] ---- @@ -38,7 +38,8 @@ curl -X POST http://localhost:8181/cxs/context.json?sessionId=1234 \ }, "requiredProfileProperties":["*"], "requiredSessionProperties":["*"], - "requireSegments":true + "requireSegments":true, + "requireScores":true } EOF ---- diff --git a/manual/src/main/asciidoc/request-examples.adoc b/manual/src/main/asciidoc/request-examples.adoc index 33928cf..0480fdf 100644 --- a/manual/src/main/asciidoc/request-examples.adoc +++ b/manual/src/main/asciidoc/request-examples.adoc @@ -41,7 +41,8 @@ By default, in order to optimize the amount of data sent over the network, Apach the profile or session properties. If you need this data, you must send a JSON object to configure the resulting output of the context.js(on) servlet. -Here is an example that will retrieve all the session and profile properties. +Here is an example that will retrieve all the session and profile properties, as well as the profile's segments and +scores [source] ---- @@ -56,7 +57,8 @@ curl -X POST http://localhost:8181/cxs/context.json?sessionId=1234 \ }, "requiredProfileProperties":["*"], "requiredSessionProperties":["*"], - "requireSegments":true + "requireSegments":true, + "requireScores":true } EOF ---- diff --git a/rest/src/main/java/org/apache/unomi/rest/endpoints/ContextJsonEndpoint.java b/rest/src/main/java/org/apache/unomi/rest/endpoints/ContextJsonEndpoint.java index aa5ac98..3184e60 100644 --- a/rest/src/main/java/org/apache/unomi/rest/endpoints/ContextJsonEndpoint.java +++ b/rest/src/main/java/org/apache/unomi/rest/endpoints/ContextJsonEndpoint.java @@ -383,6 +383,9 @@ public class ContextJsonEndpoint { if (contextRequest.isRequireSegments()) { data.setProfileSegments(profile.getSegments()); } + if (contextRequest.isRequireScores()) { + data.setProfileScores(profile.getScores()); + } if (contextRequest.getRequiredProfileProperties() != null) { Map<String, Object> profileProperties = new HashMap<>(profile.getProperties());
