diff --git a/src/docbkx/reference/programming-model/aspectj.xml b/src/docbkx/reference/programming-model/aspectj.xml
index 24680b7ff..786b1c02f 100644
--- a/src/docbkx/reference/programming-model/aspectj.xml
+++ b/src/docbkx/reference/programming-model/aspectj.xml
@@ -35,7 +35,9 @@
Eclipse and STS support AspectJ via the AJDT plugin which can be installed from the update-site:
-
+ http://download.eclipse.org/tools/ajdt/36/update/
+ (or for the latest development snapshot of the plugin
+ http://download.eclipse.org/tools/ajdt/36/dev/update).
The AspectJ support in IntelliJ IDEA lacks some of the features. JetBrains is working to improve the situation
diff --git a/src/docbkx/tutorial/recommendations.xml b/src/docbkx/tutorial/recommendations.xml
index 657331afd..48e4860a6 100644
--- a/src/docbkx/tutorial/recommendations.xml
+++ b/src/docbkx/tutorial/recommendations.xml
@@ -3,25 +3,60 @@
Movies! Friends! Bargains! - Recommendations
- In the last part of this exercise we wanted to add recommendations to the app. One obvious recommendation is movies that our friends liked
- (and their friends too, but with less importance). The second was recommendations for new friends that also liked the movies that we liked most.
-
- Doing this kind of ranking algorithms is really fun with graph databases. They are applied to the graph by traversing it in a certain order, collecting information
- on the go and deciding which paths to follow and what to include in the results.
-
- Lets say I'm only interested in the top 10 recommendations each.
-
- 5) return EXCLUDE_AND_STOP;
- Relationship rating = path.lastRelationship();
- if (rating.getType().equals(RATED)) {
- rating.getProperty()
- return INCLUDE_AND_STOP;
- }
- return INCLUDE_AND_CONTINUE;
- })
-]]>
+ In the last part of this exercise we wanted to add recommendations to the app. One obvious recommendation is
+ movies that our friends liked
+ (and their friends too, but with less importance). The second was recommendations for new friends that also
+ liked the movies that we liked most.
+
+
+ Doing this kind of ranking algorithms is really fun with graph databases. They are applied to the graph by
+ traversing it in a certain order, collecting information on the go and deciding which paths to follow and what
+ to include in the results.
+
+
+ Lets say we're only interested in the recommendations of a certain degree of friends.
+
+
+ recommendMovies(User user, final int ratingDistance) {
+ final DynamicRelationshipType RATED = withName(User.RATED);
+ final Map ratings=new HashMap();
+ TraversalDescription traversal= Traversal.description().breadthFirst()
+ .relationships(withName(User.FRIEND)).relationships(RATED, OUTGOING).evaluator(new Evaluator() {
+
+ public Evaluation evaluate(Path path) {
+ final int length = path.length() - 1;
+ if (length > ratingDistance) return Evaluation.EXCLUDE_AND_PRUNE; // only as far as requested
+ Relationship rating = path.lastRelationship();
+ if (rating != null && rating.getType().equals(RATED)) { // process RATED relationships, not FRIEND
+ if (length == 0) return Evaluation.EXCLUDE_AND_PRUNE; // my rated movies
+ final long movieId = rating.getEndNode().getId();
+ int[] stars = ratings.get(movieId);
+ if (stars == null) {
+ stars = new int[2];
+ ratings.put(movieId, stars);
+ }
+ int weight = ratingDistance - length; // aggregate for averaging, inverse to distance
+ stars[0] += weight * (Integer) rating.getProperty("stars", 0);
+ stars[1] += weight;
+ return Evaluation.INCLUDE_AND_PRUNE;
+ }
+ return Evaluation.EXCLUDE_AND_CONTINUE;
+ }
+ });
+
+ Map result=new HashMap();
+ final Iterable movies = movieRepository.findAllByTraversal(user, traversal); // lazy traversal results
+ for (Movie movie : movies) { // assign movie to averaged rating
+ final int[] stars = ratings.get(movie.getNodeId());
+ result.put(movie, stars[0]/stars[1]);
+ }
+ return result;
+}
+ ]]>
+
+
+ The UserController just calls this method, adds it's results to the the model and the view renders the
+ recommendation alongside with your own ratings.