Skip to content

Commit

Permalink
added microreasoners v.0
Browse files Browse the repository at this point in the history
  • Loading branch information
jbarrasa committed Jun 18, 2018
1 parent cdf2a74 commit 59aa5d3
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 0 deletions.
91 changes: 91 additions & 0 deletions src/main/java/semantics/inference/MicroReasoners.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package semantics.inference;

import org.neo4j.graphdb.*;
import org.neo4j.logging.Log;
import org.neo4j.procedure.*;
import semantics.result.NodeResult;
import semantics.result.RelAndNodeResult;

import java.util.*;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static org.neo4j.graphdb.RelationshipType.withName;

public class MicroReasoners {

static final String sloInferenceCypher = "MATCH (:Label { name: $virtLabel})<-[:SLO*0..]-(sublabel:Label) WITH collect(sublabel.name) + $virtLabel AS subPlusSelf UNWIND subPlusSelf as sublabel RETURN distinct sublabel";
static final String sroInferenceCypher = "MATCH (:Relationship { name: $virtRel})<-[:SRO*0..]-(subRel:Relationship) WITH COLLECT(subRel.name) + $virtRel AS subPlusSelf UNWIND subPlusSelf as subRel RETURN DISTINCT subRel";
@Context
public GraphDatabaseService db;
@Context
public Log log;

@Procedure(mode = Mode.READ)
@Description("semantics.inference.getNodes('virtLabel') - returns all nodes with label 'virtLabel' or its sublabels.")
public Stream<NodeResult> getNodes(@Name("virtLabel") String virtLabel) {

Map<String, Object> params = new HashMap<String, Object>();
params.put("virtLabel", virtLabel);
Result results = db.execute(sloInferenceCypher, params);
StringBuilder sb = new StringBuilder();
boolean isFirstSubLabel = true;
while (results.hasNext()) {
Map<String, Object> result = results.next();
String subLabel = (String) result.get("sublabel");
if (!isFirstSubLabel) sb.append(" UNION "); else isFirstSubLabel = false;
sb.append(" MATCH (x:`").append(subLabel).append("`) RETURN x as result ");
}
if (!sb.toString().isEmpty()) {
return db.execute(sb.toString()).stream().map(n -> (Node) n.get("result")).map(NodeResult::new);
} else {
return null;
}
}

@Procedure(mode = Mode.READ)
@Description("semantics.inference.getRels(node,'virtRel','>') - returns all outgoing relationships of type 'virtRel' " +
"or its subtypes along with the target nodes.")
public Stream<RelAndNodeResult> getRels(@Name("node") Node node, @Name("virtRel") String virtRel,
@Name(value="reldir",defaultValue = "") String directionString) {

Map<String, Object> params = new HashMap<String, Object>();
params.put("virtRel", virtRel);

Result results = db.execute(sroInferenceCypher, params);
Set<RelationshipType> rts = new HashSet<RelationshipType>();
while (results.hasNext()) {
rts.add(withName((String)results.next().get("subRel")));
}

Direction direction = (directionString.equals(">")?Direction.OUTGOING:(directionString.equals("<")?Direction.INCOMING:Direction.BOTH));

return StreamSupport.stream(node.getRelationships(direction, rts.toArray(new RelationshipType[0])).spliterator(),true)
.map(n -> new RelAndNodeResult(n,n.getOtherNode(node)));

}


@UserFunction
@Description("semantics.inference.hasLabel(node,'Label') - checks whether node is explicitly or implicitly labeled as 'Label'.")
public boolean hasLabel(
@Name("node") Node node,
@Name("virtLabel") String virtLabel) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("virtLabel", virtLabel);
Result results = db.execute(sloInferenceCypher, params);
Set<String> sublabels = new HashSet<>();
sublabels.add(virtLabel);
while (results.hasNext()) {
sublabels.add((String)results.next().get("sublabel"));
}
Iterable<Label> labels = node.getLabels();
boolean is = false;
for (Label label : labels) {
is |= sublabels.contains(label.name());
}

return is;
}

}
26 changes: 26 additions & 0 deletions src/main/java/semantics/result/NodeResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package semantics.result;

import org.neo4j.graphdb.Node;

/**
* (taken from APOC)
* @author mh
* @since 26.02.16
*/
public class NodeResult {
public final Node node;

public NodeResult(Node node) {
this.node = node;
}

@Override
public boolean equals(Object o) {
return this == o || o != null && getClass() == o.getClass() && node.equals(((NodeResult) o).node);
}

@Override
public int hashCode() {
return node.hashCode();
}
}
17 changes: 17 additions & 0 deletions src/main/java/semantics/result/RelAndNodeResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package semantics.result;

import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;

public class RelAndNodeResult {


public final Relationship rel;
public final Node node;

public RelAndNodeResult(Relationship rel, Node node) {
this.rel = rel;
this.node = node;
}

}
140 changes: 140 additions & 0 deletions src/test/java/semantics/inference/MicroReasonersTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package semantics.inference;

import org.junit.Rule;
import org.junit.Test;
import org.neo4j.driver.v1.*;
import org.neo4j.harness.junit.Neo4jRule;

import java.util.HashSet;
import java.util.Set;

import static org.junit.Assert.assertEquals;

public class MicroReasonersTest {

@Rule
public Neo4jRule neo4j = new Neo4jRule()
.withProcedure( MicroReasoners.class ).withFunction(MicroReasoners.class);
@Test
public void testGetNodesNoOnto() throws Exception {
try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build().withEncryptionLevel(Config.EncryptionLevel.NONE).toConfig())) {

Session session = driver.session();

session.run("CREATE (b:B {id:'iamb'}) CREATE (a:A {id: 'iama' }) ");
StatementResult results = session.run("CALL semantics.inference.getNodes('B') YIELD node RETURN count(node) as ct, collect(node.id) as nodes");
assertEquals(true, results.hasNext());
Record next = results.next();
Set<String> expectedNodeIds = new HashSet<String>();
expectedNodeIds.add("iamb");
assertEquals(expectedNodeIds,new HashSet<>(next.get("nodes").asList()));
assertEquals(1L, next.get("ct").asLong());
assertEquals(false, results.hasNext());
}
}

@Test
public void testGetNodes() throws Exception {
try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build().withEncryptionLevel(Config.EncryptionLevel.NONE).toConfig())) {

Session session = driver.session();

session.run("CREATE (b:B {id:'iamb'}) CREATE (a:A {id: 'iama' }) ");
session.run("CREATE (b:Label { name: \"B\"}) CREATE (a:Label { name: \"A\"})-[:SLO]->(b) ");
StatementResult results = session.run("CALL semantics.inference.getNodes('B') YIELD node RETURN count(node) as ct, collect(node.id) as nodes");
assertEquals(true, results.hasNext());
Record next = results.next();
Set<String> expectedNodeIds = new HashSet<String>();
expectedNodeIds.add("iama");
expectedNodeIds.add("iamb");
assertEquals(expectedNodeIds,new HashSet<>(next.get("nodes").asList()));
assertEquals(2L, next.get("ct").asLong());
assertEquals(false, results.hasNext());
}
}

@Test
public void testGetRelsNoOnto() throws Exception {
try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build().withEncryptionLevel(Config.EncryptionLevel.NONE).toConfig())) {

Session session = driver.session();

session.run("CREATE (b:B {id:'iamb'})-[:REL1 { prop: 123 }]->(a:A {id: 'iama' }) CREATE (b)-[:REL2 { prop: 456 }]->(a)");
StatementResult results = session.run("MATCH (b:B) CALL semantics.inference.getRels(b,'REL2') YIELD rel, node RETURN b.id as source, type(rel) as relType, rel.prop as propVal, node.id as target");
assertEquals(true, results.hasNext());
Record next = results.next();
assertEquals("iamb", next.get("source").asString());
assertEquals("REL2", next.get("relType").asString());
assertEquals(456L, next.get("propVal").asLong());
assertEquals("iama", next.get("target").asString());
assertEquals(false, results.hasNext());
assertEquals(false,session.run("MATCH (b:B) CALL semantics.inference.getRels(b,'GENERIC') YIELD rel, node RETURN b.id as source, type(rel) as relType, rel.prop as propVal, node.id as target").hasNext());
}
}

