Skip to content
This repository was archived by the owner on Apr 22, 2020. It is now read-only.

Commit 71c9181

Browse files
committed
common neighbors function
1 parent 034acb1 commit 71c9181

File tree

8 files changed

+325
-2
lines changed

8 files changed

+325
-2
lines changed

algo/src/main/java/org/neo4j/graphalgo/linkprediction/LinkPrediction.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,24 @@ public double resourceAllocationSimilarity(@Name("node1") Node node1, @Name("nod
7171
return neighbors.stream().mapToDouble(nb -> 1.0 / degree(relationshipType, direction, nb)).sum();
7272
}
7373

74+
@UserFunction("algo.linkprediction.commonNeighbors")
75+
@Description("algo.linkprediction.commonNeighbors(node1:Node, node2:Node, {relationshipQuery:'relationshipName', direction:'BOTH'}) " +
76+
"given two nodes, returns the number of common neighbors")
77+
public double commonNeighbors(@Name("node1") Node node1, @Name("node2") Node node2,
78+
@Name(value = "config", defaultValue = "{}") Map<String, Object> config) {
79+
if (node1 == null || node2 == null) {
80+
throw new RuntimeException("Nodes must not be null");
81+
}
82+
83+
ProcedureConfiguration configuration = ProcedureConfiguration.create(config);
84+
RelationshipType relationshipType = configuration.getRelationship();
85+
Direction direction = configuration.getDirection(Direction.BOTH);
86+
87+
Set<Node> neighbors = findPotentialNeighbors(node1, relationshipType, direction);
88+
neighbors.removeIf(node -> noCommonNeighbors(node, relationshipType, direction, node2));
89+
return neighbors.size();
90+
}
91+
7492
private Set<Node> findPotentialNeighbors(@Name("node1") Node node1, RelationshipType relationshipType, Direction direction) {
7593
Set<Node> neighbors = new HashSet<>();
7694

doc/asciidoc/algorithms-link-prediction.adoc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ endif::env-docs[]
1111
These algorithms help determine the closeness of a pair of nodes.
1212
We would then use the computed scores as part of a link prediction solution:
1313

14-
* <<algorithms-linkprediction-adamic-adar, Adamic Adar Similarity>> (`algo.linkprediction.adamicAdar`)
15-
* <<algorithms-linkprediction-resource-allocation, Resource Allocation Similarity>> (`algo.linkprediction.resourceAllocation`)
14+
* <<algorithms-linkprediction-adamic-adar, Adamic Adar>> (`algo.linkprediction.adamicAdar`)
15+
* <<algorithms-linkprediction-common-neighbors, Common Neighbors>> (`algo.linkprediction.commonNeighbors`)
16+
* <<algorithms-linkprediction-resource-allocation, Resource Allocation>> (`algo.linkprediction.resourceAllocation`)
1617

1718
include::linkprediction-adamic-adar.adoc[leveloffset=2]
19+
include::linkprediction-common-neighbors.adoc[leveloffset=2]
1820
include::linkprediction-resource-allocation.adoc[leveloffset=2]
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
[[algorithms-linkprediction-common-neighbors]]
2+
= The Common Neighbors algorithm
3+
4+
[abstract]
5+
--
6+
This section describes the Common Neighbors algorithm in the Neo4j Graph Algorithms library.
7+
--
8+
9+
// tag::introduction[]
10+
Common neighbors captures the idea that two strangers who have a friend in common are more likely to be introduced than those who don't have any friends in common.
11+
// end::introduction[]
12+
13+
14+
[[algorithms-linkprediction-common-neighbors-context]]
15+
== History and explanation
16+
17+
// tag::explanation[]
18+
19+
It is computed using the following formula:
20+
21+
image::common-neighbors.svg[role="middle"]
22+
23+
where `N(x)` is the set of nodes adjacent to node `x`, and `N(y)` is the set of nodes adjacent to node `y`.
24+
25+
A value of 0 indicates that two nodes are not close, while higher values indicate nodes are closer.
26+
27+
The library contains a function to calculate closeness between two nodes.
28+
29+
// end::explanation[]
30+
31+
32+
[[algorithms-linkprediction-common-neighbors-sample]]
33+
== Common Neighbors algorithm sample
34+
35+
.The following will create a sample graph:
36+
[source, cypher]
37+
----
38+
include::scripts/linkprediction-common-neighbors.cypher[tag=create-sample-graph]
39+
----
40+
41+
.The following will return the number of common neighbors for Michael and Karin:
42+
[source, cypher]
43+
----
44+
include::scripts/linkprediction-common-neighbors.cypher[tag=all-rels]
45+
----
46+
47+
// tag::function[]
48+
.Results
49+
[opts="header",cols="1"]
50+
|===
51+
| `score`
52+
| 1.0
53+
|===
54+
// end::function[]
55+
56+
57+
We can also compute the score of a pair of nodes based on a specific relationship type.
58+
59+
.The following will return the number of common neighbors for Michael and Karin based only on the `FRIENDS` relationships:
60+
[source, cypher]
61+
----
62+
include::scripts/linkprediction-common-neighbors.cypher[tag=only-friends]
63+
----
64+
65+
// tag::function[]
66+
.Results
67+
[opts="header",cols="1"]
68+
|===
69+
| `score`
70+
| 0.0
71+
|===
72+
// end::function[]
73+
74+
75+
[[algorithms-linkprediction-common-neighbors-syntax]]
76+
== Syntax
77+
78+
.The following will run the algorithm and return the result:
79+
[source, cypher]
80+
----
81+
RETURN algo.linkprediction.commonNeighbors(node1:Node, node2:Node, {
82+
relationshipQuery: null,
83+
direction: "BOTH"
84+
})
85+
----
86+
87+
88+
.Parameters
89+
[opts="header",cols="1,1,1,1,4"]
90+
|===
91+
| Name | Type | Default | Optional | Description
92+
| `node1` | Node | null | no | A node
93+
| `node2` | Node | null | no | Another node
94+
| `relationshipQuery` | String | null | yes | The relationship type used to compute similarity between `node1` and `node2`
95+
| `direction` | String | BOTH | yes | The direction of relationship type used to compute similarity between `node1` and `node2`
96+
|===
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// tag::create-sample-graph[]
2+
3+
MERGE (zhen:Person {name: "Zhen"})
4+
MERGE (praveena:Person {name: "Praveena"})
5+
MERGE (michael:Person {name: "Michael"})
6+
MERGE (arya:Person {name: "Arya"})
7+
MERGE (karin:Person {name: "Karin"})
8+
9+
MERGE (zhen)-[:FRIENDS]-(arya)
10+
MERGE (zhen)-[:FRIENDS]-(praveena)
11+
MERGE (praveena)-[:WORKS_WITH]-(karin)
12+
MERGE (praveena)-[:FRIENDS]-(michael)
13+
MERGE (michael)-[:WORKS_WITH]-(karin)
14+
MERGE (arya)-[:FRIENDS]-(karin)
15+
16+
// end::create-sample-graph[]
17+
18+
// tag::all-rels[]
19+
MATCH (p1:Person {name: 'Michael'})
20+
MATCH (p2:Person {name: 'Karin'})
21+
RETURN algo.linkprediction.commonNeighbors(p1, p2) AS score
22+
// end::all-rels[]
23+
24+
// tag::only-friends[]
25+
MATCH (p1:Person {name: 'Michael'})
26+
MATCH (p2:Person {name: 'Karin'})
27+
RETURN algo.linkprediction.commonNeighbors(p1, p2, {relationshipQuery: "FRIENDS"}) AS score
28+
// end::only-friends[]

doc/docbook/content-map.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
<d:tocentry linkend="algorithms-linkprediction"><?dbhtml filename="algorithms/linkprediction/index.html"?>
6868
<d:tocentry linkend="algorithms-linkprediction-adamic-adar"><?dbhtml filename="algorithms/linkprediction-adamic-adar/index.html"?>
6969
</d:tocentry>
70+
<d:tocentry linkend="algorithms-linkprediction-common-neighbors"><?dbhtml filename="algorithms/linkprediction-common-neighbors/index.html"?>
71+
</d:tocentry>
7072
<d:tocentry linkend="algorithms-linkprediction-resource-allocation"><?dbhtml filename="algorithms/linkprediction-resource-allocation/index.html"?>
7173
</d:tocentry>
7274
</d:tocentry>

doc/images/common-neighbors.svg

Lines changed: 37 additions & 0 deletions
Loading

readme.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ These algorithms help calculate the similarity of nodes:
7878
These algorithms can be used as part of Link Prediction solution:
7979

8080
* <<algorithms-linkprediction-adamic-adar, Adamic Adar>> (`algo.linkprediction.adamicAdar`)
81+
* <<algorithms-linkprediction-common-neighbors, Common Neighbors>> (`algo.linkprediction.commonNeighbors`)
8182
* <<algorithms-linkprediction-adamic-adar, Resource Allocation>> (`algo.linkprediction.resourceAllocation`)
8283

8384
=== Preprocessing

0 commit comments

Comments
 (0)