feat(reasoner): add thinker

This commit is contained in:
FishJoy 2024-04-23 13:51:15 +08:00
parent 7211dc6c1c
commit 7db5fab22c
17 changed files with 284 additions and 101 deletions

View File

@ -0,0 +1,12 @@
package com.antgroup.openspg.reasoner.thinker;
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 TripleStore {
void init(Map<String, String> param);
List<Triple> find(Element s, Element p, Element o);
}

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,26 @@
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.graph.Element;
import com.antgroup.openspg.reasoner.thinker.logic.graph.Triple;
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);
}
}
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)));
}
return this.graphStore.find(s, p, o);
}
}

View File

@ -0,0 +1,97 @@
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.TripleStore;
import com.antgroup.openspg.reasoner.thinker.logic.graph.*;
import java.util.*;
public class GraphStore<K> implements TripleStore {
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,27 @@
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.Triple;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class InfTripleStore implements TripleStore {
private LogicNetwork logicNetwork;
public InfTripleStore(LogicNetwork logicNetwork) {
this.logicNetwork = logicNetwork;
}
@Override
public void init(Map<String, String> param) {}
@Override
public List<Triple> find(Element s, Element p, Element o) {
return Collections.emptyList();
}
public void addTriple(Triple triple) {}
}

View File

@ -0,0 +1,47 @@
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) {
if (forwardRules.containsKey(e)) {
return forwardRules.get(e).values();
} else {
return new ArrayList<>();
}
}
public Collection<Rule> getBackwardRules(Element e) {
if (backwardRules.containsKey(e)) {
return backwardRules.get(e).values();
} else {
return new ArrayList<>();
}
}
}

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

@ -12,12 +12,11 @@
*/
package com.antgroup.openspg.reasoner.thinker.logic.graph;
import java.util.Objects;
import lombok.Data;
import java.util.Objects;
@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>.
*