@Test
public void testGetRels() throws Exception {
try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build().withEncryptionLevel(Config.EncryptionLevel.NONE).toConfig())) {

Session session = driver.session();

session.run("CREATE (b:B {id:'iamb'})-[:REL1 { prop: 123 }]->(a:A {id: 'iama' }) CREATE (b)-[:REL2 { prop: 456 }]->(a)");
session.run("CREATE (n:Relationship { name: 'REL1'})-[:SRO]->(:Relationship { name: 'GENERIC'})");
StatementResult results = session.run("MATCH (b:B) CALL semantics.inference.getRels(b,'GENERIC','>') YIELD rel, node RETURN b.id as source, type(rel) as relType, rel.prop as propVal, node.id as target");
assertEquals(true, results.hasNext());
Record next = results.next();
assertEquals("iamb", next.get("source").asString());
assertEquals("REL1", next.get("relType").asString());
assertEquals(123L, next.get("propVal").asLong());
assertEquals("iama", next.get("target").asString());
assertEquals(false, results.hasNext());
}
}

@Test
public void testHasLabelNoOnto() throws Exception {
try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build().withEncryptionLevel(Config.EncryptionLevel.NONE).toConfig())) {

Session session = driver.session();

session.run("CREATE (:A {id:'iamA1'}) CREATE (:A {id: 'iamA2' }) CREATE (:B {id: 'iamB1' }) ");
StatementResult results = session.run("MATCH (n) WHERE semantics.inference.hasLabel(n,'A') RETURN count(n) as ct, collect(n.id) as nodes");
assertEquals(true, results.hasNext());
Record next = results.next();
Set<String> expectedNodeIds = new HashSet<String>();
expectedNodeIds.add("iamA1");
expectedNodeIds.add("iamA2");
assertEquals(expectedNodeIds,new HashSet<>(next.get("nodes").asList()));
assertEquals(2L, next.get("ct").asLong());
assertEquals(false, results.hasNext());
assertEquals(false,session.run("MATCH (n:A) WHERE semantics.inference.hasLabel(n,'C') RETURN *").hasNext());
}
}

@Test
public void testHasLabel() throws Exception {
try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build().withEncryptionLevel(Config.EncryptionLevel.NONE).toConfig())) {

Session session = driver.session();

session.run("CREATE (:A {id:'iamA1'}) CREATE (:A {id: 'iamA2' }) CREATE (:B {id: 'iamB1' }) ");
session.run("CREATE (b:Label { name: \"B\"}) CREATE (a:Label { name: \"A\"})-[:SLO]->(b) ");
StatementResult results = session.run("MATCH (n) WHERE semantics.inference.hasLabel(n,'B') RETURN count(n) as ct, collect(n.id) as nodes");
assertEquals(true, results.hasNext());
Record next = results.next();
Set<String> expectedNodeIds = new HashSet<String>();
expectedNodeIds.add("iamA1");
expectedNodeIds.add("iamA2");
expectedNodeIds.add("iamB1");
assertEquals(expectedNodeIds,new HashSet<>(next.get("nodes").asList()));
assertEquals(3L, next.get("ct").asLong());
}
}

//TODO: test modifying the ontology

//TODO: test relationship with directions

//TODO: test use of UDF in return expression

}

0 comments on commit 59aa5d3

Please sign in to comment.