ProGM
ProGM

Reputation: 7108

Keeping track of visits on a certain resource in neo4j

I want to keep track of user's visits on the various resources pages.

I'm keeping this informations to query most viewed pages, suggest similar topics and more.

I thought about three possible designs.

First one: Create a new relation of type "visited" between the user and the resource, any time the user visits the page.

MATCH (u:User), (r:Resource)
WHERE some conditions
create (u)-[:visited]->d

Second one: Create an unique relation with attribute an count, and update it any time you got a new visit.

Third one: Create a node of type Visit that keeps all information about the visit, and update it.

(The third was inspired by this article: http://snowplowanalytics.com/blog/2014/07/31/using-graph-databases-to-perform-pathing-analysis-initial-experimentation-with-neo4j/ )

Since I'm quite new to neo4j, I can't determine which of this is the best in term of performances. Can you help me?

Upvotes: 1

Views: 78

Answers (1)

Brian Underwood
Brian Underwood

Reputation: 10856

Martin is right in that it depends on what you're doing. I actually tackled this problem in a Ruby on Rails engine gem I call GraphStarter recently. The goal of that gem is to provide a web UI for your data. Additionally it records the Rails sessions (either logged out or logged in) and relates those to users, and it relates the sessions to individual assets. What I ended up doing was have one relationship between each session and each asset, MERGE it if it doesn't already exist, and increment a counter if it does. You can see the code here:

https://github.com/neo4j-examples/graph_starter/blob/master/app/controllers/graph_starter/assets_controller.rb#L52

https://github.com/neo4j-examples/graph_starter/blob/master/app/models/graph_starter/view.rb#L34

If I wanted to count views for an asset by user I can do this:

MATCH (asset:Asset)<-[view:VIEWED]-(:Session)-[:FOR_USER]->(user:User)
WITH asset, user, sum(view.count) AS view_count
RETURN asset.title, user.username, view_count

That is, of course, because a user could have multiple sessions over time. Also, I do the WITH by the asset and user rather than simply RETURNing because I don't want to group by the asset's title / user's username in case there are multiple assets with the same title / multiple users with the same username.

A last note, if you decide to go with the intermediate Session node like I did: For security reasons Rails creates a fresh session for you whenever you login/logout. So I also create a REPLACES relationship to show the chain of sessions when we know them. This means that we can tie a user to an asset view via logged out sessions like so:

MATCH (asset:Asset)<-[view:VIEWED]-(:Session)-[:FOR_USER|REPLACES*]->(user:User)
WITH asset, user, sum(view.count) AS view_count
RETURN asset.title, user.username, view_count

Upvotes: 1

Related Questions