Merge branch 'thinker' of github.com:OpenSPG/openspg into thinker_syntax

This commit is contained in:
kejian 2024-04-24 16:12:43 +08:00
commit 2f5cd46b12
21 changed files with 372 additions and 106 deletions

View File

@ -1,12 +1,13 @@
package com.antgroup.openspg.reasoner.thinker;
import com.antgroup.openspg.reasoner.thinker.logic.Result;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Element;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Triple;
import java.util.List;
import java.util.Map;
public interface Thinker<K> {
void init(Map<String, String> params);
List<Triple> find(Element s, Element p, Element o);
Result find(Element s, Element p, Element o);
Result find(Element s, Element p, Element o, Map<String, Object> context);
}

View File

@ -0,0 +1,19 @@
package com.antgroup.openspg.reasoner.thinker;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Element;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Entity;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Triple;
import java.util.List;
import java.util.Map;
public interface TripleStore {
void init(Map<String, String> param);
List<Triple> find(Element s, Element p, Element o);
void addEntity(Entity entity);
void addTriple(Triple triple);
void clear();
}

View File

@ -0,0 +1,15 @@
package com.antgroup.openspg.reasoner.thinker.catalog;
import com.antgroup.openspg.reasoner.lube.catalog.Catalog;
import com.antgroup.openspg.reasoner.thinker.logic.LogicNetwork;
public abstract class LogicCatalog extends Catalog {
private LogicNetwork logicNetwork;
public void init() {
super.init();
logicNetwork = loadLogicNetwork();
}
public abstract LogicNetwork loadLogicNetwork();
}

View File

