cancel
Showing results for 
Search instead for 
Did you mean: 

Simple Recommendation

SebastianL
Node

Hey Community,

i'm new to Neo4J.

How can i reason/interference with Neo4j?

Data:

user1-[hasItem]->Item1

user1-[hasItem]->Item2

user2-[hasItem]->Item1

user2-[hasItem]->Item2

user2-[hasItem]->Item3

user3-[hasItem]->Item1

user3-[hasItem]->Item2

user3-[hasItem]->Item3

user3-[hasItem]->Item4

Question:

i'm searching something like recommend (user1) top 5 Items (by count), that other Users have with the same items (item1, item2). It's like people that bought item1, item2 also bought item3, item4 (priorized by count item3[2 times], item4[1 time]).

Is there a simple solution? Sorry, that might be a stupid question and obvious, but like i sayd i'm new and i think, this is one of the benefits of Neo4J.

 

thanks!

Sebastian

7 REPLIES 7

wgevaert
Node Link

I think the following query might do something you want:

MATCH
  (User1)-[:hasItem]->()<-[:hasItem]-(OtherUser)-[:hasItem]->(ItemToRecommend)
  WHERE NOT (User1)-[:hasItem]->(ItemToRecommend)
WITH id(ItemToRecommend) AS RecommendedId, count(*) AS numberOfUsersThatHaveThisItem
RETURN RecommendedId
ORDER BY numberOfUsersThatHaveThisItem
LIMIT 5;

Explanation:
For each item that User1 has, this query matches for all users that also have this item (Excluding User1 by relationship isomorphism ) and then matches for other items that these other users have. This can be another item that User1 already has, which we do not want, so we exclude it in a where clause.
Then we just count for each item in how many matches it did occur and we are done.

oh yes! I'm going to test this! Thanks a lot! This sounds like the think i'm searching

SebastianL
Node

Ok i tried this out, but it's not that, what i'm searching for (even it is awesome).

How do i describe it... let's see. Let's make an example with a movie recommender. I like action movies and i watched 100 of them. There are more people on the graph, that like comedy and watched over 1000 movies. So i get the recommendation to watch a comedy movie. This query shows me all the movies, that i didn't see and recommend me the movies, that people have watched the most. What i'm searching is to find other users with the same pattern, that have seen those 100 (action) movies and recommends me the most viewed movie, wich should be an action, not a comedy movie. The Query should match/recognize patterns.

f.e. user have seen movies:

User1: {M1, M2, M3} -> recommendation: M4, M5

User2: {M1, M2, M3, M4}  -> recommendation: M5

User3: {M1, M2, M3, M4, M5} -> no recommendation (pattern doesn't match)

User4: {M1, M2, M3, M5, M6} -> no recommendation (pattern doesn't match)

User5: {M1, M6}  -> recommendation: M2, M3, M5

In the Algorithm that is showed on the top, User3 M6 and User4 would get M4 recommended - wich is wrong in my opinion for my case.

Is there a Way to do it in one query? thanks for the awesome help so far

ameyasoft
Graph Maven

Created a graph from the example data.

Screen Shot 2022-07-20 at 2.47.15 PM.png

Here is the query:

match (a:User)-[]-(b:Movie)
with a, collect(distinct b.name) as mv1

match (c:User)-[]-(d:Movie)
where id(c)<> id(a)
with a, mv1, c, collect(distinct d.name) as mv2

with id(a) as ID, a.name as usr1, id(c) as ID2, c.name as usr2, apoc.coll.subtract(mv2, mv1) as mv3

with ID, usr1, ID2, usr2, mv3, size(mv3) as cnt
with distinct ID, usr1, ID2, usr2, mv3, cnt order by cnt desc
return usr1 as User, mv3 as RecommendMovies, usr1 as toUser
Result:
Screen Shot 2022-07-20 at 2.53.52 PM.png

 

Sorry for the typo:

match (a:User)-[]-(b:Movie)
with a, collect(distinct b.name) as mv1

match (c:User)-[]-(d:Movie)
where id(c)<> id(a)
with a, mv1, c, collect(distinct d.name) as mv2

with id(a) as ID, a.name as usr1, id(c) as ID2, c.name as usr2, apoc.coll.subtract(mv2, mv1) as mv3

with ID, usr1, ID2, usr2, mv3, size(mv3) as cnt
with distinct ID, usr1, ID2, usr2, mv3, cnt order by cnt desc
return usr2 as User, mv3 as RecommendMovies, usr1 as toUser
Result:
Screen Shot 2022-07-20 at 3.00.54 PM.png

glilienfield
Ninja
Ninja

I don't follow what you described, so I made up what I thought made sense. I want to get movie recommendations from those people that have watched the same movies as the person getting the recommendations. Then I want to get all the moves these top similar people have watched that I have not watched, and return the top 5 movies watched the most within the group of similar movie watchers.  

match(n:User)-[:WATCHED]->(:Movie)<-[:WATCHED]-(m:User)
with n, m, count(*) as noSameMovies
order by noSameMovies desc
limit 5
match(m)-[:WATCHED]->(x:Movie)
where not exists( (n)-[:WATCHED]->(x) )
with n, x, count(*) as noOfWatches
order by noOfWatches desc
limit 5
return n.name as movieWatcher, collect(x.title) as recommendations

 Just a thought

SebastianL
Node

you gave me some inspiration. I have solved the problem by myself with the first post. Thanks to all, that took the time to answer me. Sorry that it took so long for a "thank you". Anyway thank you for your answes!

Nodes 2022
Nodes
NODES 2022, Neo4j Online Education Summit

On November 16 and 17 for 24 hours across all timezones, you’ll learn about best practices for beginners and experts alike.