Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Graph DB get the next best recommended node in Neo4j cypher

I have a graph using NEO4j and currently trying to build a simple recommendation system that is better than text based search.

Nodes are created such as: Album, People, Type, Chart

Relationship are created such as:

People - [:role] -> Album where roles are: Artist, Producer, Songwriter

Album-[:is_a_type_of]->Type (type is basically Pop, Rock, Disco...)

People -[:POPULAR_ON]->Chart (Chart is which Billboard they might have been)

People -[:SIMILAR_TO]->People (Predetermined similarity connection)

I have written the following cypher:

    MATCH (a:Album { id: { id } })-[:is_a_type_of]->(t)<-[:is_a_type_of]-(recommend)    
    WITH recommend, t, a
    MATCH (recommend)<-[:ARTIST_OF]-(p)
    OPTIONAL MATCH (p)-[:POPULAR_ON]->()
    RETURN recommend, count(DISTINCT t) AS type
    ORDER BY type DESC
    LIMIT 25;

It works however, it easily repeats itself if it has only one type of music connected to it, therefore has the same neighbors.

Is there a suggested way to say:

  • Find me the next best album that has the most similar connected relationships to the starting Album from.
  • Any Recommendation for a tie breaker scenario? Right now it is order by type (so if an album has more than one type of music it is valued more but if everyone has the same number, there is no more significant)
  • -I made the [:SIMILAR_TO] link to enforce a priority to consider that relationship as important, but I haven't had a working cypher with it
  • -Same goes for [:Popular_On] (Maybe Drop this relationship?)
like image 438
azngunit81 Avatar asked Oct 30 '22 18:10

azngunit81


1 Answers

You can use 4 configurations and order albums according to higher value in this order. Keep configuration between 0 to 1 (ex. 0.6)

a. People Popular on Chart and People are similar
b. People Popular on Chart and People are Not similar
c. People Not Popular on Chart and People are similar
d. People Not Popular on Chart and People are Not similar

Calculate and sum these 4 values with each album. Higher the value, higher recommended Album.

I have temporarily made config as a = 1, b =0.8, c=0.6, d = 0.4. And assumed some relationship present which suggests some People Likes Album. If you are making logic based on Chart only then use a & b only.

MATCH (me:People)
where id(me) = 123
MATCH (a:Album { id: 456 })-[:is_a_type_of]->(t:Type)<-[:is_a_type_of]-(recommend)    
OPTIONAL MATCH (recommend)<-[:ARTIST_OF]-(a:People)-[:POPULAR_ON]->(:Chart)
WHERE exists((me)-[:SIMILAR_TO]->(a))
OPTIONAL MATCH (recommend)<-[:ARTIST_OF]-(b:People)-[:POPULAR_ON]->(:Chart)
WHERE NOT exists((me)-[:SIMILAR_TO]->(b))
OPTIONAL MATCH (recommend)<-[:LIKES]-(c:People)
WHERE exists((me)-[:SIMILAR_TO]->(a))
OPTIONAL MATCH (recommend)<-[:LIKES]-(d:People)
WHERE NOT exists((me)-[:SIMILAR_TO]->(a))
RETURN recommend, (count(a)*1 + count(b)*0.8 + count(c)* 0.6+count(d)*0.4) as rec_order
ORDER BY rec_order DESC
LIMIT 10;
like image 133
Somnath Muluk Avatar answered Jan 04 '23 15:01

Somnath Muluk