Skip to content

Instantly share code, notes, and snippets.

@MarneeDear
Forked from RaulEstrada/socialNetworking.adoc
Last active August 29, 2015 14:07
Show Gist options
  • Save MarneeDear/04a858d8ff42f01b2e8c to your computer and use it in GitHub Desktop.
Save MarneeDear/04a858d8ff42f01b2e8c to your computer and use it in GitHub Desktop.

Revisions

  1. @RaulEstrada RaulEstrada revised this gist Jan 28, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -341,7 +341,7 @@ RETURN str(m.title + ' (' + m.genre + ')') AS Movie, rating, views LIMIT 3;

    '''

    ==== See how much time people we follow have spend watching a movie
    ==== See how much time people we follow have spend watching movies

    Last, but not least, we'll write a query that calculates the total amount of minutes people we follow have spend watching movies (let's suppose they watched those movies once)

  2. @RaulEstrada RaulEstrada revised this gist Jan 28, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -358,6 +358,6 @@ ORDER BY Total_minutes DESC;

    //table

    ===== *Note* : The OPTIONAL MATCH clause is used because otherwise, if the user we follow hasn't watched any movie, that user will not appear in the result. This way, if the user has watched a movie, he/she will appear anyway and the total amount of time will be 0.
    ===== *Note* : The OPTIONAL MATCH clause is used because otherwise, if the user we follow hasn't watched any movie, that user will not appear in the result. This way, if the user hasn't watched any movie, he/she will appear anyway and the total amount of time will be 0.

    That's the reason why in this query 'we' are Amy and not Bradley, since all the people Bradley follows have watched some movie.
  3. @RaulEstrada RaulEstrada revised this gist Jan 28, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    = An small social networking website +
    = A small social networking website +

    This database is a small example of a networking site where users can watch movies, subscribe to TV shows
    and comment and rate any of the previous media. Users may follow or block other users, just like any other networking
  4. @RaulEstrada RaulEstrada revised this gist Jan 28, 2014. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -255,7 +255,8 @@ Sometimes we are suggested to follow someone because that user and I follow the
    [source, cypher]
    ----
    MATCH (me:User)-[:FOLLOWS]->(common:User)<-[:FOLLOWS]-(stranger:User)
    WHERE NOT (me)-[:BLOCKED]->(stranger) AND me.name = 'Bradley' AND me.surname = 'Green'
    WHERE NOT (me)-[:BLOCKED]->(stranger) AND me.name = 'Bradley' AND me.surname = 'Green' AND
    NOT (me)-[:FOLLOWS]->(stranger)
    RETURN str(stranger.name + ' ' + stranger.surname) AS User, COLLECT(str(common.name + ' ' + common.surname)) AS Common_Friends, COUNT(*) AS Occurrences ORDER BY Occurrences DESC;
    ----

  5. @RaulEstrada RaulEstrada revised this gist Jan 28, 2014. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -123,6 +123,7 @@ CREATE
    (lisa)-[:COMMENTED {date:'2013-09-27', comment:'They tried to cover too much and reach to too many people. This movie is really overrated'}]->(wreckitralph),
    (lisa)-[:COMMENTED {date:'2013-12-05', comment:'It was entertaining in the beginning, but it was repetitive in the end'}]->(fringe),
    (annie)-[:COMMENTED {date:'2013-12-19', comment:'Mostly boring and way overrated'}]->(thehours),
    (annie)-[:COMMENTED {date:'2013-12-12', comment:'Impressive. That is all I have to say'}]->(toystory),
    (ripley)-[:COMMENTED {date:'2013-06-14', comment:'I was reluctant to see this movie because I usually hate Julia Roberts crappy romantic comedies, but I was very surprised by this movie. I think it is the best performance Roberts has made ever and the story is just incredible. It was awesome'}]->(erinbrockovich),
    (john)-[:COMMENTED {date:'2013-08-18', comment:'I liked this one. I was amused and entertained through the whole movie and that is enough for me. And the special effects are great.'}]->(avengers),
    //RATED
    @@ -212,10 +213,12 @@ In this example, we list all the comments posted about a given movie (Toy Story
    MATCH (movie:Movie {title:'Toy Story 3'})<-[c:COMMENTED]-(author:User)
    WITH c, author
    MATCH (me:User{name:'Bradley', surname:'Green'})-[:FOLLOWS]->(other:User)
    WITH c, author, collect(other) as Friends
    WITH c, author, collect(other) as Friends, me
    RETURN c.comment AS Comment, str(author.name + ' ' + author.surname) AS Author, c.date AS Date,
    CASE WHEN (author) in Friends
    THEN str('Following the author')
    WHEN (author) = (me)
    THEN str('me')
    ELSE str('Not following the author') END AS Following
    ORDER BY Date DESC;
    ----
  6. @RaulEstrada RaulEstrada revised this gist Jan 28, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -160,7 +160,7 @@ at least one movie, subscribed to some TV show or both.

    ==== Which are the active users that live in the same city as I do?

    This query looks for active users that live in the same city as I do and they are ordered by their activity level, that is, the total number of movies watched and TV Shows subscribed to.
    This query looks for active users that live in the same city as I do. It also displays their activity level, that is, the total number of movies watched and TV Shows subscribed to.

    [source, cypher]
    ----
  7. @RaulEstrada RaulEstrada revised this gist Jan 28, 2014. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -23,10 +23,10 @@ rating, subscribing to or commenting. The following diagram is a tiny sample of
    image::http://i.imgur.com/XBotTMJ.png[Model]

    The following are links to other diagrams that can also help understand the model:
    http://i.imgur.com/9Y9z79Z[users diagram],
    http://i.imgur.com/9Y9z79Z.png[users diagram],
    http://i.imgur.com/UddC0Ca.png[watched and subscribed diagram],
    http://i.imgur.com/pRnbOQW[rated diagram],
    http://i.imgur.com/emK8tIU[commented diagram]
    http://i.imgur.com/pRnbOQW.png[rated diagram],
    http://i.imgur.com/emK8tIU.png[commented diagram]
    and
    http://i.imgur.com/zwAPJtj.jpg[complete diagram].

  8. @RaulEstrada RaulEstrada revised this gist Jan 28, 2014. 1 changed file with 236 additions and 2 deletions.
    238 changes: 236 additions & 2 deletions socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -9,7 +9,6 @@ website nowadays.
    The theme was chosen because of the success these type of webs have all over the world, and because in general their
    structure can easily and naturally be displayed as a graph with very different types of relationships and very connected data. So, in a nutshell,
    they are a very good environment to start working with graph databases.



    //console
    @@ -122,4 +121,239 @@ CREATE
    (matthew)-[:COMMENTED {date:'2013-12-03', comment:'Deeply moving. Great performances too!'}]->(thehours),
    (lisa)-[:COMMENTED {date:'2013-05-08', comment:'The cast was great. They really did a great job choosing the girl who played Olive'}]->(misssunshine),
    (lisa)-[:COMMENTED {date:'2013-09-27', comment:'They tried to cover too much and reach to too many people. This movie is really overrated'}]->(wreckitralph),
    (lisa)-[:COMMENTED {date:'2013-12-05', comment:'It was entertaining in the beginning, but it was repetitive in the e
    (lisa)-[:COMMENTED {date:'2013-12-05', comment:'It was entertaining in the beginning, but it was repetitive in the end'}]->(fringe),
    (annie)-[:COMMENTED {date:'2013-12-19', comment:'Mostly boring and way overrated'}]->(thehours),
    (ripley)-[:COMMENTED {date:'2013-06-14', comment:'I was reluctant to see this movie because I usually hate Julia Roberts crappy romantic comedies, but I was very surprised by this movie. I think it is the best performance Roberts has made ever and the story is just incredible. It was awesome'}]->(erinbrockovich),
    (john)-[:COMMENTED {date:'2013-08-18', comment:'I liked this one. I was amused and entertained through the whole movie and that is enough for me. And the special effects are great.'}]->(avengers),
    //RATED
    (bradley)-[:RATED {date:'2013-12-05', score:10}]->(toystory),
    (bradley)-[:RATED {date:'2013-12-01', score:9}]->(wreckitralph),
    (matthew)-[:RATED {date:'2013-11-20', score:10}]->(toystory),
    (matthew)-[:RATED {date:'2013-11-25', score:9}]->(misssunshine),
    (lisa)-[:RATED {date:'2013-11-29', score:9}]->(friends),
    (lisa)-[:RATED {date:'2013-09-27', score:6}]->(wreckitralph),
    (lisa)-[:RATED {date:'2013-11-29', score:8}]->(toystory),
    (annie)-[:RATED {date:'2013-12-10', score:9}]->(misssunshine),
    (annie)-[:RATED {date:'2013-12-10', score:8}]->(friends),
    (annie)-[:RATED {date:'2013-12-12', score:8}]->(toystory),
    (ripley)-[:RATED {date:'2013-06-14', score:9}]->(erinbrockovich),
    (john)-[:RATED {date:'2013-10-18', score:8}]->(office),
    (john)-[:RATED {date:'2013-08-18', score:8}]->(avengers)
    ----

    The following is the graph representing users, media and the connection between all of them.

    //graph

    '''
    '''

    == Queries

    ===== Note:

    From now on, in these queries and examples "we" will be the user 'Bradley Green'. Furthermore, an active user is a given user that has watched
    at least one movie, subscribed to some TV show or both.




    ==== Which are the active users that live in the same city as I do?

    This query looks for active users that live in the same city as I do and they are ordered by their activity level, that is, the total number of movies watched and TV Shows subscribed to.

    [source, cypher]
    ----
    MATCH (me:User {name:'Bradley', surname:'Green'}), (other:User)-[:WATCHED|:SUBSCRIBED]->(media:Media)
    WHERE other.city = me.city AND other<>me
    RETURN str(other.surname + ", " + other.name) as Other_User, other.city as City, count(other) as Activity_Level ORDER BY Other_User ASC;
    ----

    //table

    '''

    ==== Which are the users I have blocked?

    In any social networking site there exists the possibility of blocking other users in order not to be contacted by those users
    and not to receive news from them.

    http://i.imgur.com/7Tavsid.png[Figure 1. Example of blocking in Tumblr and Twitter]

    Since users have such operation available, they should be able to see
    who they have blocked.

    In this example, we list those users that we (remember, we are Bradley Green), have blocked and the reason why we blocked them. If there is no reason, 'No reason known' will appear instead.

    [source, cypher]
    ----
    MATCH (me:User {name:'Bradley', surname:'Green'})-[b:BLOCKED]->(other:User)
    RETURN str(other.name + ' ' + other.surname) AS Blocked,
    CASE WHEN HAS(b.reason)
    THEN b.reason
    ELSE 'No reason known' END AS Reason;
    ----

    //table

    '''

    ==== List all the reviews of a given movie

    It's very common in webs with media content like movies or tv shows such as IMDB, Rotten Tomatoes, FilmAffinity, SeriesLy and whatnot to
    allow users to list and view the comments and opinions other users have posted about a given item.

    http://i.imgur.com/WNDJyZ9.png[Figure 2. Example of reviews posted of a given movie in IMDB and Rotten Tomatoes]

    In this example, we list all the comments posted about a given movie (Toy Story 3), ordered by the date they were posted.

    [source, cypher]
    ----
    MATCH (movie:Movie {title:'Toy Story 3'})<-[c:COMMENTED]-(author:User)
    WITH c, author
    MATCH (me:User{name:'Bradley', surname:'Green'})-[:FOLLOWS]->(other:User)
    WITH c, author, collect(other) as Friends
    RETURN c.comment AS Comment, str(author.name + ' ' + author.surname) AS Author, c.date AS Date,
    CASE WHEN (author) in Friends
    THEN str('Following the author')
    ELSE str('Not following the author') END AS Following
    ORDER BY Date DESC;
    ----

    //table

    '''

    ==== Users that have watched this movie have also watched...

    http://i.imgur.com/xjPlMVb.png[Figure 3. Example of recommendations in FNAC and IMDB]

    Another usual thing to run into not only in these kind of websites, but also in ecommerces is a list of other items
    visited/liked/bought by users that have also visited the item we're currently seeing.

    In this example we are in the movie 'Toy Story 3' and we list those movies users that watched 'Toy Story 3' also watched. These recommendations are ordered by how many times those movies appear as recommended.

    [source, cypher]
    ----
    MATCH (target:Movie)<-[:WATCHED]-(u:User)-[:WATCHED]->(p:Movie)
    WHERE p.title = 'Toy Story 3'
    WITH str(target.title + ' (' + target.genre + ')') AS Suggestion, count(target.title) as Occurrences
    RETURN distinct Suggestion, Occurrences ORDER BY Occurrences DESC, Suggestion ASC;
    ----

    //table

    '''

    ==== Users that follow someone I follow too

    Sometimes we are suggested to follow someone because that user and I follow the same people. In this example we show which users we are recommended to follow and which are our common 'links' (people we follow)

    [source, cypher]
    ----
    MATCH (me:User)-[:FOLLOWS]->(common:User)<-[:FOLLOWS]-(stranger:User)
    WHERE NOT (me)-[:BLOCKED]->(stranger) AND me.name = 'Bradley' AND me.surname = 'Green'
    RETURN str(stranger.name + ' ' + stranger.surname) AS User, COLLECT(str(common.name + ' ' + common.surname)) AS Common_Friends, COUNT(*) AS Occurrences ORDER BY Occurrences DESC;
    ----

    //table

    '''

    ==== List the rates of people I follow.

    In websites with media content (movies, tv shows, music, ...), if we follow someone is because we may be interested in knowing which items that user liked or recommended. There are webs like Filmaffinity or IMDB that allow you to list the rates people you follow have given to media items.

    In this example that's what we'll do.

    [source, cypher]
    ----
    MATCH (me:User)-[:FOLLOWS]->(friend:User)-[r:RATED]->(media:Media)
    WHERE me.name = 'Bradley' AND me.surname = 'Green'
    RETURN r.score as SCORE, friend.name as FRIEND, media.title as TITLE
    ORDER BY SCORE;
    ----

    //table

    '''

    ==== Display those users that have watched movies from all the different genres but not subscribed to a TV Show

    This query or example, even though it could be a feature of a given social website, it's more of a query that allows us to play a little bit with the graph. The purpose is to find users that have watched at least a movie from every genre, but are not subscribed to a TV Show

    [source, cypher]
    ----
    MATCH (movie:Movie)
    WITH COLLECT(DISTINCT movie.genre) AS genres
    MATCH (user:User)-[:WATCHED]->(movie:Movie)
    WITH user, genres, COLLECT(DISTINCT movie.genre) AS watched
    WHERE ALL(x IN genres WHERE x IN watched) AND NOT (user)-[:SUBSCRIBED]->(:TV_Show)
    RETURN str(user.name + ' ' + user.surname) AS User;
    ----

    //table

    '''

    ==== Ready to mingle

    Sometimes in networking websites we want to list our friends, or friends of friends, or even friends of friends of friends. In this example that's exactly what we'll do, and we'll display the relationship between us. (Remember: We are Bradley Green)

    [source, cypher]
    ----
    MATCH (me:User{name:'Bradley', surname:'Green'})-[p:FOLLOWS*1..3]->(other:User)
    WHERE NOT (me)-[:BLOCKED]->(other) AND me<>other
    RETURN DISTINCT str(other.name + ' ' + other.surname) AS User,
    CASE WHEN LENGTH(shortestPath((me)-[:FOLLOWS*]->(other))) = 1 THEN
    str('Friend')
    WHEN LENGTH(shortestPath((me)-[:FOLLOWS*]->(other))) = 2 THEN
    str('Friend of friend')
    ELSE
    str('Friend of friend of friend') END AS Relation;
    ----

    //table

    '''

    ==== Top 3 favourites since July 2013

    Another feature of almost any website is the Top 10, Top 3 and whatnot. In our example, we'll show the Top 3 movies since July 2013. The criteria to be 'higher' in this 'scale' is to have higher ratings, and if two movies have the same rating, it's higher the one with more views by the users.

    [source, cypher]
    ----
    MATCH ()-[r:RATED]->(m:Movie)
    WHERE r.date >= '2013-07-01'
    WITH m, AVG(r.score) AS rating
    MATCH path=()-[w:WATCHED]->(m)
    WHERE w.date >= '2013-07-01'
    WITH m, rating, count(path) as views
    ORDER BY rating DESC, views DESC
    RETURN str(m.title + ' (' + m.genre + ')') AS Movie, rating, views LIMIT 3;
    ----

    //table

    '''

    ==== See how much time people we follow have spend watching a movie

    Last, but not least, we'll write a query that calculates the total amount of minutes people we follow have spend watching movies (let's suppose they watched those movies once)

    [source, cypher]
    ----
    MATCH (me:User{name:'Amy'})-[:FOLLOWS]->(other:User)
    WITH other
    OPTIONAL MATCH (other)-[:WATCHED]->(movie:Movie)
    WITH other, COLLECT(movie) AS watched
    RETURN str(other.name + ' ' + other.surname) AS User,
    reduce(time = 0, mov IN watched | time + mov.runtime_min) AS Total_minutes
    ORDER BY Total_minutes DESC;
    ----

    //table

    ===== *Note* : The OPTIONAL MATCH clause is used because otherwise, if the user we follow hasn't watched any movie, that user will not appear in the result. This way, if the user has watched a movie, he/she will appear anyway and the total amount of time will be 0.

    That's the reason why in this query 'we' are Amy and not Bradley, since all the people Bradley follows have watched some movie.
  9. @RaulEstrada RaulEstrada revised this gist Jan 28, 2014. 1 changed file with 2 additions and 239 deletions.
    241 changes: 2 additions & 239 deletions socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -9,9 +9,7 @@ website nowadays.
    The theme was chosen because of the success these type of webs have all over the world, and because in general their
    structure can easily and naturally be displayed as a graph with very different types of relationships and very connected data. So, in a nutshell,
    they are a very good environment to start working with graph databases.

    == Table of Contents
    :toc: right



    //console
    @@ -124,239 +122,4 @@ CREATE
    (matthew)-[:COMMENTED {date:'2013-12-03', comment:'Deeply moving. Great performances too!'}]->(thehours),
    (lisa)-[:COMMENTED {date:'2013-05-08', comment:'The cast was great. They really did a great job choosing the girl who played Olive'}]->(misssunshine),
    (lisa)-[:COMMENTED {date:'2013-09-27', comment:'They tried to cover too much and reach to too many people. This movie is really overrated'}]->(wreckitralph),
    (lisa)-[:COMMENTED {date:'2013-12-05', comment:'It was entertaining in the beginning, but it was repetitive in the end'}]->(fringe),
    (annie)-[:COMMENTED {date:'2013-12-19', comment:'Mostly boring and way overrated'}]->(thehours),
    (ripley)-[:COMMENTED {date:'2013-06-14', comment:'I was reluctant to see this movie because I usually hate Julia Roberts crappy romantic comedies, but I was very surprised by this movie. I think it is the best performance Roberts has made ever and the story is just incredible. It was awesome'}]->(erinbrockovich),
    (john)-[:COMMENTED {date:'2013-08-18', comment:'I liked this one. I was amused and entertained through the whole movie and that is enough for me. And the special effects are great.'}]->(avengers),
    //RATED
    (bradley)-[:RATED {date:'2013-12-05', score:10}]->(toystory),
    (bradley)-[:RATED {date:'2013-12-01', score:9}]->(wreckitralph),
    (matthew)-[:RATED {date:'2013-11-20', score:10}]->(toystory),
    (matthew)-[:RATED {date:'2013-11-25', score:9}]->(misssunshine),
    (lisa)-[:RATED {date:'2013-11-29', score:9}]->(friends),
    (lisa)-[:RATED {date:'2013-09-27', score:6}]->(wreckitralph),
    (lisa)-[:RATED {date:'2013-11-29', score:8}]->(toystory),
    (annie)-[:RATED {date:'2013-12-10', score:9}]->(misssunshine),
    (annie)-[:RATED {date:'2013-12-10', score:8}]->(friends),
    (annie)-[:RATED {date:'2013-12-12', score:8}]->(toystory),
    (ripley)-[:RATED {date:'2013-06-14', score:9}]->(erinbrockovich),
    (john)-[:RATED {date:'2013-10-18', score:8}]->(office),
    (john)-[:RATED {date:'2013-08-18', score:8}]->(avengers)
    ----

    The following is the graph representing users, media and the connection between all of them.

    //graph

    '''
    '''

    == Queries

    ===== Note:

    From now on, in these queries and examples "we" will be the user 'Bradley Green'. Furthermore, an active user is a given user that has watched
    at least one movie, subscribed to some TV show or both.




    ==== Which are the active users that live in the same city as I do?

    This query looks for active users that live in the same city as I do and they are ordered by their activity level, that is, the total number of movies watched and TV Shows subscribed to.

    [source, cypher]
    ----
    MATCH (me:User {name:'Bradley', surname:'Green'}), (other:User)-[:WATCHED|:SUBSCRIBED]->(media:Media)
    WHERE other.city = me.city AND other<>me
    RETURN str(other.surname + ", " + other.name) as Other_User, other.city as City, count(other) as Activity_Level ORDER BY Other_User ASC;
    ----

    //table

    '''

    ==== Which are the users I have blocked?

    In any social networking site there exists the possibility of blocking other users in order not to be contacted by those users
    and not to receive news from them.

    http://i.imgur.com/7Tavsid.png[Figure 1. Example of blocking in Tumblr and Twitter]

    Since users have such operation available, they should be able to see
    who they have blocked.

    In this example, we list those users that we (remember, we are Bradley Green), have blocked and the reason why we blocked them. If there is no reason, 'No reason known' will appear instead.

    [source, cypher]
    ----
    MATCH (me:User {name:'Bradley', surname:'Green'})-[b:BLOCKED]->(other:User)
    RETURN str(other.name + ' ' + other.surname) AS Blocked,
    CASE WHEN HAS(b.reason)
    THEN b.reason
    ELSE 'No reason known' END AS Reason;
    ----

    //table

    '''

    ==== List all the reviews of a given movie

    It's very common in webs with media content like movies or tv shows such as IMDB, Rotten Tomatoes, FilmAffinity, SeriesLy and whatnot to
    allow users to list and view the comments and opinions other users have posted about a given item.

    http://i.imgur.com/WNDJyZ9.png[Figure 2. Example of reviews posted of a given movie in IMDB and Rotten Tomatoes]

    In this example, we list all the comments posted about a given movie (Toy Story 3), ordered by the date they were posted.

    [source, cypher]
    ----
    MATCH (movie:Movie {title:'Toy Story 3'})<-[c:COMMENTED]-(author:User)
    WITH c, author
    MATCH (me:User{name:'Bradley', surname:'Green'})-[:FOLLOWS]->(other:User)
    WITH c, author, collect(other) as Friends
    RETURN c.comment AS Comment, str(author.name + ' ' + author.surname) AS Author, c.date AS Date,
    CASE WHEN (author) in Friends
    THEN str('Following the author')
    ELSE str('Not following the author') END AS Following
    ORDER BY Date DESC;
    ----

    //table

    '''

    ==== Users that have watched this movie have also watched...

    http://i.imgur.com/xjPlMVb.png[Figure 3. Example of recommendations in FNAC and IMDB]

    Another usual thing to run into not only in these kind of websites, but also in ecommerces is a list of other items
    visited/liked/bought by users that have also visited the item we're currently seeing.

    In this example we are in the movie 'Toy Story 3' and we list those movies users that watched 'Toy Story 3' also watched. These recommendations are ordered by how many times those movies appear as recommended.

    [source, cypher]
    ----
    MATCH (target:Movie)<-[:WATCHED]-(u:User)-[:WATCHED]->(p:Movie)
    WHERE p.title = 'Toy Story 3'
    WITH str(target.title + ' (' + target.genre + ')') AS Suggestion, count(target.title) as Occurrences
    RETURN distinct Suggestion, Occurrences ORDER BY Occurrences DESC, Suggestion ASC;
    ----

    //table

    '''

    ==== Users that follow someone I follow too

    Sometimes we are suggested to follow someone because that user and I follow the same people. In this example we show which users we are recommended to follow and which are our common 'links' (people we follow)

    [source, cypher]
    ----
    MATCH (me:User)-[:FOLLOWS]->(common:User)<-[:FOLLOWS]-(stranger:User)
    WHERE NOT (me)-[:BLOCKED]->(stranger) AND me.name = 'Bradley' AND me.surname = 'Green'
    RETURN str(stranger.name + ' ' + stranger.surname) AS User, COLLECT(str(common.name + ' ' + common.surname)) AS Common_Friends, COUNT(*) AS Occurrences ORDER BY Occurrences DESC;
    ----

    //table

    '''

    ==== List the rates of people I follow.

    In websites with media content (movies, tv shows, music, ...), if we follow someone is because we may be interested in knowing which items that user liked or recommended. There are webs like Filmaffinity or IMDB that allow you to list the rates people you follow have given to media items.

    In this example that's what we'll do.

    [source, cypher]
    ----
    MATCH (me:User)-[:FOLLOWS]->(friend:User)-[r:RATED]->(media:Media)
    WHERE me.name = 'Bradley' AND me.surname = 'Green'
    RETURN r.score as SCORE, friend.name as FRIEND, media.title as TITLE
    ORDER BY SCORE;
    ----

    //table

    '''

    ==== Display those users that have watched movies from all the different genres but not subscribed to a TV Show

    This query or example, even though it could be a feature of a given social website, it's more of a query that allows us to play a little bit with the graph. The purpose is to find users that have watched at least a movie from every genre, but are not subscribed to a TV Show

    [source, cypher]
    ----
    MATCH (movie:Movie)
    WITH COLLECT(DISTINCT movie.genre) AS genres
    MATCH (user:User)-[:WATCHED]->(movie:Movie)
    WITH user, genres, COLLECT(DISTINCT movie.genre) AS watched
    WHERE ALL(x IN genres WHERE x IN watched) AND NOT (user)-[:SUBSCRIBED]->(:TV_Show)
    RETURN str(user.name + ' ' + user.surname) AS User;
    ----

    //table

    '''

    ==== Ready to mingle

    Sometimes in networking websites we want to list our friends, or friends of friends, or even friends of friends of friends. In this example that's exactly what we'll do, and we'll display the relationship between us. (Remember: We are Bradley Green)

    [source, cypher]
    ----
    MATCH (me:User{name:'Bradley', surname:'Green'})-[p:FOLLOWS*1..3]->(other:User)
    WHERE NOT (me)-[:BLOCKED]->(other) AND me<>other
    RETURN DISTINCT str(other.name + ' ' + other.surname) AS User,
    CASE WHEN LENGTH(shortestPath((me)-[:FOLLOWS*]->(other))) = 1 THEN
    str('Friend')
    WHEN LENGTH(shortestPath((me)-[:FOLLOWS*]->(other))) = 2 THEN
    str('Friend of friend')
    ELSE
    str('Friend of friend of friend') END AS Relation;
    ----

    //table

    '''

    ==== Top 3 favourites since July 2013

    Another feature of almost any website is the Top 10, Top 3 and whatnot. In our example, we'll show the Top 3 movies since July 2013. The criteria to be 'higher' in this 'scale' is to have higher ratings, and if two movies have the same rating, it's higher the one with more views by the users.

    [source, cypher]
    ----
    MATCH ()-[r:RATED]->(m:Movie)
    WHERE r.date >= '2013-07-01'
    WITH m, AVG(r.score) AS rating
    MATCH path=()-[w:WATCHED]->(m)
    WHERE w.date >= '2013-07-01'
    WITH m, rating, count(path) as views
    ORDER BY rating DESC, views DESC
    RETURN str(m.title + ' (' + m.genre + ')') AS Movie, rating, views LIMIT 3;
    ----

    //table

    '''

    ==== See how much time people we follow have spend watching a movie

    Last, but not least, we'll write a query that calculates the total amount of minutes people we follow have spend watching movies (let's suppose they watched those movies once)

    [source, cypher]
    ----
    MATCH (me:User{name:'Amy'})-[:FOLLOWS]->(other:User)
    WITH other
    OPTIONAL MATCH (other)-[:WATCHED]->(movie:Movie)
    WITH other, COLLECT(movie) AS watched
    RETURN str(other.name + ' ' + other.surname) AS User,
    reduce(time = 0, mov IN watched | time + mov.runtime_min) AS Total_minutes
    ORDER BY Total_minutes DESC;
    ----

    //table

    ===== *Note* : The OPTIONAL MATCH clause is used because otherwise, if the user we follow hasn't watched any movie, that user will not appear in the result. This way, if the user has watched a movie, he/she will appear anyway and the total amount of time will be 0.

    That's the reason why in this query 'we' are Amy and not Bradley, since all the people Bradley follows have watched some movie.
    (lisa)-[:COMMENTED {date:'2013-12-05', comment:'It was entertaining in the beginning, but it was repetitive in the e
  10. @RaulEstrada RaulEstrada revised this gist Jan 28, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -11,7 +11,7 @@ structure can easily and naturally be displayed as a graph with very different t
    they are a very good environment to start working with graph databases.

    == Table of Contents
    :toc:
    :toc: right


    //console
  11. @RaulEstrada RaulEstrada revised this gist Jan 28, 2014. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -10,8 +10,7 @@ The theme was chosen because of the success these type of webs have all over the
    structure can easily and naturally be displayed as a graph with very different types of relationships and very connected data. So, in a nutshell,
    they are a very good environment to start working with graph databases.

    = Table of Contents

    == Table of Contents
    :toc:


  12. @RaulEstrada RaulEstrada revised this gist Jan 28, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -10,7 +10,7 @@ The theme was chosen because of the success these type of webs have all over the
    structure can easily and naturally be displayed as a graph with very different types of relationships and very connected data. So, in a nutshell,
    they are a very good environment to start working with graph databases.

    == Table of Contents
    = Table of Contents

    :toc:

  13. @RaulEstrada RaulEstrada revised this gist Jan 28, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -24,7 +24,7 @@ structure can easily and naturally be displayed as a graph with very different t
    As explained before, the networking site has users with relationships between them (they can follow or block each other), and media items users may interact with by watching,
    rating, subscribing to or commenting. The following diagram is a tiny sample of the database that will hopefully help you see how data is structured and interconnected.

    image::http://i.imgur.com/XBotTMJ[Model]
    image::http://i.imgur.com/XBotTMJ.png[Model]

    The following are links to other diagrams that can also help understand the model:
    http://i.imgur.com/9Y9z79Z[users diagram],
  14. @RaulEstrada RaulEstrada revised this gist Jan 28, 2014. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -10,9 +10,9 @@ The theme was chosen because of the success these type of webs have all over the
    structure can easily and naturally be displayed as a graph with very different types of relationships and very connected data. So, in a nutshell,
    they are a very good environment to start working with graph databases.

    == Table of Contents
    == Table of Contents

    :toc:
    :toc:


    //console
  15. @RaulEstrada RaulEstrada revised this gist Jan 28, 2014. 1 changed file with 45 additions and 23 deletions.
    68 changes: 45 additions & 23 deletions socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    = An mini social networking website +
    = An small social networking website +

    This database is a small example of a networking site where users can watch movies, subscribe to TV shows
    and comment and rate any of the previous media. Users may follow or block other users, just like any other networking
    @@ -8,12 +8,32 @@ website nowadays.
    The theme was chosen because of the success these type of webs have all over the world, and because in general their
    structure can easily and naturally be displayed as a graph with very different types of relationships and very connected data. So, in a nutshell,
    they can be seen as a very good environment to start working with graph databases.
    they are a very good environment to start working with graph databases.

    == Table of Contents

    :toc:


    //console

    '''

    == Model

    As explained before, the networking site has users with relationships between them (they can follow or block each other), and media items users may interact with by watching,
    rating, subscribing to or commenting. The following diagram is a tiny sample of the database that will hopefully help you see how data is structured and interconnected.

    image::http://i.imgur.com/XBotTMJ[Model]

    The following are links to other diagrams that can also help understand the model:
    http://i.imgur.com/9Y9z79Z[users diagram],
    http://i.imgur.com/UddC0Ca.png[watched and subscribed diagram],
    http://i.imgur.com/pRnbOQW[rated diagram],
    http://i.imgur.com/emK8tIU[commented diagram]
    and
    http://i.imgur.com/zwAPJtj.jpg[complete diagram].

    == Creating the database

    The following is the script used to create all the nodes of the database and the relationships between them.
    @@ -99,16 +119,16 @@ CREATE
    (ripley)-[:SUBSCRIBED]->(office),
    (dennis)-[:SUBSCRIBED]->(office),
    //COMMENTED
    (bradley)-[:COMMENTED {date:'2013-12-05', comment:'Deftly blending comedy, adventure, and honest emotion, Toy Story 3 is a rare second sequel that really works.'}]->(toystory),
    (matthew)-[:COMMENTED {date:'2013-10-11', comment:'Equally entertaining for both kids and parents old enough to catch the references, Wreck-It Ralph is a clever, colorful adventure built on familiar themes and joyful nostalgia.'}]->(wreckitralph),
    (matthew)-[:COMMENTED {date:'2013-11-20', comment:'Even with the bar raised high, Toy Story 3 enchanted and moved me so deeply I was flabbergasted that a digitally animated comedy about plastic playthings could have this effect.'}]->(toystory),
    (matthew)-[:COMMENTED {date:'2013-12-03', comment:'Deeply moving'}]->(thehours),
    (lisa)-[:COMMENTED {date:'2013-05-08', comment:'If Olive had been played by any other little girl, she would not have affected us as mightily as it did'}]->(misssunshine),
    (lisa)-[:COMMENTED {date:'2013-09-27', comment:'overplotted and underdeveloped.'}]->(wreckitralph),
    (lisa)-[:COMMENTED {date:'2013-12-05', comment:'In the beginning it had the best of The X Files and Lost, but later on it was more of the same and ended up being very repetitive'}]->(fringe),
    (bradley)-[:COMMENTED {date:'2013-12-05', comment:'I hardly ever like a sequel, yet I absolutely loved this one'}]->(toystory),
    (matthew)-[:COMMENTED {date:'2013-10-11', comment:'It was highly entertaining. I laughed and cried and sometimes both at the same time'}]->(wreckitralph),
    (matthew)-[:COMMENTED {date:'2013-11-20', comment:'I was moved very deeply. I really recommend this one to kids and grown ups and everyone in between'}]->(toystory),
    (matthew)-[:COMMENTED {date:'2013-12-03', comment:'Deeply moving. Great performances too!'}]->(thehours),
    (lisa)-[:COMMENTED {date:'2013-05-08', comment:'The cast was great. They really did a great job choosing the girl who played Olive'}]->(misssunshine),
    (lisa)-[:COMMENTED {date:'2013-09-27', comment:'They tried to cover too much and reach to too many people. This movie is really overrated'}]->(wreckitralph),
    (lisa)-[:COMMENTED {date:'2013-12-05', comment:'It was entertaining in the beginning, but it was repetitive in the end'}]->(fringe),
    (annie)-[:COMMENTED {date:'2013-12-19', comment:'Mostly boring and way overrated'}]->(thehours),
    (ripley)-[:COMMENTED {date:'2013-06-14', comment:'Roberts has wasted her effervescence on many paltry projects, but she hits the jackpot this time. Erin, single mother of three, a former Miss Wichita who improbably rallies a community to take on a multi-billion-dollar corporation, is the richest role of her career, simultaneously showing off her comic, dramatic and romantic chops'}]->(erinbrockovich),
    (john)-[:COMMENTED {date:'2013-08-18', comment:'With a script that never the humanity of its heroes and no shortage of superpowered set pieces, The Avengers lives up to its hype and raises the bar for Marvel at the movies.'}]->(avengers),
    (ripley)-[:COMMENTED {date:'2013-06-14', comment:'I was reluctant to see this movie because I usually hate Julia Roberts crappy romantic comedies, but I was very surprised by this movie. I think it is the best performance Roberts has made ever and the story is just incredible. It was awesome'}]->(erinbrockovich),
    (john)-[:COMMENTED {date:'2013-08-18', comment:'I liked this one. I was amused and entertained through the whole movie and that is enough for me. And the special effects are great.'}]->(avengers),
    //RATED
    (bradley)-[:RATED {date:'2013-12-05', score:10}]->(toystory),
    (bradley)-[:RATED {date:'2013-12-01', score:9}]->(wreckitralph),
    @@ -132,11 +152,11 @@ The following is the graph representing users, media and the connection between
    '''
    '''

    == Use Cases
    == Queries

    ===== Note:

    From now on, in these queries and examples the term "I" refers to the user 'Bradley Green'. Furthermore, an active user is a given user that has watched
    From now on, in these queries and examples "we" will be the user 'Bradley Green'. Furthermore, an active user is a given user that has watched
    at least one movie, subscribed to some TV show or both.


    @@ -164,7 +184,7 @@ and not to receive news from them.

    http://i.imgur.com/7Tavsid.png[Figure 1. Example of blocking in Tumblr and Twitter]

    Since users have such operation available, it is mandatory that they can view
    Since users have such operation available, they should be able to see
    who they have blocked.

    In this example, we list those users that we (remember, we are Bradley Green), have blocked and the reason why we blocked them. If there is no reason, 'No reason known' will appear instead.
    @@ -182,7 +202,7 @@ ELSE 'No reason known' END AS Reason;

    '''

    ==== List all the comments made of a given movie
    ==== List all the reviews of a given movie

    It's very common in webs with media content like movies or tv shows such as IMDB, Rotten Tomatoes, FilmAffinity, SeriesLy and whatnot to
    allow users to list and view the comments and opinions other users have posted about a given item.
    @@ -212,8 +232,8 @@ ORDER BY Date DESC;

    http://i.imgur.com/xjPlMVb.png[Figure 3. Example of recommendations in FNAC and IMDB]

    Other usual thing to run into not only in these kind of websites, but also in ecommerces is a list of other items
    visited/liked/bought by users that have also visited the item we're currently seeing.
    Another usual thing to run into not only in these kind of websites, but also in ecommerces is a list of other items
    visited/liked/bought by users that have also visited the item we're currently seeing.

    In this example we are in the movie 'Toy Story 3' and we list those movies users that watched 'Toy Story 3' also watched. These recommendations are ordered by how many times those movies appear as recommended.

    @@ -264,7 +284,7 @@ ORDER BY SCORE;

    ==== Display those users that have watched movies from all the different genres but not subscribed to a TV Show

    This query or example, even though it could be a feature of a given social website, it's more of a query that allows us to play a little bit with the graph. The purpose is to find users that have watched movies from all the genres but are not subscribed to a TV Show
    This query or example, even though it could be a feature of a given social website, it's more of a query that allows us to play a little bit with the graph. The purpose is to find users that have watched at least a movie from every genre, but are not subscribed to a TV Show

    [source, cypher]
    ----
    @@ -280,7 +300,7 @@ RETURN str(user.name + ' ' + user.surname) AS User;

    '''

    ==== And ready to mingle
    ==== Ready to mingle

    Sometimes in networking websites we want to list our friends, or friends of friends, or even friends of friends of friends. In this example that's exactly what we'll do, and we'll display the relationship between us. (Remember: We are Bradley Green)

    @@ -301,9 +321,9 @@ str('Friend of friend of friend') END AS Relation;

    '''

    ==== Top 3 favourites since July
    ==== Top 3 favourites since July 2013

    Another feature of almost any website is the Top 10, Top 3 or whatever number you want to choose. In our example, we'll show the Top 3 movies since July 2013. The criteria to be 'higher' in this 'scale' is to have higher ratings, and if two movies have the same rating, it's higher the one with more views by the users.
    Another feature of almost any website is the Top 10, Top 3 and whatnot. In our example, we'll show the Top 3 movies since July 2013. The criteria to be 'higher' in this 'scale' is to have higher ratings, and if two movies have the same rating, it's higher the one with more views by the users.

    [source, cypher]
    ----
    @@ -323,7 +343,7 @@ RETURN str(m.title + ' (' + m.genre + ')') AS Movie, rating, views LIMIT 3;

    ==== See how much time people we follow have spend watching a movie

    Last, but not least, we'll write a query that calculates the total amount of minutes people we follow have spend watching movies.
    Last, but not least, we'll write a query that calculates the total amount of minutes people we follow have spend watching movies (let's suppose they watched those movies once)

    [source, cypher]
    ----
    @@ -338,4 +358,6 @@ ORDER BY Total_minutes DESC;

    //table

    ===== *Note* : The OPTIONAL MATCH clause is used because otherwise, if the user we follow hasn't watched any movie, that user will not appear in the result. This way, if the user has watched a movie, he/she will appear, but if that user hasn't watched any movie, he/she will appear too, and the total amount of time will be 0.
    ===== *Note* : The OPTIONAL MATCH clause is used because otherwise, if the user we follow hasn't watched any movie, that user will not appear in the result. This way, if the user has watched a movie, he/she will appear anyway and the total amount of time will be 0.

    That's the reason why in this query 'we' are Amy and not Bradley, since all the people Bradley follows have watched some movie.
  16. @RaulEstrada RaulEstrada revised this gist Jan 12, 2014. 1 changed file with 107 additions and 4 deletions.
    111 changes: 107 additions & 4 deletions socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,7 @@ website nowadays.
    - Purpose:
    The theme was chosen because of the success these type of webs have all over the world, and because in general their
    structure can be easily and naturally displayed as a graph with very different types of relationships and strongly connected data. So, in a nutshell,
    structure can easily and naturally be displayed as a graph with very different types of relationships and very connected data. So, in a nutshell,
    they can be seen as a very good environment to start working with graph databases.

    //console
    @@ -132,7 +132,7 @@ The following is the graph representing users, media and the connection between
    '''
    '''

    == Queries
    == Use Cases

    ===== Note:

    @@ -182,7 +182,7 @@ ELSE 'No reason known' END AS Reason;

    '''

    ==== List all the reviews made of a given movie
    ==== List all the comments made of a given movie

    It's very common in webs with media content like movies or tv shows such as IMDB, Rotten Tomatoes, FilmAffinity, SeriesLy and whatnot to
    allow users to list and view the comments and opinions other users have posted about a given item.
    @@ -235,4 +235,107 @@ Sometimes we are suggested to follow someone because that user and I follow the

    [source, cypher]
    ----
    MATCH (me:User)-[:FOLLOWS]->(common:User)<-[:FOLLOWS]-
    MATCH (me:User)-[:FOLLOWS]->(common:User)<-[:FOLLOWS]-(stranger:User)
    WHERE NOT (me)-[:BLOCKED]->(stranger) AND me.name = 'Bradley' AND me.surname = 'Green'
    RETURN str(stranger.name + ' ' + stranger.surname) AS User, COLLECT(str(common.name + ' ' + common.surname)) AS Common_Friends, COUNT(*) AS Occurrences ORDER BY Occurrences DESC;
    ----

    //table

    '''

    ==== List the rates of people I follow.

    In websites with media content (movies, tv shows, music, ...), if we follow someone is because we may be interested in knowing which items that user liked or recommended. There are webs like Filmaffinity or IMDB that allow you to list the rates people you follow have given to media items.

    In this example that's what we'll do.

    [source, cypher]
    ----
    MATCH (me:User)-[:FOLLOWS]->(friend:User)-[r:RATED]->(media:Media)
    WHERE me.name = 'Bradley' AND me.surname = 'Green'
    RETURN r.score as SCORE, friend.name as FRIEND, media.title as TITLE
    ORDER BY SCORE;
    ----

    //table

    '''

    ==== Display those users that have watched movies from all the different genres but not subscribed to a TV Show

    This query or example, even though it could be a feature of a given social website, it's more of a query that allows us to play a little bit with the graph. The purpose is to find users that have watched movies from all the genres but are not subscribed to a TV Show

    [source, cypher]
    ----
    MATCH (movie:Movie)
    WITH COLLECT(DISTINCT movie.genre) AS genres
    MATCH (user:User)-[:WATCHED]->(movie:Movie)
    WITH user, genres, COLLECT(DISTINCT movie.genre) AS watched
    WHERE ALL(x IN genres WHERE x IN watched) AND NOT (user)-[:SUBSCRIBED]->(:TV_Show)
    RETURN str(user.name + ' ' + user.surname) AS User;
    ----

    //table

    '''

    ==== And ready to mingle

    Sometimes in networking websites we want to list our friends, or friends of friends, or even friends of friends of friends. In this example that's exactly what we'll do, and we'll display the relationship between us. (Remember: We are Bradley Green)

    [source, cypher]
    ----
    MATCH (me:User{name:'Bradley', surname:'Green'})-[p:FOLLOWS*1..3]->(other:User)
    WHERE NOT (me)-[:BLOCKED]->(other) AND me<>other
    RETURN DISTINCT str(other.name + ' ' + other.surname) AS User,
    CASE WHEN LENGTH(shortestPath((me)-[:FOLLOWS*]->(other))) = 1 THEN
    str('Friend')
    WHEN LENGTH(shortestPath((me)-[:FOLLOWS*]->(other))) = 2 THEN
    str('Friend of friend')
    ELSE
    str('Friend of friend of friend') END AS Relation;
    ----

    //table

    '''

    ==== Top 3 favourites since July

    Another feature of almost any website is the Top 10, Top 3 or whatever number you want to choose. In our example, we'll show the Top 3 movies since July 2013. The criteria to be 'higher' in this 'scale' is to have higher ratings, and if two movies have the same rating, it's higher the one with more views by the users.

    [source, cypher]
    ----
    MATCH ()-[r:RATED]->(m:Movie)
    WHERE r.date >= '2013-07-01'
    WITH m, AVG(r.score) AS rating
    MATCH path=()-[w:WATCHED]->(m)
    WHERE w.date >= '2013-07-01'
    WITH m, rating, count(path) as views
    ORDER BY rating DESC, views DESC
    RETURN str(m.title + ' (' + m.genre + ')') AS Movie, rating, views LIMIT 3;
    ----

    //table

    '''

    ==== See how much time people we follow have spend watching a movie

    Last, but not least, we'll write a query that calculates the total amount of minutes people we follow have spend watching movies.

    [source, cypher]
    ----
    MATCH (me:User{name:'Amy'})-[:FOLLOWS]->(other:User)
    WITH other
    OPTIONAL MATCH (other)-[:WATCHED]->(movie:Movie)
    WITH other, COLLECT(movie) AS watched
    RETURN str(other.name + ' ' + other.surname) AS User,
    reduce(time = 0, mov IN watched | time + mov.runtime_min) AS Total_minutes
    ORDER BY Total_minutes DESC;
    ----

    //table

    ===== *Note* : The OPTIONAL MATCH clause is used because otherwise, if the user we follow hasn't watched any movie, that user will not appear in the result. This way, if the user has watched a movie, he/she will appear, but if that user hasn't watched any movie, he/she will appear too, and the total amount of time will be 0.
  17. @RaulEstrada RaulEstrada revised this gist Jan 12, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -182,7 +182,7 @@ ELSE 'No reason known' END AS Reason;

    '''

    ==== List all the comments made of a given movie
    ==== List all the reviews made of a given movie

    It's very common in webs with media content like movies or tv shows such as IMDB, Rotten Tomatoes, FilmAffinity, SeriesLy and whatnot to
    allow users to list and view the comments and opinions other users have posted about a given item.
  18. @RaulEstrada RaulEstrada revised this gist Jan 12, 2014. 1 changed file with 3 additions and 109 deletions.
    112 changes: 3 additions & 109 deletions socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,7 @@ website nowadays.
    - Purpose:
    The theme was chosen because of the success these type of webs have all over the world, and because in general their
    structure can easily and naturally be displayed as a graph with very different types of relationships and very connected data. So, in a nutshell,
    structure can be easily and naturally displayed as a graph with very different types of relationships and strongly connected data. So, in a nutshell,
    they can be seen as a very good environment to start working with graph databases.

    //console
    @@ -132,7 +132,7 @@ The following is the graph representing users, media and the connection between
    '''
    '''

    == Use Cases
    == Queries

    ===== Note:

    @@ -235,110 +235,4 @@ Sometimes we are suggested to follow someone because that user and I follow the

    [source, cypher]
    ----
    MATCH (me:User)-[:FOLLOWS]->(common:User)<-[:FOLLOWS]-(stranger:User)
    WHERE NOT (me)-[:BLOCKED]->(stranger) AND me.name = 'Bradley' AND me.surname = 'Green'
    AND NOT(me)-[:FOLLOWS]->(stranger)
    RETURN str(stranger.name + ' ' + stranger.surname) AS User, COLLECT(str(common.name + ' ' + common.surname)) AS Common_Friends, COUNT(*) AS Occurrences ORDER BY Occurrences DESC;
    ----

    //table

    '''

    ==== List the rates of people I follow.

    In websites with media content (movies, tv shows, music, ...), if we follow someone is because we may be interested in knowing which items that user liked or recommended. There are webs like Filmaffinity or IMDB that allow you to list the rates people you follow have given to media items.

    In this example that's what we'll do.

    [source, cypher]
    ----
    MATCH (me:User)-[:FOLLOWS]->(friend:User)-[r:RATED]->(media:Media)
    WHERE me.name = 'Bradley' AND me.surname = 'Green'
    RETURN r.score as SCORE, friend.name as FRIEND, media.title as TITLE
    ORDER BY SCORE;
    ----

    //table

    '''

    ==== Display those users that have watched movies from all the different genres but not subscribed to a TV Show

    This query or example, even though it could be a feature of a given social website, it's more of a query that allows us to play a little bit with the graph. The purpose is to find users that have watched movies from all the genres but are not subscribed to a TV Show

    [source, cypher]
    ----
    MATCH (movie:Movie)
    WITH COLLECT(DISTINCT movie.genre) AS genres
    MATCH (user:User)-[:WATCHED]->(movie:Movie)
    WITH user, genres, COLLECT(DISTINCT movie.genre) AS watched
    WHERE ALL(x IN genres WHERE x IN watched) AND NOT (user)-[:SUBSCRIBED]->(:TV_Show)
    RETURN str(user.name + ' ' + user.surname) AS User;
    ----

    //table

    '''

    ==== And ready to mingle

    Sometimes in networking websites we want to list our friends, or friends of friends, or even friends of friends of friends. In this example that's exactly what we'll do, and we'll display the relationship between us. (Remember: We are Bradley Green)

    [source, cypher]
    ----
    MATCH (me:User{name:'Bradley', surname:'Green'})-[p:FOLLOWS*1..3]->(other:User)
    WHERE NOT (me)-[:BLOCKED]->(other) AND me<>other
    RETURN DISTINCT str(other.name + ' ' + other.surname) AS User,
    CASE WHEN LENGTH(shortestPath((me)-[:FOLLOWS*]->(other))) = 1 THEN
    str('Friend')
    WHEN LENGTH(shortestPath((me)-[:FOLLOWS*]->(other))) = 2 THEN
    str('Friend of friend')
    ELSE
    str('Friend of friend of friend') END AS Relation;
    ----

    //table

    '''

    ==== Top 3 favourites since July

    Another feature of almost any website is the Top 10, Top 3 or whatever number you want to choose. In our example, we'll show the Top 3 movies since July 2013. The criteria to be 'higher' in this 'scale' is to have higher ratings, and if two movies have the same rating, it's higher the one with more views by the users.

    [source, cypher]
    ----
    MATCH ()-[r:RATED]->(m:Movie)
    WHERE r.date >= '2013-07-01'
    WITH m, AVG(r.score) AS rating
    MATCH path=()-[w:WATCHED]->(m)
    WHERE w.date >= '2013-07-01'
    WITH m, rating, count(path) as views
    ORDER BY rating DESC, views DESC
    RETURN str(m.title + ' (' + m.genre + ')') AS Movie, rating, views LIMIT 3;
    ----

    //table

    '''

    ==== See how much time people we follow have spend watching a movie

    Last, but not least, we'll write a query that calculates the total amount of minutes people we follow have spend watching movies.

    [source, cypher]
    ----
    MATCH (me:User{name:'Bradley', surname:'Green'})-[:FOLLOWS]->(other:User)
    WITH other
    OPTIONAL MATCH (other)-[:WATCHED]->(movie:Movie)
    WITH other, COLLECT(movie) AS watched
    RETURN str(other.name + ' ' + other.surname) AS User,
    reduce(time = 0, mov IN watched | time + mov.runtime_min) AS Total_minutes
    ORDER BY Total_minutes DESC;
    ----

    //table

    ===== *Note* : The OPTIONAL MATCH clause is used because otherwise, if the user we follow hasn't watched any movie, that user will not appear in the result. This way, if the user has watched a movie, he/she will appear, but if that user hasn't watched any movie, he/she will appear too, and the total amount of time will be 0.

    To illustrate this: Every user Bradley Green follows has watched some movie. The critical part appears when we say "me" is Amy, because Amy follows Ripley (who has watched a movie) and Mark (who hasn't). If OPTIONAL MATCH is just a regular MATCH clause, Mark won't appear in the result. However, if we write the OPTIONAL MATCH the way it is already written, Mark will appear in the result with a total amount of time of 0 minutes.
    MATCH (me:User)-[:FOLLOWS]->(common:User)<-[:FOLLOWS]-
  19. @RaulEstrada RaulEstrada created this gist Jan 12, 2014.
    344 changes: 344 additions & 0 deletions socialNetworking.adoc
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,344 @@
    = An mini social networking website +

    This database is a small example of a networking site where users can watch movies, subscribe to TV shows
    and comment and rate any of the previous media. Users may follow or block other users, just like any other networking
    website nowadays.

    - Purpose:
    The theme was chosen because of the success these type of webs have all over the world, and because in general their
    structure can easily and naturally be displayed as a graph with very different types of relationships and very connected data. So, in a nutshell,
    they can be seen as a very good environment to start working with graph databases.

    //console

    '''

    == Creating the database

    The following is the script used to create all the nodes of the database and the relationships between them.

    //setup
    //hide
    [source, cypher]
    ----
    CREATE
    //Media
    //Movies
    (toystory:Movie:Media {title:'Toy Story 3', tagline:'No toy gets left behind.', genre:'Animation', runtime_min:103, won:'2 Oscars'}),
    (wreckitralph:Movie:Media {title:'Wreck-It Ralph', tagline:'When the arcade closes, the fun begins', genre:'Animation', runtime_min:108}),
    (thelmalouise:Movie:Media {title:'Thelma & Louise', genre:'Drama', runtime_min:130, won:'1 Oscar'}),
    (thehours:Movie:Media {title:'The Hours', genre:'Drama', runtime_min:114, won:'1 Oscar'}),
    (misssunshine:Movie:Media {title:'Little Miss Sunshine', genre:'Comedy', runtime_min:101, won:'2 Oscars'}),
    (erinbrockovich:Movie:Media {title:'Erin Brockovich', genre:'Drama', runtime_min:131, won:'1 Oscar'}),
    (avengers:Movie:Media {title:'The Avengers', genre:'Action', runtime_min:143}),
    //TV SHOWS
    (friends:TV_Show:Media {title:'Friends', episode_duration:'22 min', seasons:'10', genre:'Comedy', spin_off:'Joey'}),
    (office:TV_Show:Media {title:'The Office', episode_duration:'22 min', seasons:'9', genre:'Comedy'}),
    (fringe:TV_Show:Media {title:'Fringe', episode_duration:'60 min', seasons:'5', genre:'Sci-Fi'}),
    //USERS
    (bradley:User {name:'Bradley', surname:'Green', age:24, city:'Los Angeles'}),
    (matthew:User {name:'Matthew', surname:'Cooper', age:36, city:'Los Angeles'}),
    (lisa:User {name:'Lisa', surname:'Adams', age:15, city:'New York'}),
    (annie:User {name:'Annie', surname:'Behr', age:25, city:'Chicago'}),
    (ripley:User {name:'Ripley', surname:'Aniston', city:'Los Angeles'}),
    (john:User {name:'John', surname:'Goodman', age:34, city:'New York'}),
    (amy:User {name:'Amy', surname:'Cooper', age:22}),
    (mark:User {name:'Mark', surname:'McAdams', age:17, city:'Los Angeles'}),
    (dennis:User {name:'Dennis', surname:'Lemon', age:42, city:'Los Angeles'}),
    //FOLLOWS
    (bradley)-[:FOLLOWS]->(matthew),
    (bradley)-[:FOLLOWS]->(ripley),
    (bradley)-[:FOLLOWS]->(john),
    (matthew)-[:FOLLOWS]->(bradley),
    (lisa)-[:FOLLOWS]->(matthew),
    (lisa)-[:FOLLOWS]->(annie),
    (annie)-[:FOLLOWS]->(lisa),
    (annie)-[:FOLLOWS]->(matthew),
    (annie)-[:FOLLOWS]->(ripley),
    (ripley)-[:FOLLOWS]->(annie),
    (ripley)-[:FOLLOWS]->(matthew),
    (ripley)-[:FOLLOWS]->(john),
    (amy)-[:FOLLOWS]->(ripley),
    (amy)-[:FOLLOWS]->(mark),
    (mark)-[:FOLLOWS]->(amy),
    (mark)-[:FOLLOWS]->(dennis),
    //BLOCKED
    (bradley)-[:BLOCKED {reason:'Too much spam'}]->(amy),
    (bradley)-[:BLOCKED]->(annie),
    (matthew)-[:BLOCKED]->(lisa),
    (annie)-[:BLOCKED]->(john),
    (amy)-[:BLOCKED {reason:'Too much spam'}]->(john),
    //WATCHED
    (bradley)-[:WATCHED {date:'2013-12-01'}]->(wreckitralph),
    (bradley)-[:WATCHED {date:'2013-12-05'}]->(toystory),
    (matthew)-[:WATCHED {date:'2013-10-10'}]->(wreckitralph),
    (matthew)-[:WATCHED {date:'2013-11-20'}]->(toystory),
    (matthew)-[:WATCHED {date:'2013-11-25'}]->(misssunshine),
    (matthew)-[:WATCHED {date:'2013-12-01'}]->(thehours),
    (matthew)-[:WATCHED {date:'2013-12-15'}]->(avengers),
    (lisa)-[:WATCHED {date:'2013-05-08'}]->(misssunshine),
    (lisa)-[:WATCHED {date:'2013-09-26'}]->(wreckitralph),
    (lisa)-[:WATCHED {date:'2013-11-29'}]->(toystory),
    (annie)-[:WATCHED {date:'2013-12-10'}]->(misssunshine),
    (annie)-[:WATCHED {date:'2013-12-11'}]->(thehours),
    (annie)-[:WATCHED {date:'2013-12-12'}]->(toystory),
    (annie)-[:WATCHED {date:'2013-12-29'}]->(thelmalouise),
    (ripley)-[:WATCHED {date:'2013-06-14'}]->(erinbrockovich),
    (john)-[:WATCHED {date:'2013-07-11'}]->(erinbrockovich),
    (john)-[:WATCHED {date:'2013-08-18'}]->(avengers),
    (dennis)-[:WATCHED {date:'2013-08-19'}]->(avengers),
    //SUBSCRIBED
    (bradley)-[:SUBSCRIBED]->(friends),
    (bradley)-[:SUBSCRIBED]->(office),
    (annie)-[:SUBSCRIBED]->(friends),
    (lisa)-[:SUBSCRIBED]->(friends),
    (lisa)-[:SUBSCRIBED]->(fringe),
    (john)-[:SUBSCRIBED]->(office),
    (john)-[:SUBSCRIBED]->(fringe),
    (ripley)-[:SUBSCRIBED]->(office),
    (dennis)-[:SUBSCRIBED]->(office),
    //COMMENTED
    (bradley)-[:COMMENTED {date:'2013-12-05', comment:'Deftly blending comedy, adventure, and honest emotion, Toy Story 3 is a rare second sequel that really works.'}]->(toystory),
    (matthew)-[:COMMENTED {date:'2013-10-11', comment:'Equally entertaining for both kids and parents old enough to catch the references, Wreck-It Ralph is a clever, colorful adventure built on familiar themes and joyful nostalgia.'}]->(wreckitralph),
    (matthew)-[:COMMENTED {date:'2013-11-20', comment:'Even with the bar raised high, Toy Story 3 enchanted and moved me so deeply I was flabbergasted that a digitally animated comedy about plastic playthings could have this effect.'}]->(toystory),
    (matthew)-[:COMMENTED {date:'2013-12-03', comment:'Deeply moving'}]->(thehours),
    (lisa)-[:COMMENTED {date:'2013-05-08', comment:'If Olive had been played by any other little girl, she would not have affected us as mightily as it did'}]->(misssunshine),
    (lisa)-[:COMMENTED {date:'2013-09-27', comment:'overplotted and underdeveloped.'}]->(wreckitralph),
    (lisa)-[:COMMENTED {date:'2013-12-05', comment:'In the beginning it had the best of The X Files and Lost, but later on it was more of the same and ended up being very repetitive'}]->(fringe),
    (annie)-[:COMMENTED {date:'2013-12-19', comment:'Mostly boring and way overrated'}]->(thehours),
    (ripley)-[:COMMENTED {date:'2013-06-14', comment:'Roberts has wasted her effervescence on many paltry projects, but she hits the jackpot this time. Erin, single mother of three, a former Miss Wichita who improbably rallies a community to take on a multi-billion-dollar corporation, is the richest role of her career, simultaneously showing off her comic, dramatic and romantic chops'}]->(erinbrockovich),
    (john)-[:COMMENTED {date:'2013-08-18', comment:'With a script that never the humanity of its heroes and no shortage of superpowered set pieces, The Avengers lives up to its hype and raises the bar for Marvel at the movies.'}]->(avengers),
    //RATED
    (bradley)-[:RATED {date:'2013-12-05', score:10}]->(toystory),
    (bradley)-[:RATED {date:'2013-12-01', score:9}]->(wreckitralph),
    (matthew)-[:RATED {date:'2013-11-20', score:10}]->(toystory),
    (matthew)-[:RATED {date:'2013-11-25', score:9}]->(misssunshine),
    (lisa)-[:RATED {date:'2013-11-29', score:9}]->(friends),
    (lisa)-[:RATED {date:'2013-09-27', score:6}]->(wreckitralph),
    (lisa)-[:RATED {date:'2013-11-29', score:8}]->(toystory),
    (annie)-[:RATED {date:'2013-12-10', score:9}]->(misssunshine),
    (annie)-[:RATED {date:'2013-12-10', score:8}]->(friends),
    (annie)-[:RATED {date:'2013-12-12', score:8}]->(toystory),
    (ripley)-[:RATED {date:'2013-06-14', score:9}]->(erinbrockovich),
    (john)-[:RATED {date:'2013-10-18', score:8}]->(office),
    (john)-[:RATED {date:'2013-08-18', score:8}]->(avengers)
    ----

    The following is the graph representing users, media and the connection between all of them.

    //graph

    '''
    '''

    == Use Cases

    ===== Note:

    From now on, in these queries and examples the term "I" refers to the user 'Bradley Green'. Furthermore, an active user is a given user that has watched
    at least one movie, subscribed to some TV show or both.




    ==== Which are the active users that live in the same city as I do?

    This query looks for active users that live in the same city as I do and they are ordered by their activity level, that is, the total number of movies watched and TV Shows subscribed to.

    [source, cypher]
    ----
    MATCH (me:User {name:'Bradley', surname:'Green'}), (other:User)-[:WATCHED|:SUBSCRIBED]->(media:Media)
    WHERE other.city = me.city AND other<>me
    RETURN str(other.surname + ", " + other.name) as Other_User, other.city as City, count(other) as Activity_Level ORDER BY Other_User ASC;
    ----

    //table

    '''

    ==== Which are the users I have blocked?

    In any social networking site there exists the possibility of blocking other users in order not to be contacted by those users
    and not to receive news from them.

    http://i.imgur.com/7Tavsid.png[Figure 1. Example of blocking in Tumblr and Twitter]

    Since users have such operation available, it is mandatory that they can view
    who they have blocked.

    In this example, we list those users that we (remember, we are Bradley Green), have blocked and the reason why we blocked them. If there is no reason, 'No reason known' will appear instead.

    [source, cypher]
    ----
    MATCH (me:User {name:'Bradley', surname:'Green'})-[b:BLOCKED]->(other:User)
    RETURN str(other.name + ' ' + other.surname) AS Blocked,
    CASE WHEN HAS(b.reason)
    THEN b.reason
    ELSE 'No reason known' END AS Reason;
    ----

    //table

    '''

    ==== List all the comments made of a given movie

    It's very common in webs with media content like movies or tv shows such as IMDB, Rotten Tomatoes, FilmAffinity, SeriesLy and whatnot to
    allow users to list and view the comments and opinions other users have posted about a given item.

    http://i.imgur.com/WNDJyZ9.png[Figure 2. Example of reviews posted of a given movie in IMDB and Rotten Tomatoes]

    In this example, we list all the comments posted about a given movie (Toy Story 3), ordered by the date they were posted.

    [source, cypher]
    ----
    MATCH (movie:Movie {title:'Toy Story 3'})<-[c:COMMENTED]-(author:User)
    WITH c, author
    MATCH (me:User{name:'Bradley', surname:'Green'})-[:FOLLOWS]->(other:User)
    WITH c, author, collect(other) as Friends
    RETURN c.comment AS Comment, str(author.name + ' ' + author.surname) AS Author, c.date AS Date,
    CASE WHEN (author) in Friends
    THEN str('Following the author')
    ELSE str('Not following the author') END AS Following
    ORDER BY Date DESC;
    ----

    //table

    '''

    ==== Users that have watched this movie have also watched...

    http://i.imgur.com/xjPlMVb.png[Figure 3. Example of recommendations in FNAC and IMDB]

    Other usual thing to run into not only in these kind of websites, but also in ecommerces is a list of other items
    visited/liked/bought by users that have also visited the item we're currently seeing.

    In this example we are in the movie 'Toy Story 3' and we list those movies users that watched 'Toy Story 3' also watched. These recommendations are ordered by how many times those movies appear as recommended.

    [source, cypher]
    ----
    MATCH (target:Movie)<-[:WATCHED]-(u:User)-[:WATCHED]->(p:Movie)
    WHERE p.title = 'Toy Story 3'
    WITH str(target.title + ' (' + target.genre + ')') AS Suggestion, count(target.title) as Occurrences
    RETURN distinct Suggestion, Occurrences ORDER BY Occurrences DESC, Suggestion ASC;
    ----

    //table

    '''

    ==== Users that follow someone I follow too

    Sometimes we are suggested to follow someone because that user and I follow the same people. In this example we show which users we are recommended to follow and which are our common 'links' (people we follow)

    [source, cypher]
    ----
    MATCH (me:User)-[:FOLLOWS]->(common:User)<-[:FOLLOWS]-(stranger:User)
    WHERE NOT (me)-[:BLOCKED]->(stranger) AND me.name = 'Bradley' AND me.surname = 'Green'
    AND NOT(me)-[:FOLLOWS]->(stranger)
    RETURN str(stranger.name + ' ' + stranger.surname) AS User, COLLECT(str(common.name + ' ' + common.surname)) AS Common_Friends, COUNT(*) AS Occurrences ORDER BY Occurrences DESC;
    ----

    //table

    '''

    ==== List the rates of people I follow.

    In websites with media content (movies, tv shows, music, ...), if we follow someone is because we may be interested in knowing which items that user liked or recommended. There are webs like Filmaffinity or IMDB that allow you to list the rates people you follow have given to media items.

    In this example that's what we'll do.

    [source, cypher]
    ----
    MATCH (me:User)-[:FOLLOWS]->(friend:User)-[r:RATED]->(media:Media)
    WHERE me.name = 'Bradley' AND me.surname = 'Green'
    RETURN r.score as SCORE, friend.name as FRIEND, media.title as TITLE
    ORDER BY SCORE;
    ----

    //table

    '''

    ==== Display those users that have watched movies from all the different genres but not subscribed to a TV Show

    This query or example, even though it could be a feature of a given social website, it's more of a query that allows us to play a little bit with the graph. The purpose is to find users that have watched movies from all the genres but are not subscribed to a TV Show

    [source, cypher]
    ----
    MATCH (movie:Movie)
    WITH COLLECT(DISTINCT movie.genre) AS genres
    MATCH (user:User)-[:WATCHED]->(movie:Movie)
    WITH user, genres, COLLECT(DISTINCT movie.genre) AS watched
    WHERE ALL(x IN genres WHERE x IN watched) AND NOT (user)-[:SUBSCRIBED]->(:TV_Show)
    RETURN str(user.name + ' ' + user.surname) AS User;
    ----

    //table

    '''

    ==== And ready to mingle

    Sometimes in networking websites we want to list our friends, or friends of friends, or even friends of friends of friends. In this example that's exactly what we'll do, and we'll display the relationship between us. (Remember: We are Bradley Green)

    [source, cypher]
    ----
    MATCH (me:User{name:'Bradley', surname:'Green'})-[p:FOLLOWS*1..3]->(other:User)
    WHERE NOT (me)-[:BLOCKED]->(other) AND me<>other
    RETURN DISTINCT str(other.name + ' ' + other.surname) AS User,
    CASE WHEN LENGTH(shortestPath((me)-[:FOLLOWS*]->(other))) = 1 THEN
    str('Friend')
    WHEN LENGTH(shortestPath((me)-[:FOLLOWS*]->(other))) = 2 THEN
    str('Friend of friend')
    ELSE
    str('Friend of friend of friend') END AS Relation;
    ----

    //table

    '''

    ==== Top 3 favourites since July

    Another feature of almost any website is the Top 10, Top 3 or whatever number you want to choose. In our example, we'll show the Top 3 movies since July 2013. The criteria to be 'higher' in this 'scale' is to have higher ratings, and if two movies have the same rating, it's higher the one with more views by the users.

    [source, cypher]
    ----
    MATCH ()-[r:RATED]->(m:Movie)
    WHERE r.date >= '2013-07-01'
    WITH m, AVG(r.score) AS rating
    MATCH path=()-[w:WATCHED]->(m)
    WHERE w.date >= '2013-07-01'
    WITH m, rating, count(path) as views
    ORDER BY rating DESC, views DESC
    RETURN str(m.title + ' (' + m.genre + ')') AS Movie, rating, views LIMIT 3;
    ----

    //table

    '''

    ==== See how much time people we follow have spend watching a movie

    Last, but not least, we'll write a query that calculates the total amount of minutes people we follow have spend watching movies.

    [source, cypher]
    ----
    MATCH (me:User{name:'Bradley', surname:'Green'})-[:FOLLOWS]->(other:User)
    WITH other
    OPTIONAL MATCH (other)-[:WATCHED]->(movie:Movie)
    WITH other, COLLECT(movie) AS watched
    RETURN str(other.name + ' ' + other.surname) AS User,
    reduce(time = 0, mov IN watched | time + mov.runtime_min) AS Total_minutes
    ORDER BY Total_minutes DESC;
    ----

    //table

    ===== *Note* : The OPTIONAL MATCH clause is used because otherwise, if the user we follow hasn't watched any movie, that user will not appear in the result. This way, if the user has watched a movie, he/she will appear, but if that user hasn't watched any movie, he/she will appear too, and the total amount of time will be 0.

    To illustrate this: Every user Bradley Green follows has watched some movie. The critical part appears when we say "me" is Amy, because Amy follows Ripley (who has watched a movie) and Mark (who hasn't). If OPTIONAL MATCH is just a regular MATCH clause, Mark won't appear in the result. However, if we write the OPTIONAL MATCH the way it is already written, Mark will appear in the result with a total amount of time of 0 minutes.