mirror of
https://github.com/OpenSPG/openspg.git
synced 2025-12-12 07:41:27 +00:00
feat(reasoner): add thinker
This commit is contained in:
parent
7211dc6c1c
commit
7db5fab22c
@ -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);
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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) {}
|
||||
}
|
||||
@ -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<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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() {}
|
||||
|
||||
@ -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() {}
|
||||
|
||||
@ -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>.
|
||||
*
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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>.
|
||||
*
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user