diff --git a/algo/src/main/java/org/neo4j/graphalgo/linkprediction/LinkPrediction.java b/algo/src/main/java/org/neo4j/graphalgo/linkprediction/LinkPrediction.java index 1bc48144d..33f1a29b0 100644 --- a/algo/src/main/java/org/neo4j/graphalgo/linkprediction/LinkPrediction.java +++ b/algo/src/main/java/org/neo4j/graphalgo/linkprediction/LinkPrediction.java @@ -119,6 +119,17 @@ public double totalNeighbors(@Name("node1") Node node1, @Name("node2") Node node return neighborsFinder.findNeighbors(node1, node2, relationshipType, direction).size(); } + @UserFunction("algo.linkprediction.sameCommunity") + @Description("algo.linkprediction.sameCommunity(node1:Node, node2:Node, communityProperty: String) " + + "given two nodes, indicates if they have the same community") + public double sameCommunity(@Name("node1") Node node1, @Name("node2") Node node2, + @Name(value = "communityProperty", defaultValue = "community") String communityProperty) { + if(!node1.hasProperty(communityProperty) || !node2.hasProperty(communityProperty)) { + return 0.0; } + + return node1.getProperty(communityProperty).equals(node2.getProperty(communityProperty)) ? 1.0 : 0.0; + } + private int degree(Node node, RelationshipType relationshipType, Direction direction) { return relationshipType == null ? node.getDegree(direction) : node.getDegree(relationshipType, direction); } diff --git a/tests/src/test/java/org/neo4j/graphalgo/algo/linkprediction/SameCommunityProcIntegrationTest.java b/tests/src/test/java/org/neo4j/graphalgo/algo/linkprediction/SameCommunityProcIntegrationTest.java new file mode 100644 index 000000000..d9171c44d --- /dev/null +++ b/tests/src/test/java/org/neo4j/graphalgo/algo/linkprediction/SameCommunityProcIntegrationTest.java @@ -0,0 +1,130 @@ +/** + * Copyright (c) 2017 "Neo4j, Inc." + * + * This file is part of Neo4j Graph Algorithms . + * + * Neo4j Graph Algorithms is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.graphalgo.algo.linkprediction; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.neo4j.graphalgo.linkprediction.LinkPrediction; +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.graphdb.Result; +import org.neo4j.graphdb.Transaction; +import org.neo4j.graphdb.factory.GraphDatabaseSettings; +import org.neo4j.kernel.impl.proc.Procedures; +import org.neo4j.kernel.internal.GraphDatabaseAPI; +import org.neo4j.test.TestGraphDatabaseFactory; + +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class SameCommunityProcIntegrationTest { + private static final String SETUP = + "CREATE (mark:Person {name: 'Mark'})\n" + + "SET mark.community=1, mark.partition = 4\n" + + "CREATE (michael:Person {name: 'Michael'})\n" + + "SET michael.community=2, michael.partition=4\n" + + "CREATE (praveena:Person {name: 'Praveena'})\n" + + "SET praveena.community=1\n" + + "CREATE (jennifer:Person {name: 'Jennifer'})\n"; + + private static GraphDatabaseService db; + + @BeforeClass + public static void setUp() throws Exception { + db = new TestGraphDatabaseFactory() + .newImpermanentDatabaseBuilder() + .setConfig(GraphDatabaseSettings.procedure_unrestricted,"algo.*") + .newGraphDatabase(); + + ((GraphDatabaseAPI) db).getDependencyResolver() + .resolveDependency(Procedures.class) + .registerFunction(LinkPrediction.class); + + db.execute(SETUP).close(); + } + + @AfterClass + public static void tearDown() { + db.shutdown(); + } + + @Test + public void missingProperty() throws Exception { + String controlQuery = + "MATCH (p1:Person {name: 'Jennifer'})\n" + + "MATCH (p2:Person {name: 'Mark'})\n" + + "RETURN algo.linkprediction.sameCommunity(p1, p2) AS score, " + + " 0.0 AS cypherScore"; + + try (Transaction tx = db.beginTx()) { + Result result = db.execute(controlQuery); + Map node = result.next(); + assertEquals((Double) node.get("cypherScore"), (double) node.get("score"), 0.01); + } + } + + @Test + public void sameCommunity() throws Exception { + String controlQuery = + "MATCH (p1:Person {name: 'Praveena'})\n" + + "MATCH (p2:Person {name: 'Mark'})\n" + + "RETURN algo.linkprediction.sameCommunity(p1, p2) AS score, " + + " 1.0 AS cypherScore"; + + try (Transaction tx = db.beginTx()) { + Result result = db.execute(controlQuery); + Map node = result.next(); + assertEquals((Double) node.get("cypherScore"), (double) node.get("score"), 0.01); + } + } + + @Test + public void differentCommunity() throws Exception { + String controlQuery = + "MATCH (p1:Person {name: 'Michael'})\n" + + "MATCH (p2:Person {name: 'Mark'})\n" + + "RETURN algo.linkprediction.sameCommunity(p1, p2) AS score, " + + " 0.0 AS cypherScore"; + + try (Transaction tx = db.beginTx()) { + Result result = db.execute(controlQuery); + Map node = result.next(); + assertEquals((Double) node.get("cypherScore"), (double) node.get("score"), 0.01); + } + } + + @Test + public void specifyProperty() throws Exception { + String controlQuery = + "MATCH (p1:Person {name: 'Michael'})\n" + + "MATCH (p2:Person {name: 'Mark'})\n" + + "RETURN algo.linkprediction.sameCommunity(p1, p2, 'partition') AS score, " + + " 1.0 AS cypherScore"; + + try (Transaction tx = db.beginTx()) { + Result result = db.execute(controlQuery); + Map node = result.next(); + assertEquals((Double) node.get("cypherScore"), (double) node.get("score"), 0.01); + } + } + + + +}