Last active
March 2, 2016 14:33
-
-
Save MPiunti/d118d26c3a101bef9b52 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
image::https://dl.dropboxusercontent.com/u/2236831/logo_jobme_neg.png[jOB.me,150] | |
Part 1 - link:./?9765844[Building the Graph] | |
== Extending the Graph == | |
Modeled and developed in http://www.neo4j.org/[*neo4j.org*], the graph here is extendes to include *Events, Technologies, Area of Interests, Contents*. | |
Nodes are related each other using lalelled relationships. | |
//hide | |
//setup | |
//output | |
[source,cypher] | |
---- | |
CREATE | |
(p1:Person {id:"1", gender:"M", name:"Jean Paul", City:"Paris"}), | |
(p2:Person {id:"2", gender:"M", name:"John", City:"London"}), | |
(p3:Person {id:"3", gender:"M", name:"Karl", City:"Detroit"}), | |
(c1:Company {id:"4", name:"Reply Inc.", City:"Detroit"}), | |
(c2:Company {id:"5", name:"Bitmama", City:"London"}), | |
(c3:Company {id:"6", name:"Spike Reply", City:"Dussendorf"}), | |
(cc1:Country {id:"7", name:"US"}), | |
(cc2:Country {id:"8", name:"UK"}), | |
(cc3:Country {id:"9", name:"DE"}), | |
(ev1:Event {type:"Labcamp", name:"Neo4j Graph DB"}), | |
(t1:Technology {name:"Neo4j"}), | |
(t2:Technology {name:"OrientDB"}), | |
(t3:Technology {name:"TITAN Aurelius"}), | |
(a1:Area {name:"Graph+DB"}), | |
(cc1)-[:HAS]->(c1), | |
(cc2)-[:HAS]->(c2), | |
(cc3)-[:HAS]->(c3), | |
(p1)-[:WORKS]->(c1), | |
(p2)-[:WORKS]->(c2), | |
(p3)-[:WORKS]->(c3), | |
(st1:Skill {rank:"1", name:"Agent+Oriented+Programming+and+Modeling"}), | |
(st2:Skill {rank:"1", name:"Artificial+Intelligence"}), | |
(st3:Skill {rank:"2", name:"Big+Data"}), | |
(st4:Skill {rank:"3", name:"Graph+DB"}), | |
(st5:Skill {rank:"5", name:"Information+design"}), | |
(st6:Skill {rank:"8", name:"j2ee"}), | |
(st7:Skill {rank:"13", name:"java"}), | |
(st8:Skill {rank:"21", name:"Javascript"}), | |
(st9:Skill {rank:"34", name:"JQuery"}), | |
(st10:Skill {rank:"55", name:"jQuery+Mobile"}), | |
(st11:Skill {rank:"89", name:"Neo4j"}), | |
(st12:Skill {rank:"144", name:"Open+data"}), | |
(st13:Skill {rank:"233", name:"Oracle"}), | |
(st14:Skill {rank:"377", name:"PL-SQL"}), | |
(st15:Skill {rank:"610", name:"REST"}), | |
(st16:Skill {rank:"987", name:"Social+Media"}), | |
(st17:Skill {rank:"1597", name:"Spring"}), | |
(st18:Skill {rank:"2584", name:"Spring+framework"}), | |
(st19:Skill {rank:"4181", name:"SQL"}), | |
(st20:Skill {rank:"6765", name:"Struts"}), | |
(st21:Skill {rank:"10946", name:"Web+2.0"}), | |
(st22:Skill {rank:"17711", name:"Web+Application"}), | |
(st23:Skill {rank:"28657", name:"apache"}), | |
(st24:Skill {rank:"46386", name:"apple"}), | |
(st25:Skill {rank:"75025", name:"Hadoop"}), | |
(st26:Skill {rank:"75025", name:"J2EE+developer"}), | |
(st27:Skill {rank:"75026", name:"jqueryUI"}), | |
(st28:Skill {rank:"75027", name:"mongodb"}), | |
(st29:Skill {rank:"7503", name:"prototype+javascript"}), | |
(st30:Skill {rank:"75028", name:"swat"}), | |
(st31:Skill {rank:"755", name:"tamtamy"}), | |
(st32:Skill {rank:"7245", name:"tomcat"}), | |
(st33:Skill {rank:"25", name:"Nosql"}), | |
(st34:Skill {rank:"55", name:"angularjs"}), | |
(st35:Skill {rank:"9535", name:"CSS"}), | |
(st36:Skill {rank:"7535", name:"d3js"}), | |
(st37:Skill {rank:"7535", name:"Cypher"}), | |
(co1:Content {title:"Bootstrap 3 Released", source:"infoQ"}), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st1), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st2), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st3), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st4), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st5), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st6), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st7), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st8), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st9), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st10), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st11), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st12), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st13), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st14), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st15), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st16), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st17), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st18), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st19), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st20), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st21), | |
(p1)-[:HAS_SKILL {source:"GitHub"}]->(st37), | |
(p1)-[:HAS_SKILL {source:"TamTamy"}]->(st22), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st23), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st24), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st25), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st26), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st27), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st28), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st29), | |
(p2)-[:HAS_SKILL {source:"GitHub"}]->(st30), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st31), | |
(p2)-[:HAS_SKILL {source:"StackOverflow"}]->(st32), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st33), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st3), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st4), | |
(p2)-[:HAS_SKILL {source:"StackOverflow"}]->(st6), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st7), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st8), | |
(p2)-[:HAS_SKILL {source:"GitHub"}]->(st8), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st9), | |
(p2)-[:HAS_SKILL {source:"StackOverflow"}]->(st10), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st11), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st13), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st14), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st17), | |
(p2)-[:HAS_SKILL {source:"StackOverflow"}]->(st19), | |
(p2)-[:HAS_SKILL {source:"TamTamy"}]->(st35), | |
(p2)-[:SHARED]->(co1), | |
(p3)-[:HAS_SKILL {source:"TamTamy"}]->(st8), | |
(p3)-[:HAS_SKILL {source:"TamTamy"}]->(st34), | |
(p3)-[:HAS_SKILL {source:"TamTamy"}]->(st35), | |
(p3)-[:HAS_SKILL {source:"TamTamy"}]->(st28), | |
(p3)-[:HAS_SKILL {source:"TamTamy"}]->(st11), | |
(p3)-[:HAS_SKILL {source:"TamTamy"}]->(st13), | |
(p3)-[:HAS_SKILL {source:"TamTamy"}]->(st14), | |
(p3)-[:HAS_SKILL {source:"TamTamy"}]->(st18), | |
(p3)-[:HAS_SKILL {source:"TamTamy"}]->(st35), | |
(p3)-[:LIKED]->(co1), | |
(v1:Vacancy {id:"10", type:"Season", name:"Summer Vacancy", City:"Belo Horizonte"}), | |
(c4:Company {id:"11", name:"Reply Brasil", City:"Belo Horizonte"}), | |
(v1)-[:RAISED_BY]->(c4), | |
(v1)-[:REQUIRES]->(st3), | |
(v1)-[:REQUIRES]->(st4), | |
(v1)-[:REQUIRES]->(st6), | |
(v1)-[:REQUIRES]->(st8), | |
(v1)-[:REQUIRES]->(st11), | |
(v1)-[:REQUIRES]->(st15), | |
(v1)-[:REQUIRES]->(st25), | |
(v1)-[:REQUIRES]->(st28), | |
(v1)-[:REQUIRES]->(st33), | |
(v1)-[:REQUIRES]->(st34), | |
(v1)-[:REQUIRES]->(st35), | |
(v2:Vacancy {id:"11", type:"Season", name:"Stage", City:"Chicago"}), | |
(c5:Company {id:"12", name:"Reply Inc.", City:"Chicago"}), | |
(v2)-[:RAISED_BY]->(c5), | |
(v2)-[:REQUIRES]->(st8), | |
(v2)-[:REQUIRES]->(st18), | |
(v2)-[:REQUIRES]->(st20), | |
(v2)-[:REQUIRES]->(st21), | |
(v2)-[:REQUIRES]->(st22), | |
(v2)-[:REQUIRES]->(st23), | |
(v2)-[:REQUIRES]->(st26), | |
(v2)-[:REQUIRES]->(st27), | |
(v2)-[:REQUIRES]->(st29), | |
(v2)-[:REQUIRES]->(st32), | |
(v2)-[:REQUIRES]->(st35), | |
(v2)-[:REQUIRES]->(st34), | |
(v3:Vacancy {id:"13", type:"Season", name:"Temporary Position", City:"London"}), | |
(c6:Company {id:"14", name:"Glue Reply", City:"London"}), | |
(v3)-[:RAISED_BY]->(c6), | |
(v3)-[:REQUIRES]->(st3), | |
(v3)-[:REQUIRES]->(st6), | |
(v3)-[:REQUIRES]->(st7), | |
(v3)-[:REQUIRES]->(st12), | |
(v3)-[:REQUIRES]->(st15), | |
(v3)-[:REQUIRES]->(st23), | |
(v3)-[:REQUIRES]->(st32), | |
// LEVEL2 | |
(p2)-[:ATTENDED]->(ev1), | |
(p3)-[:ATTENDED]->(ev1), | |
(ev1)-[:ADDRESSED]->(t1), | |
(t1)-[:INCLUDES]->(st37), | |
(t1)-[:INCLUDES]->(st6), | |
(t1)-[:INCLUDES]->(st15), | |
(a1)-[:INVOLVES]->(t1), | |
(a1)-[:INVOLVES]->(t2), | |
(a1)-[:INVOLVES]->(t3), | |
(p2)-[:INTERESTED {source:"Inferenced"}]->(a1), | |
(p3)-[:INTERESTED {source:"Inferenced"}]->(a1) | |
---- | |
Which gives the following Graph | |
//graph | |
The following query shows who exhibits the same skills among users: | |
[source,cypher] | |
---- | |
MATCH (p1{name:'Karl'})-[:HAS_SKILL]->(Skill), | |
(p2{name:'John'})-[:HAS_SKILL]->(Skill) | |
RETURN p1.name,p2.name, Skill.name | |
---- | |
which, for the provided graph, gives the following result: | |
//table | |
And the following shows all the users who shared (or liked) a given content on the time line: | |
[source,cypher] | |
---- | |
MATCH (m)-[:SHARED|LIKED]->(Content) | |
RETURN m.name,Content.title | |
---- | |
//table | |
=== Third Party Sources === | |
The graph is in this case fed with external sources, through the use of public APIs. For instance, users skill cloud is extendend connecting http://stackoverflow.com/[*Stackoverflow*] and https://github.com/[*GitHub*]. | |
[source,cypher] | |
---- | |
MATCH (person{name:'John'})-[r:HAS_SKILL]->(skill) | |
RETURN person.name,r.source,skill.name | |
---- | |
//table | |
The following query unveils _who knows_ a given technolgy, ranking the results accoridng to the whole set of external information sources: | |
[source,cypher] | |
---- | |
MATCH (p:Person)-[:HAS_SKILL]->(s:Skill), | |
(t:Technology)-[:INCLUDES]->(s) | |
RETURN p.name AS name, t.name, | |
count(s) AS Skill_o_Meter, | |
collect(s.name) AS skills | |
---- | |
//table | |
=== Reccomendation Engine === | |
Once anyone partecipates an event, we may suggest area of interests and related technologies: | |
[source,cypher] | |
---- | |
MATCH (p2{name:'John'})-[:ATTENDED]->(Event), | |
(Event)-[:ADDRESSED]->(Technology), | |
(Technology)<-[:INVOLVES]-(Area), | |
(Area)-[:INVOLVES]->(Suggestions) | |
RETURN Area.name, Suggestions.name | |
---- | |
//table | |
*Step 1: Generate concrete relationships on hidden connections* Adopting a typical argumentation mechanisms, the following script *generates* brand new realtionships of type [:SUPPORTS] every time a content is found: these supports links toghether the content node and the skills owned by the publisher user and any of the users who "LIKED" this content. | |
[source,cypher] | |
---- | |
MATCH (content:Content) <-[:SHARED|LIKED]-(person:Person), | |
(person)-[:HAS_SKILL]->(skill:Skill) | |
WITH content, skill, count(skill) as weight | |
CREATE p=(content)-[r:SUPPORTS {weight: weight}]-> (skill) | |
RETURN content.title, skill.name, r.weight as SUPPORTS | |
ORDER BY r.weight DESC | |
---- | |
The resulting sub-graph constitutes a 'digest' for the skills which can be related to this content. New [:SUPPORTS] are automatically generated between contents and skills. | |
//table | |
*Step 2: Generate User profiled Recommendation* the meta inforation introduced with the previous argumentation phase can be then applied to _suggest_ content to the users exhibiting the same skill configuration: | |
[source,cypher] | |
---- | |
MATCH (person)-[:HAS_SKILL]->(skill), | |
(content)-[r:SUPPORTS]-> (skill) | |
WHERE NOT (person)-[:SHARED|LIKED]->(content) | |
RETURN person.name, content.title, skill.name, r.weight | |
ORDER BY r.weight DESC | |
---- | |
//table | |
The results provide a *Social Reccomendation*. It can be noticed how the _weight_ is tuned with the supports which the content skills have received in the previous argumentation phase. | |
Similarly, given a user profile we may find any possible content recommendation based on his interest and skills. The following Cypher query can be executed for retrieving such an information. | |
[source,cypher] | |
---- | |
MATCH (person:Person)-[:HAS_SKILL]->(skill:Skill), | |
(skill) <-[r:SUPPORTS]-(content:Content) | |
WHERE NOT (person)-[:SHARED|LIKED]->(content) | |
RETURN person.name , content.title as title, sum(r.weight) as weight | |
ORDER BY weight DESC | |
---- | |
The retrieved result can be then used as a reccomendation to the matching users, as follows: | |
//table |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment