Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 44 additions & 27 deletions reasoner/src/main/java/eu/knowledge/engine/reasoner/BaseRule.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import org.apache.jena.sparql.core.Var;
import org.slf4j.Logger;
Expand All @@ -34,6 +36,11 @@ public class BaseRule {

public static final String ARROW = "->";

/**
* Precalculated hashcode to improve performance of the matching algorithm.
*/
private int hashCodeValue;

/**
* A comparator to make sure the smaller matches collection is ordered from big
* to small.
Expand Down Expand Up @@ -147,6 +154,7 @@ protected BaseRule(Set<TriplePattern> anAntecedent, Set<TriplePattern> aConseque

this.antecedent = anAntecedent;
this.consequent = aConsequent;
this.hashCodeValue = this.calcHashCode();
}

public static Set<Var> getVars(Set<TriplePattern> aPattern) {
Expand Down Expand Up @@ -287,8 +295,7 @@ public String getName() {
return name;
}

@Override
public int hashCode() {
private int calcHashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((antecedent == null) ? 0 : antecedent.hashCode());
Expand All @@ -297,6 +304,11 @@ public int hashCode() {
return result;
}

@Override
public int hashCode() {
return this.hashCodeValue;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
Expand Down Expand Up @@ -393,13 +405,14 @@ public static Map<BaseRule, Set<Match>> getMatches(BaseRule aTargetRule, Set<Bas
Map<TriplePattern, Set<CombiMatch>> combiMatchesPerTriple = getMatchesPerTriplePerRule(targetGP,
new ArrayList<>(someCandidateRules), antecedentOfTarget);

printCombiMatchesPerTriple(combiMatchesPerTriple);

// if not every triple pattern can be matched, we stop the process if we require
// a full match.
if (config.contains(MatchFlag.FULLY_COVERED) && combiMatchesPerTriple.keySet().size() < targetGP.size())
if (targetGP.isEmpty() || (config.contains(MatchFlag.FULLY_COVERED)
&& combiMatchesPerTriple.keySet().size() < targetGP.size()))
return new HashMap<>();

printCombiMatchesPerTriple(aTargetRule, combiMatchesPerTriple);

List<CombiMatch> biggestMatches = new ArrayList<>();
List<CombiMatch> smallerMatches = new ArrayList<>();
List<CombiMatch> toBeAddedToBiggestMatches = null, toBeAddedToSmallerMatches = null;
Expand Down Expand Up @@ -453,31 +466,36 @@ public static Map<BaseRule, Set<Match>> getMatches(BaseRule aTargetRule, Set<Bas
// we need to sort the smaller matches on size (from big to small)
// to make sure the isSubCombiMatch method works correctly in this algo

// try to merge with smaller combi matches
for (CombiMatch aSmallerMatch : smallerMatches) {
CombiMatch newCombiMatch = mergeCombiMatches(candidateCombiMatch, aSmallerMatch, config);
if (newCombiMatch != null) {
// merge successful, add to smaller matches
if (candidateWasMerged) {
if (isSubCombiMatch(newCombiMatch, toBeAddedToBiggestMatches)) {
toBeAddedToSmallerMatches.add(newCombiMatch);
} else {
toBeAddedToBiggestMatches.add(newCombiMatch);
}
// do this 'costly' merge operation in parallel
var newCombiMatches = smallerMatches.stream().parallel().map(aSmallerMatch -> {
return mergeCombiMatches(candidateCombiMatch, aSmallerMatch, config);
}).filter(Objects::nonNull).sorted(new CombiMatchSizeComparator()).collect(Collectors.toList());

// determine where to add new combi matches
for (CombiMatch newCombiMatch : newCombiMatches) {

// merge successful, add to smaller matches
if (candidateWasMerged) {
if (isSubCombiMatch(newCombiMatch, toBeAddedToBiggestMatches)) {
toBeAddedToSmallerMatches.add(newCombiMatch);
} else {
// add to biggest matches
candidateWasMerged = true;
toBeAddedToBiggestMatches.add(newCombiMatch);
candidateWasMerged = true;
}

} else {
// add to biggest matches
candidateWasMerged = true;
toBeAddedToBiggestMatches.add(newCombiMatch);
}
}
}

if (!candidateWasMerged && !config.contains(MatchFlag.FULLY_COVERED))
toBeAddedToBiggestMatches.add(candidateCombiMatch);
else
toBeAddedToSmallerMatches.add(candidateCombiMatch);
if (!config.contains(MatchFlag.FULLY_COVERED)) {
if (!candidateWasMerged)
toBeAddedToBiggestMatches.add(candidateCombiMatch);
else
toBeAddedToSmallerMatches.add(candidateCombiMatch);
}
}

// update collections
Expand All @@ -494,8 +512,6 @@ public static Map<BaseRule, Set<Match>> getMatches(BaseRule aTargetRule, Set<Bas
// add all toBeAddedMatches
biggestMatches.addAll(toBeAddedToBiggestMatches);
smallerMatches.addAll(toBeAddedToSmallerMatches);

Collections.sort(smallerMatches, new CombiMatchSizeComparator());
}

toBeAddedToBiggestMatches = null;
Expand Down Expand Up @@ -538,7 +554,8 @@ private static boolean isSubCombiMatch(CombiMatch aSmallerMatch, List<CombiMatch
return false;
}

private static void printCombiMatchesPerTriple(Map<TriplePattern, Set<CombiMatch>> combiMatchesPerTriple) {
private static void printCombiMatchesPerTriple(BaseRule aTargetRule,
Map<TriplePattern, Set<CombiMatch>> combiMatchesPerTriple) {
StringBuilder sb = new StringBuilder();

int total = 1;
Expand All @@ -547,7 +564,7 @@ private static void printCombiMatchesPerTriple(Map<TriplePattern, Set<CombiMatch
sb.append(combiMatch.size()).append(" * ");
}

LOG.trace("{} = {}", total, sb.toString());
LOG.trace("{}: {} = {}", aTargetRule.getName(), total, sb.toString());

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,13 +267,14 @@ private RuleNode createOrGetReasonerNode(BaseRule aRule, BaseRule aParent) {
// determine whether our parent matches us partially
boolean ourAntecedentFullyMatchesParentConsequent = false;

if (aParent != null && this.store.getAntecedentNeighbors(aRule, this.matchConfig).containsKey(aParent)) {
Map<BaseRule, Set<Match>> antecedentNeighbors = this.store.getAntecedentNeighbors(aRule, this.matchConfig);
if (aParent != null && antecedentNeighbors.containsKey(aParent)) {
ourAntecedentFullyMatchesParentConsequent = antecedentFullyMatchesConsequent(aRule, aParent,
this.store.getAntecedentNeighbors(aRule, this.matchConfig).get(aParent));
antecedentNeighbors.get(aParent));
}

if (!ourAntecedentFullyMatchesParentConsequent) {
this.store.getAntecedentNeighbors(aRule, this.matchConfig).forEach((rule, matches) -> {
antecedentNeighbors.forEach((rule, matches) -> {
if (!(rule instanceof ProactiveRule)) {
assert reasonerNode instanceof AntSide;
var newNode = createOrGetReasonerNode(rule, aRule);
Expand Down Expand Up @@ -357,4 +358,9 @@ public RuleStore getStore() {
return this.store;
}

@Override
public String toString() {
return "ReasonerPlan [link=" + this.store.getGraphVizCode(this, true) + "]";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -69,7 +70,7 @@ public void addRules(Set<BaseRule> someRules) {
*/
public Set<BaseRule> getRules() {

return this.ruleToRuleNode.values().stream().map(rn -> rn.getRule()).collect(Collectors.toSet());
return this.ruleToRuleNode.keySet();
}

/**
Expand Down Expand Up @@ -155,30 +156,34 @@ public void reset() {
}
}

public void printGraphVizCode(ReasonerPlan aPlan) {
LOG.info(getGraphVizCode(aPlan, false));
}

/**
* Prints all the rules and the connections between them in GraphViz encoding.
* Use code in: {@link http://viz-js.com/}
* Use code in: {@link https://dreampuf.github.io/GraphvizOnline/}
*/
public void printGraphVizCode(ReasonerPlan aPlan) {
public void printGraphVizCode(ReasonerPlan aPlan, boolean urlOnly) {
LOG.info(getGraphVizCode(aPlan, urlOnly));
}

public String getGraphVizCode(ReasonerPlan aPlan, boolean urlOnly) {

String color = "red";
String width = "2";

StringBuilder sb = new StringBuilder();

sb.append("digraph {\n");
sb.append("strict digraph {\n");
Map<BaseRule, String> ruleToName = new HashMap<>();

int ruleNumber = 1;

for (MatchNode r : ruleToRuleNode.values()) {

String currentName = ruleToName.get(r.getRule());
boolean sourceInPlan = false, destInPlan = false;
if (currentName == null) {
currentName = /* "rule" + ruleNumber; */ generateName(r.getRule());
assert !currentName.isEmpty();
ruleNumber++;
String replaceAll = toStringRule(r.getRule()).replaceAll("\\\"", "\\\\\"");

// check the colouring
Expand All @@ -187,7 +192,6 @@ public void printGraphVizCode(ReasonerPlan aPlan) {
RuleNode rn = aPlan.getRuleNodeForRule(r.getRule());
if (rn != null) {
pen = "color=\"" + color + "\", penwidth=\"" + width + "\",";
sourceInPlan = true;
}
}

Expand All @@ -201,16 +205,17 @@ public void printGraphVizCode(ReasonerPlan aPlan) {
ruleToName.put(r.getRule(), currentName);

}

Map<BaseRule, Set<Match>> antecedentNeighbors = r.getAntecedentNeighbors();
Set<BaseRule> anteNeigh = antecedentNeighbors.keySet();
String neighName;

for (BaseRule neighR : anteNeigh) {
neighName = ruleToName.get(neighR);

if (neighName == null) {
neighName = /* "rule" + ruleNumber; */ generateName(neighR);
assert !neighName.isEmpty();
ruleNumber++;
String replaceAll = toStringRule(neighR).replaceAll("\\\"", "\\\\\"");

// check the colouring
Expand All @@ -219,7 +224,6 @@ public void printGraphVizCode(ReasonerPlan aPlan) {
RuleNode rn = aPlan.getRuleNodeForRule(neighR);
if (rn != null) {
pen = "color=\"" + color + "\", penwidth=\"" + width + "\",";
destInPlan = true;
}
}

Expand All @@ -230,6 +234,7 @@ public void printGraphVizCode(ReasonerPlan aPlan) {

sb.append(neighName).append("[").append(shape).append(pen).append("tooltip=").append("\"")
.append(replaceAll).append("\"").append("]").append("\n");

ruleToName.put(neighR, neighName);
}

Expand All @@ -251,9 +256,9 @@ public void printGraphVizCode(ReasonerPlan aPlan) {

sb.append("}");

LOG.info("Visualize on website: https://dreampuf.github.io/GraphvizOnline/#"
+ URLEncoder.encode(sb.toString(), StandardCharsets.UTF_8).replaceAll("\\+", "%20") + "\n"
+ sb.toString());
return "Visualize on website: https://dreampuf.github.io/GraphvizOnline/#"
+ URLEncoder.encode(sb.toString(), StandardCharsets.UTF_8).replaceAll("\\+", "%20")
+ (urlOnly ? "" : "\n" + sb.toString());
}

private String toStringRule(BaseRule neighR) {
Expand All @@ -277,6 +282,7 @@ private String trimAtLength(String aString, int aLength) {
*
* @param r
* @return
* @throws NoSuchAlgorithmException
*/
private String generateName(BaseRule r) {

Expand All @@ -302,7 +308,29 @@ private String generateName(BaseRule r) {

String consequent = trimAtLength(sb.toString(), MAX_STR_LENGTH);

return "\"" + Integer.toHexString(r.hashCode()) + "\\n" + antecedent + "->\\n" + consequent + "\"";
String name = r.getName();
MessageDigest digest;
byte[] encodedhash = new byte[0];
try {
digest = MessageDigest.getInstance("SHA-256");
encodedhash = digest.digest(name.getBytes(StandardCharsets.UTF_8));
} catch (NoSuchAlgorithmException e) {
LOG.error("{}", e);
}

return "\"" + bytesToHex(encodedhash) + "\\n" + antecedent + "->\\n" + consequent + "\"";
}

private static String bytesToHex(byte[] hash) {
StringBuilder hexString = new StringBuilder(2 * hash.length);
for (int i = 0; i < hash.length; i++) {
String hex = Integer.toHexString(0xff & hash[i]);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}

private String generateName(TriplePattern tp) {
Expand Down
Loading