Skip to content

Instantly share code, notes, and snippets.

@MPiunti
Last active August 29, 2015 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save MPiunti/9765844 to your computer and use it in GitHub Desktop.
Save MPiunti/9765844 to your computer and use it in GitHub Desktop.
jOB.me - Reply Innovation Award 2014
image::https://dl.dropboxusercontent.com/u/2236831/logo_jobme_neg.png[jOB.me,150]
Part 2 - link:./?d118d26c3a101bef9b52[Extending the Graph]
As a global player in IT, Reply is shaped over a network organizational model which is actually spread over 3 continents. The group partnership is natively conceived over multidisciplinary skills and resources, tackling multifaceted markets, technologies and IT domains thanks to the tremendous competencies of its employees. The same competencies which are are well suited and represented over _TamTamy_, more and more constituting the real backbone, an _Ark of the Covenant_ where each of the corporate assets dwell.
video::89655760[vimeo]
*jOB.me* is conceived as a *social crawler*, aiming at promoting and reinforcing the links between different companies inside the group: its basic idea is that knowledge, people and their relationships stand as _FIRST CLASS ENTITIES_ inside the corporate network. jOB.me promotes the organizational structure to scale horizontally - in-the-large - towards an evolutionary network where processes, organizations and people are oriented to the natural diffusion and exchange of knowledge and capabilities.
== How it works ==
Plugging TamTamy as Information source, jOB.me learns to extract *skills*, attitudes and experiences from *users*’ profiles and their timelines. Once a consistent vocabulary of skills and attitudes is stored, the tool is capable to automatically find relationships between users and relate them towards *open positions* belonging to different *companies*.
This process can be established in two different phases, which allow to traverse the organization looking for information which is worth to be discovered either from an employee perspective (i.e. job swapping) and from a management one (i.e. recruitment). The data model is envisaged taking a graph-DB approach, which allows the network to be traversed either top down (starting from companys’ positions) and bottom up (linking employee as peers).
== Building The Graph ==
Modeled and developed in http://www.neo4j.org/[*neo4j.org*], the graph includes different entites as nodes, representing *Persons, Skills, Companies, Positions*. Nodes are related each other using lalelled relationships.
//hide
//setup
//output
[source,cypher]
----
CREATE
(p1:Person {id:"1", gender:"M", name:"m.piunti", City:"Rome"}),
(p2:Person {id:"2", gender:"M", name:"m.ferella", City:"London"}),
(p3:Person {id:"3", gender:"M", name:"a.santurbano", City:"Dussendorf"}),
(c1:Company {id:"4", name:"Whitehall Reply", City:"Rome"}),
(c2:Company {id:"5", name:"Bitmama", City:"London"}),
(c3:Company {id:"6", name:"Spike Reply", City:"Dussendorf"}),
(cc1:Country {id:"7", name:"IT"}),
(cc2:Country {id:"8", name:"DE"}),
(cc3:Country {id:"9", name:"UK"}),
(cc1)-[:has]->(c1),
(cc2)-[:has]->(c2),
(cc3)-[:has]->(c3),
(p1)-[:works]->(c1),
(p2)-[:works]->(c2),
(p3)-[:works]->(c3),
(st1:skill_tag {rank:"1", name:"Agent+Oriented+Programming+and+Modeling"}),
(st2:skill_tag {rank:"1", name:"Artificial+Intelligence"}),
(st3:skill_tag {rank:"2", name:"Big+Data"}),
(st4:skill_tag {rank:"3", name:"Graph+DB"}),
(st5:skill_tag {rank:"5", name:"Information+design"}),
(st6:skill_tag {rank:"8", name:"j2ee"}),
(st7:skill_tag {rank:"13", name:"java"}),
(st8:skill_tag {rank:"21", name:"Javascript"}),
(st9:skill_tag {rank:"34", name:"JQuery"}),
(st10:skill_tag {rank:"55", name:"jQuery+Mobile"}),
(st11:skill_tag {rank:"89", name:"Neo4j"}),
(st12:skill_tag {rank:"144", name:"Open+data"}),
(st13:skill_tag {rank:"233", name:"Oracle"}),
(st14:skill_tag {rank:"377", name:"PL-SQL"}),
(st15:skill_tag {rank:"610", name:"REST"}),
(st16:skill_tag {rank:"987", name:"Social+Media"}),
(st17:skill_tag {rank:"1597", name:"Spring"}),
(st18:skill_tag {rank:"2584", name:"Spring+framework"}),
(st19:skill_tag {rank:"4181", name:"SQL"}),
(st20:skill_tag {rank:"6765", name:"Struts"}),
(st21:skill_tag {rank:"10946", name:"Web+2.0"}),
(st22:skill_tag {rank:"17711", name:"Web+Application"}),
(st23:skill_tag {rank:"28657", name:"apache"}),
(st24:skill_tag {rank:"46386", name:"apple"}),
(st25:skill_tag {rank:"75025", name:"Hadoop"}),
(st26:skill_tag {rank:"75025", name:"J2EE+developer"}),
(st27:skill_tag {rank:"75025", name:"jqueryUI"}),
(st28:skill_tag {rank:"75025", name:"mongodb"}),
(st29:skill_tag {rank:"75025", name:"prototype+javascript"}),
(st30:skill_tag {rank:"75025", name:"swat"}),
(st31:skill_tag {rank:"75025", name:"tamtamy"}),
(st32:skill_tag {rank:"75025", name:"tomcat"}),
(st33:skill_tag {rank:"75025", name:"Nosql"}),
(st34:skill_tag {rank:"75025", name:"angularjs"}),
(st35:skill_tag {rank:"75025", name:"d3js"}),
(p1)-[:has_skill_with]->(st1),
(p1)-[:has_skill_with]->(st2),
(p1)-[:has_skill_with]->(st3),
(p1)-[:has_skill_with]->(st4),
(p1)-[:has_skill_with]->(st5),
(p1)-[:has_skill_with]->(st6),
(p1)-[:has_skill_with]->(st7),
(p1)-[:has_skill_with]->(st8),
(p1)-[:has_skill_with]->(st9),
(p1)-[:has_skill_with]->(st10),
(p1)-[:has_skill_with]->(st11),
(p1)-[:has_skill_with]->(st12),
(p1)-[:has_skill_with]->(st13),
(p1)-[:has_skill_with]->(st14),
(p1)-[:has_skill_with]->(st15),
(p1)-[:has_skill_with]->(st16),
(p1)-[:has_skill_with]->(st17),
(p1)-[:has_skill_with]->(st18),
(p1)-[:has_skill_with]->(st19),
(p1)-[:has_skill_with]->(st20),
(p1)-[:has_skill_with]->(st21),
(p1)-[:has_skill_with]->(st22),
(p2)-[:has_skill_with]->(st23),
(p2)-[:has_skill_with]->(st24),
(p2)-[:has_skill_with]->(st25),
(p2)-[:has_skill_with]->(st26),
(p2)-[:has_skill_with]->(st27),
(p2)-[:has_skill_with]->(st28),
(p2)-[:has_skill_with]->(st29),
(p2)-[:has_skill_with]->(st30),
(p2)-[:has_skill_with]->(st31),
(p2)-[:has_skill_with]->(st32),
(p2)-[:has_skill_with]->(st33),
(p2)-[:has_skill_with]->(st3),
(p2)-[:has_skill_with]->(st4),
(p2)-[:has_skill_with]->(st6),
(p2)-[:has_skill_with]->(st7),
(p2)-[:has_skill_with]->(st8),
(p2)-[:has_skill_with]->(st9),
(p2)-[:has_skill_with]->(st10),
(p2)-[:has_skill_with]->(st11),
(p2)-[:has_skill_with]->(st13),
(p2)-[:has_skill_with]->(st14),
(p2)-[:has_skill_with]->(st17),
(p2)-[:has_skill_with]->(st19),
(p3)-[:has_skill_with]->(st34),
(p3)-[:has_skill_with]->(st35),
(p3)-[:has_skill_with]->(st28),
(p3)-[:has_skill_with]->(st11),
(p3)-[:has_skill_with]->(st13),
(p3)-[:has_skill_with]->(st14),
(p3)-[:has_skill_with]->(st18),
(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)-[:require]->(st3),
(v1)-[:require]->(st4),
(v1)-[:require]->(st6),
(v1)-[:require]->(st8),
(v1)-[:require]->(st11),
(v1)-[:require]->(st15),
(v1)-[:require]->(st25),
(v1)-[:require]->(st28),
(v1)-[:require]->(st33),
(v1)-[:require]->(st34),
(v1)-[:require]->(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)-[:require]->(st8),
(v2)-[:require]->(st18),
(v2)-[:require]->(st20),
(v2)-[:require]->(st21),
(v2)-[:require]->(st22),
(v2)-[:require]->(st23),
(v2)-[:require]->(st26),
(v2)-[:require]->(st27),
(v2)-[:require]->(st29),
(v2)-[:require]->(st32),
(v2)-[:require]->(st35),
(v2)-[:require]->(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)-[:require]->(st3),
(v3)-[:require]->(st6),
(v3)-[:require]->(st7),
(v3)-[:require]->(st12),
(v3)-[:require]->(st15),
(v3)-[:require]->(st23),
(v3)-[:require]->(st32)
----
Which gives the following Graph
//graph
The graph is then _mined_ using the Cypher query language and its matching techniques, which allow to compute a metric called *Skill-o-Meter*, used to quantify the match between one’s skills and any applicable position. Once a fair match is found, the employee can apply for the job exchange. Position can be covered on different temporal basis, on a project/seasonal work as well as extended/permanent job.
Based on the provided model, the Cypher query language allows to apply match-making footprints to retrieve patterns inside the whole graph, for instance, the following query:
[source,cypher]
----
MATCH (me{name:'m.piunti'})-[:has_skill_with]->(Skill),
(me)-[:works]->(Company)
RETURN Company,me,Skill
----
gives the foolowing result table:
//table
This approach allows to straightforwardly taverse the graph, stetting the stage for more a complex scenario.
To give an example, the following use cases are provided:
. *jOB.xChange*: As an employee the user want to know who in the company has similar skills to hers one, so that they can exchange position. This allows employees to _swap their workplaces from place to place_, by finding a candidate among other employees.
. *jOB.vacancy*: As an employee, the user want to know which company has raised a vacancy position having requirements
similar to hers’ skills, so that she can apply. This allows the _match between supply and demand, pushing employees towards the most suitable positions.
=== jOB.xChange ===
As an Employee, I want to know who in the company has similar skills to me, So that we can exchange our position. For doing this, we proceed with a lexical analysis, looking for noun and verbs:
* Which *employee*, who work for the same *company* as me, have similar *skills* to me ?
* Which employee, who *work for* the same company as me, *have* similar skills to me ?
Thereby we want to know:
[source]
----
Person WORKS for _Company_
Person HAS_SKILL_WITH _Skill_
----
that in Cypher becomes:
[source,cypher]
----
MATCH (Company)<- [:works]- (me:Person)- [:has_skill_with]->(Skill),
(Company2)<- [:works]- (colleague)- [:has_skill_with]->(Skill)
WHERE me.name='m.piunti'
RETURN colleague.name AS name,
count(Skill) AS Skill_o_Meter,
collect(Skill.name) AS skills
----
In this first use case the result, for the provided graph, is the following:
//table
=== jOB.vacancy ===
As an Employee, I want to know which company has raised a vacancy position having similar skills to mine, So that I can apply. Analyzing nouns and verbs:
* Which *vacancy position*, raised by any *company*, has required skills similar to my ones ?
* Which vacancy position, *raised by* any company, *has* required skills similar to my ones ?
Namely, we want to know:
[source]
----
Vacancy RAISED_BY _Company_
Vacancy HAS_SKILL_WITH _Skill_
----
Which translated in *Cypher* becomes:
[source,cypher]
----
MATCH (me:Person)-[:has_skill_with]->(Skill),
(Company)<-[:RAISED_BY]-(vacancy)-[:require]->(Skill)
WHERE me.name='m.piunti'
RETURN vacancy.name AS Name,
Company.name AS Company,
Company.City AS City,
count(Skill) AS Skill_o_Meter,
collect(Skill.name) AS Skills
----
which, for the provided graph, provides the following result:
//table
//console
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment