Search code examples
neo4jcypherrecommendation-engine

Recommendation based on similartiy of relationship


I want to create a recommendation engine based on the current shopping cart content compared to other (already put) orders and thinking of having a graph like:

(u:User)-[po:PUT_ORDER]->(o:Order)-[cp:CONTAINS_PRODUCT]->(p:Product)

I'm a newbie to Neo4j/Cypher and would appreciate if someone could point me in the right direction regarding the questions below:

  1. Is it possible based on my current shopping cart fetch other already put orders that have most similar products (at least the products I have in current shopping cart) and recommend the delta products, i.e. subtract products we have in common and recommend the other ones... Is that possible?

  2. Let's say there are no other orders that have all the products I have in my shopping cart. Is there a way to group already put orders in result based on how many products they have in common descending and fetch the "delta products" for every order (let's say top 10 orders)?


Solution

  • The questions are not very clear, but I'll try to provide an answer:

    Is it possible based on my current shopping cart fetch other already put orders that have most similar products (at least the products I have in current shopping cart) and recommend the delta products, i.e. subtract products we have in common and recommend the other ones... Is that possible?

    Yes, it is possible. Subtracting can be quite tricky (as Cypher currently lacks a MINUS clause), but you can use list comprehensions to calculate it:

    WITH [1, 2, 3, 4] AS xs, [3, 4, 5] AS ys
    RETURN [x IN xs WHERE NOT x IN ys | x]
    

    Also, if you subtract along relationships, you might want to use a negative pattern condition (WHERE NOT <pattern>):

    MATCH (p:Product) ...
    WHERE NOT (p)-[:SOME_REL_TYPE]->(:SomeNodeLabel)
    RETURN p
    

    Let's say there are no other orders that have all the products I have in my shopping cart. Is there a way to group already put orders in result based on how many products they have in common descending and fetch the "delta products" for every order (let's say top 10 orders)?

    To calculate the number of common products, use a MATCH clause that targets the same p node.

    MATCH
      (u1:User {id: $currentUser})-[:PUT_ORDER]->(:Order)-[:CONTAINS_PRODUCT]->(p:Product),
      (u2:User)-[:PUT_ORDER]->(:Order)-[:CONTAINS_PRODUCT]->(p)
    WITH u1, u2, count(p) AS commonProducts
    ORDER BY commonProducts DESC
    LIMIT 10
    // continue calculation with u1, u2