@ -1,99 +1,36 @@
package com.antgroup.openspg.reasoner.thinker.engine;
import com.antgroup.openspg.reasoner.common.constants.Constants;
import com.antgroup.openspg.reasoner.common.graph.edge.Direction;
import com.antgroup.openspg.reasoner.common.graph.edge.IEdge;
import com.antgroup.openspg.reasoner.common.graph.property.IProperty;
import com.antgroup.openspg.reasoner.common.graph.vertex.IVertex;
import com.antgroup.openspg.reasoner.graphstate.GraphState;
import com.antgroup.openspg.reasoner.thinker.Thinker;
import com.antgroup.openspg.reasoner.thinker.logic.graph.*;
import java.util.*;
import com.antgroup.openspg.reasoner.thinker.logic.Result;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Element;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class DefaultThinker<K> implements Thinker<K> {
private GraphState<K> graphState;
private GraphStore<K> graphStore;
public DefaultThinker(GraphState<K> graphState) {
this.graphState = graphState;
this.graphStore = new GraphStore<>(graphState);
}
@Override
public void init(Map<String, String> params) {
this.graphState.init(params);
this.graphStore.init(params);
}
@Override
public List<Triple> find(Element s, Element p, Element o) {
if (s instanceof Entity) {
return match((Entity<K>) s, p, o, Direction.OUT);
} else if (o instanceof Entity) {
return match((Entity<K>) o, p, s, Direction.IN);
} else {
throw new RuntimeException("Cannot support " + s);
}
public Result find(Element s, Element p, Element o) {
Result result = new Result();
List<Element> data = new LinkedList<>();
data.addAll(this.graphStore.find(s, p, o));
result.setData(data);
return result;
}
private List<Triple> match(Entity<K> s, Element p, Element o, Direction direction) {
IVertex<K, IProperty> vertex = this.graphState.getVertex(s.getId(), null);
List<IEdge<K, IProperty>> edges;
if (p instanceof Any) {
edges = this.graphState.getEdges(s.getId(), null, null, null, direction);
} else if (p instanceof Predicate) {
Set<String> types = new HashSet<>();
types.add(((Predicate) p).getName());
edges = this.graphState.getEdges(s.getId(), null, null, types, direction);
} else {
throw new RuntimeException("Cannot support " + p);
}
return match(s, p, o, vertex, edges);
}
private List<Triple> match(
Entity s,
Element p,
Element o,
IVertex<K, IProperty> vertex,
List<IEdge<K, IProperty>> edges) {
List<Triple> triples = new LinkedList<>();
for (String key : vertex.getValue().getKeySet()) {
if (p instanceof Any || ((Predicate) p).getName().equalsIgnoreCase(key)) {
triples.add(new Triple(s, new Predicate(key), new Value(key, vertex.getValue().get(key))));
}
}
for (IEdge<K, IProperty> edge : edges) {
if (p instanceof Any || ((Predicate) p).getName().equalsIgnoreCase(edge.getType())) {
if (o instanceof Entity) {
if (edge.getTargetId().equals(((Entity<?>) o).getId())) {
triples.add(edgeToTriple(edge));
}
} else if (o instanceof Node) {
if (edge.getValue().get(Constants.EDGE_TO_ID_TYPE_KEY).equals(((Node) o).getType())) {
triples.add(edgeToTriple(edge));
}
} else if (o instanceof Any) {
triples.add(edgeToTriple(edge));
}
}
}
return triples;
}
private Triple edgeToTriple(IEdge<K, IProperty> edge) {
if (edge.getDirection() == Direction.OUT) {
return new Triple(
new Entity(
edge.getSourceId(), (String) edge.getValue().get(Constants.EDGE_FROM_ID_TYPE_KEY)),
new Predicate(edge.getType()),
new Entity(
edge.getTargetId(), (String) edge.getValue().get(Constants.EDGE_TO_ID_TYPE_KEY)));
} else {
return new Triple(
new Entity(
edge.getTargetId(), (String) edge.getValue().get(Constants.EDGE_TO_ID_TYPE_KEY)),
new Predicate(edge.getType()),
new Entity(
edge.getSourceId(), (String) edge.getValue().get(Constants.EDGE_FROM_ID_TYPE_KEY)));
}
@Override
public Result find(Element s, Element p, Element o, Map<String, Object> context) {
return null;
}
}

View File

@ -0,0 +1,96 @@
package com.antgroup.openspg.reasoner.thinker.engine;
import com.antgroup.openspg.reasoner.common.constants.Constants;
import com.antgroup.openspg.reasoner.common.graph.edge.Direction;
import com.antgroup.openspg.reasoner.common.graph.edge.IEdge;
import com.antgroup.openspg.reasoner.common.graph.property.IProperty;
import com.antgroup.openspg.reasoner.common.graph.vertex.IVertex;
import com.antgroup.openspg.reasoner.graphstate.GraphState;
import com.antgroup.openspg.reasoner.thinker.logic.graph.*;
import java.util.*;
public class GraphStore<K> {
private GraphState graphState;
public GraphStore(GraphState<K> graphState) {
this.graphState = graphState;
}
public void init(Map<String, String> param) {
this.graphState.init(param);
}
public List<Triple> find(Element s, Element p, Element o) {
if (s instanceof Entity) {
return match((Entity<K>) s, p, o, Direction.OUT);
} else if (o instanceof Entity) {
return match((Entity<K>) o, p, s, Direction.IN);
} else {
throw new RuntimeException("Cannot support " + s);
}
}
private List<Triple> match(Entity<K> s, Element p, Element o, Direction direction) {
IVertex<K, IProperty> vertex = this.graphState.getVertex(s.getId(), null);
List<IEdge<K, IProperty>> edges;
if (p instanceof Any) {
edges = this.graphState.getEdges(s.getId(), null, null, null, direction);
} else if (p instanceof Predicate) {
Set<String> types = new HashSet<>();
types.add(((Predicate) p).getName());
edges = this.graphState.getEdges(s.getId(), null, null, types, direction);
} else {
throw new RuntimeException("Cannot support " + p);
}
return match(s, p, o, vertex, edges);
}
private List<Triple> match(
Entity s,
Element p,
Element o,
IVertex<K, IProperty> vertex,
List<IEdge<K, IProperty>> edges) {
List<Triple> triples = new LinkedList<>();
for (String key : vertex.getValue().getKeySet()) {
if (p instanceof Any || ((Predicate) p).getName().equalsIgnoreCase(key)) {
triples.add(new Triple(s, new Predicate(key), new Value(key, vertex.getValue().get(key))));
}
}
for (IEdge<K, IProperty> edge : edges) {
if (p instanceof Any || ((Predicate) p).getName().equalsIgnoreCase(edge.getType())) {
if (o instanceof Entity) {
if (edge.getTargetId().equals(((Entity<?>) o).getId())) {
triples.add(edgeToTriple(edge));
}
} else if (o instanceof Node) {
if (edge.getValue().get(Constants.EDGE_TO_ID_TYPE_KEY).equals(((Node) o).getType())) {
triples.add(edgeToTriple(edge));
}
} else if (o instanceof Any) {
triples.add(edgeToTriple(edge));
}
}
}
return triples;
}
private Triple edgeToTriple(IEdge<K, IProperty> edge) {
if (edge.getDirection() == Direction.OUT) {
return new Triple(
new Entity(
edge.getSourceId(), (String) edge.getValue().get(Constants.EDGE_FROM_ID_TYPE_KEY)),
new Predicate(edge.getType()),
new Entity(
edge.getTargetId(), (String) edge.getValue().get(Constants.EDGE_TO_ID_TYPE_KEY)));
} else {
return new Triple(
new Entity(
edge.getTargetId(), (String) edge.getValue().get(Constants.EDGE_TO_ID_TYPE_KEY)),
new Predicate(edge.getType()),
new Entity(
edge.getSourceId(), (String) edge.getValue().get(Constants.EDGE_FROM_ID_TYPE_KEY)));
}
}
}

View File

@ -0,0 +1,48 @@
package com.antgroup.openspg.reasoner.thinker.engine;
import com.antgroup.openspg.reasoner.thinker.TripleStore;
import com.antgroup.openspg.reasoner.thinker.logic.LogicNetwork;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Element;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Entity;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Triple;
import com.antgroup.openspg.reasoner.thinker.logic.rule.Rule;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class InfTripleStore implements TripleStore {
private LogicNetwork logicNetwork;
private MemTripleStore tripleStore;
public InfTripleStore(LogicNetwork logicNetwork, MemTripleStore tripleStore) {
this.logicNetwork = logicNetwork;
this.tripleStore = tripleStore;
}
@Override
public void init(Map<String, String> param) {}
@Override
public List<Triple> find(Element s, Element p, Element o) {
Collection<Rule> rules = logicNetwork.getForwardRules(s);
if (rules.isEmpty()) {
return new LinkedList<>();
}
return null;
}
@Override
public void addEntity(Entity entity) {
this.tripleStore.addEntity(entity);
}
public void addTriple(Triple triple) {
this.tripleStore.addTriple(triple);
}
@Override
public void clear() {
this.tripleStore.clear();
}
}

View File

@ -0,0 +1,28 @@
package com.antgroup.openspg.reasoner.thinker.engine;
import com.antgroup.openspg.reasoner.thinker.TripleStore;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Element;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Entity;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Triple;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class MemTripleStore implements TripleStore {
@Override
public void init(Map<String, String> param) {}
@Override
public List<Triple> find(Element s, Element p, Element o) {
return Collections.emptyList();
}
@Override
public void addEntity(Entity entity) {}
@Override
public void addTriple(Triple triple) {}
@Override
public void clear() {}
}

View File

@ -0,0 +1,51 @@
package com.antgroup.openspg.reasoner.thinker.logic;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Element;
import com.antgroup.openspg.reasoner.thinker.logic.rule.ClauseEntry;
import com.antgroup.openspg.reasoner.thinker.logic.rule.Rule;
import java.util.*;
import java.util.stream.Collectors;
import lombok.Data;
@Data
public class LogicNetwork {
private Map<Element, Map<Element, Rule>> forwardRules;
private Map<Element, Map<List<Element>, Rule>> backwardRules;
public LogicNetwork() {
this.forwardRules = new HashMap<>();
this.backwardRules = new HashMap<>();
}
public void addRule(Rule rule) {
for (ClauseEntry body : rule.getBody()) {
Map<Element, Rule> rules =
forwardRules.computeIfAbsent(body.toElement(), (key) -> new HashMap<>());
rules.put(rule.getHead().toElement(), rule);
}
Map<List<Element>, Rule> rules =
backwardRules.computeIfAbsent(rule.getHead().toElement(), (key) -> new HashMap<>());
rules.put(
rule.getBody().stream().map(ClauseEntry::toElement).collect(Collectors.toList()), rule);
}
public Collection<Rule> getForwardRules(Element e) {
Set<Rule> rules = new HashSet<>();
for (Map.Entry<Element, Map<Element, Rule>> entry : forwardRules.entrySet()) {
if (entry.getKey().matches(e)) {
rules.addAll(entry.getValue().values());
}
}
return rules;
}
public Collection<Rule> getBackwardRules(Element e) {
Set<Rule> rules = new HashSet<>();
for (Map.Entry<Element, Map<List<Element>, Rule>> entry : backwardRules.entrySet()) {
if (entry.getKey().matches(e)) {
rules.addAll(entry.getValue().values());
}
}
return rules;
}
}

View File

@ -0,0 +1,12 @@
package com.antgroup.openspg.reasoner.thinker.logic;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Element;
import com.antgroup.openspg.reasoner.thinker.logic.rule.TreeLogger;
import java.util.List;
import lombok.Data;
@Data
public class Result {
private List<Element> data;
private TreeLogger traceLog;
}

View File

@ -12,4 +12,11 @@
*/
package com.antgroup.openspg.reasoner.thinker.logic.graph;
public class Any implements Element {}
public class Any extends Element {
public static final Element ANY = new Any();
@Override
public boolean matches(Element other) {
return other != null;
}
}

View File

@ -15,4 +15,8 @@ package com.antgroup.openspg.reasoner.thinker.logic.graph;
import java.io.Serializable;
public interface Element extends Serializable {}
public abstract class Element implements Serializable {
public boolean matches(Element other) {
return equals(other);
}
}

View File

@ -16,7 +16,7 @@ import java.util.Objects;
import lombok.Data;
@Data
public class Entity<K> implements Element {
public class Entity<K> extends Element {
private K id;
private String type;

View File

@ -16,7 +16,7 @@ import java.util.Objects;
import lombok.Data;
@Data
public class Node implements Element {
public class Node extends Element {
private String type;
private Node() {}

View File

@ -3,7 +3,7 @@ package com.antgroup.openspg.reasoner.thinker.logic.graph;
import lombok.Data;
@Data
public class Predicate implements Element {
public class Predicate extends Element {
private String name;
public Predicate() {}

View File

@ -12,7 +12,7 @@
*/
package com.antgroup.openspg.reasoner.thinker.logic.graph;
public class Triple implements Element {
public class Triple extends Element {
private Element subject;
private Element predicate;
private Element object;
@ -25,6 +25,25 @@ public class Triple implements Element {
this.object = object;
}
@Override
public boolean matches(Element other) {
if (other instanceof Triple) {
return subject.matches(((Triple) other).subject)
&& predicate.matches(((Triple) other).predicate)
&& object.matches(((Triple) other).object);
} else {
return false;
}
}
public static Triple create(Element s, Element p, Element o) {
return new Triple(nullToAny(s), nullToAny(p), nullToAny(o));
}
private static Element nullToAny(Element n) {
return n == null ? Any.ANY : n;
}
/**
* Getter method for property <tt>subject</tt>.
*

View File

@ -3,7 +3,7 @@ package com.antgroup.openspg.reasoner.thinker.logic.graph;
import lombok.Data;
@Data
public class Value implements Element {
public class Value extends Element {
private String name;
private Object val;

View File

@ -1,5 +1,8 @@
package com.antgroup.openspg.reasoner.thinker.logic.rule;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Element;
import java.io.Serializable;
public interface ClauseEntry extends Serializable {}
public interface ClauseEntry extends Serializable {
Element toElement();
}

View File

@ -1,11 +1,17 @@
package com.antgroup.openspg.reasoner.thinker.logic.rule;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Element;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Entity;
import java.util.Objects;
public class EntityPattern<K> implements ClauseEntry {
private Entity<K> entity;
@Override
public Element toElement() {
return entity;
}
public EntityPattern() {}
public EntityPattern(Entity<K> entity) {

View File

@ -28,13 +28,19 @@ public class TreeLogger implements Serializable {
}
public TreeLogger log(Object msg) {
if (this.currentNodeMsg == null) this.currentNodeMsg = new StringBuilder();
if (msg != null) this.currentNodeMsg.append(msg);
if (this.currentNodeMsg == null) {
this.currentNodeMsg = new StringBuilder();
}
if (msg != null) {
this.currentNodeMsg.append(msg);
}
return this;
}
public TreeLogger addChild(String name) {
if (this.children == null) this.children = new ArrayList<TreeLogger>();
if (this.children == null) {
this.children = new ArrayList<>();
}
TreeLogger ret = new TreeLogger(name);
this.children.add(ret);
return ret;
@ -43,7 +49,7 @@ public class TreeLogger implements Serializable {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
genLog(sb, this, 0, false, new HashSet<Integer>());
genLog(sb, this, 0, false, new HashSet<>());
return sb.toString();
}
@ -64,16 +70,24 @@ public class TreeLogger implements Serializable {
sb.append(IDENT);
}
}
if (level != 0)
if (hasNextSibling) sb.append(CON);
else sb.append(END_CON);
if (level != 0) {
if (hasNextSibling) {
sb.append(CON);
} else {
sb.append(END_CON);
}
}
sb.append(cur.currentNodeName);
if (cur.currentNodeMsg != null) sb.append(": ").append(cur.currentNodeMsg);
if (cur.currentNodeMsg != null) {
sb.append(": ").append(cur.currentNodeMsg);
}
sb.append('\n');
Set<Integer> childrenVerts = new HashSet<Integer>(vertIdentIdxes);
if (hasNextSibling) childrenVerts.add(level * 2 - 1);
Set<Integer> childrenVerts = new HashSet<>(vertIdentIdxes);
if (hasNextSibling) {
childrenVerts.add(level * 2 - 1);
}
if (cur.children != null && !cur.children.isEmpty()) {
for (int i = 0; i < cur.children.size(); i++) {
TreeLogger c = cur.children.get(i);

View File

@ -1,5 +1,6 @@
package com.antgroup.openspg.reasoner.thinker.logic.rule;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Element;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Triple;
public class TriplePattern implements ClauseEntry {
@ -11,6 +12,11 @@ public class TriplePattern implements ClauseEntry {
this.triple = triple;
}
@Override
public Element toElement() {
return triple;
}
/**
* Getter method for property <tt>triple</tt>.
*

View File

@ -10,8 +10,8 @@ import com.antgroup.openspg.reasoner.graphstate.GraphState;
import com.antgroup.openspg.reasoner.graphstate.impl.MemGraphState;
import com.antgroup.openspg.reasoner.thinker.engine.DefaultThinker;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Any;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Element;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Entity;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Triple;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
@ -74,16 +74,16 @@ public class DefaultThinkerTests {
@Test
public void testFindForward() {
Thinker thinker = new DefaultThinker(buildGraphState());
List<Triple> triples =
thinker.find(new Entity<>(IVertexId.from("a1", "A"), "A"), new Any(), new Any());
List<Element> triples =
thinker.find(new Entity<>(IVertexId.from("a1", "A"), "A"), new Any(), new Any()).getData();
Assert.assertTrue(triples.size() == 1);
}
@Test
public void testBackForward() {
Thinker thinker = new DefaultThinker(buildGraphState());
List<Triple> triples =
thinker.find(new Any(), new Any(), new Entity<>(IVertexId.from("b", "B"), "B"));
List<Element> triples =
thinker.find(new Any(), new Any(), new Entity<>(IVertexId.from("b", "B"), "B")).getData();
Assert.assertTrue(triples.size() == 2);
}
}