Skip to content
Open
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
140 changes: 73 additions & 67 deletions src/main/java/be/ugent/rml/MappingOptimizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,88 +64,94 @@ private void eliminateSelfJoins() {
for (Quad refObjectMapQuad : refObjectMapsQuads) {
Term parentTriplesMap = refObjectMapQuad.getObject();
Term childObjectMap = refObjectMapQuad.getSubject();
Term parentLogicalSource = Utils.getObjectsFromQuads(rmlStore.getQuads(parentTriplesMap, new NamedNode(NAMESPACES.RML2 + "logicalSource"), null)).get(0);
Term childPredicateObjectMap = Utils.getSubjectsFromQuads(rmlStore.getQuads(null, new NamedNode(NAMESPACES.RML2 + "objectMap"), childObjectMap)).get(0);
Term childTriplesMap = Utils.getSubjectsFromQuads(rmlStore.getQuads(null, new NamedNode(NAMESPACES.RML2 + "predicateObjectMap"), childPredicateObjectMap)).get(0);
Term childLogicalSource = Utils.getObjectsFromQuads(rmlStore.getQuads(childTriplesMap, new NamedNode(NAMESPACES.RML2 + "logicalSource"), null)).get(0);

// check if the logical sources are the same
if (childLogicalSource.equals(parentLogicalSource)) {

List<Term> joinConditions = Utils.getObjectsFromQuads(rmlStore.getQuads(childObjectMap, new NamedNode(NAMESPACES.RML2 + "joinCondition"), null));
try {
Term parentLogicalSource = Utils.getObjectsFromQuads(rmlStore.getQuads(parentTriplesMap, new NamedNode(NAMESPACES.RML2 + "logicalSource"), null)).get(0);
Term childPredicateObjectMap = Utils.getSubjectsFromQuads(rmlStore.getQuads(null, new NamedNode(NAMESPACES.RML2 + "objectMap"), childObjectMap)).get(0);
Term childTriplesMap = Utils.getSubjectsFromQuads(rmlStore.getQuads(null, new NamedNode(NAMESPACES.RML2 + "predicateObjectMap"), childPredicateObjectMap)).get(0);
Term childLogicalSource = Utils.getObjectsFromQuads(rmlStore.getQuads(childTriplesMap, new NamedNode(NAMESPACES.RML2 + "logicalSource"), null)).get(0);

List<Term> parentSubjectMaps = Utils.getObjectsFromQuads(rmlStore.getQuads(parentTriplesMap, new NamedNode(NAMESPACES.RML2 + "subjectMap"), null));
Term parentSubjectMap = null;
if (!parentSubjectMaps.isEmpty()) {
parentSubjectMap = parentSubjectMaps.get(0);
}
// check if the logical sources are the same
if (childLogicalSource.equals(parentLogicalSource)) {

boolean safeSelfJoinElimination = true;

// if no join condition, we can safely eliminate the self-join
// else we need more checks
if (parentSubjectMap != null && !joinConditions.isEmpty()) {
// we can eliminate a self-join when all join conditions have equal references and all references for the parent subject or all reference for the related child triple come back in the join conditions
// 1. check if all join references are equal
List<String> joinReferences = new ArrayList<>();
for (Term joinCondition : joinConditions) {
String parent = getObjectsFromQuads(rmlStore.getQuads(joinCondition, new NamedNode(NAMESPACES.RML2 + "parent"), null)).get(0).getValue();
String child = getObjectsFromQuads(rmlStore.getQuads(joinCondition, new NamedNode(NAMESPACES.RML2 + "child"), null)).get(0).getValue();
if (child.equals(parent)) {
joinReferences.add(child);
} else {
safeSelfJoinElimination = false;
}
List<Term> joinConditions = Utils.getObjectsFromQuads(rmlStore.getQuads(childObjectMap, new NamedNode(NAMESPACES.RML2 + "joinCondition"), null));

List<Term> parentSubjectMaps = Utils.getObjectsFromQuads(rmlStore.getQuads(parentTriplesMap, new NamedNode(NAMESPACES.RML2 + "subjectMap"), null));
Term parentSubjectMap = null;
if (!parentSubjectMaps.isEmpty()) {
parentSubjectMap = parentSubjectMaps.get(0);
}
if (safeSelfJoinElimination) {
// 2. check if all references for the parent subject come back in the join conditions
boolean safeTerms = hasSafeReferences(parentSubjectMap, joinReferences);
if(!safeTerms) {
// if not all references for the parent subject come back in the join conditions,
// 3. check if all references for the related child terms come back in the join conditions
// 3.1 check child subject
List<Term> childSubjectMaps = Utils.getObjectsFromQuads(rmlStore.getQuads(parentTriplesMap, new NamedNode(NAMESPACES.RML2 + "subjectMap"), null));
if(!childSubjectMaps.isEmpty()) {
safeTerms = hasSafeReferences(childSubjectMaps.get(0), joinReferences);

boolean safeSelfJoinElimination = true;

// if no join condition, we can safely eliminate the self-join
// else we need more checks
if (parentSubjectMap != null && !joinConditions.isEmpty()) {
// we can eliminate a self-join when all join conditions have equal references and all references for the parent subject or all reference for the related child triple come back in the join conditions
// 1. check if all join references are equal
List<String> joinReferences = new ArrayList<>();
for (Term joinCondition : joinConditions) {
String parent = getObjectsFromQuads(rmlStore.getQuads(joinCondition, new NamedNode(NAMESPACES.RML2 + "parent"), null)).get(0).getValue();
String child = getObjectsFromQuads(rmlStore.getQuads(joinCondition, new NamedNode(NAMESPACES.RML2 + "child"), null)).get(0).getValue();
if (child.equals(parent)) {
joinReferences.add(child);
} else {
safeTerms = true;
safeSelfJoinElimination = false;
}
//3.2 check child predicate (only make sense if the child subject was safe, otherwise we cannot eliminate the-self join)
if (safeTerms) {
List<Term> childPredicateMaps = Utils.getObjectsFromQuads(rmlStore.getQuads(childPredicateObjectMap, new NamedNode(NAMESPACES.RML2 + "predicateMap"), null));
if(!childPredicateMaps.isEmpty()) {
safeTerms = hasSafeReferences(childPredicateMaps.get(0), joinReferences);
}
if (safeSelfJoinElimination) {
// 2. check if all references for the parent subject come back in the join conditions
boolean safeTerms = hasSafeReferences(parentSubjectMap, joinReferences);
if (!safeTerms) {
// if not all references for the parent subject come back in the join conditions,
// 3. check if all references for the related child terms come back in the join conditions
// 3.1 check child subject
List<Term> childSubjectMaps = Utils.getObjectsFromQuads(rmlStore.getQuads(parentTriplesMap, new NamedNode(NAMESPACES.RML2 + "subjectMap"), null));
if (!childSubjectMaps.isEmpty()) {
safeTerms = hasSafeReferences(childSubjectMaps.get(0), joinReferences);
} else {
safeTerms = true;
}
//3.2 check child predicate (only make sense if the child subject was safe, otherwise we cannot eliminate the-self join)
if (safeTerms) {
List<Term> childPredicateMaps = Utils.getObjectsFromQuads(rmlStore.getQuads(childPredicateObjectMap, new NamedNode(NAMESPACES.RML2 + "predicateMap"), null));
if (!childPredicateMaps.isEmpty()) {
safeTerms = hasSafeReferences(childPredicateMaps.get(0), joinReferences);
}
}
}
}
// 4. if parent subject or all child terms are safe, the self join can be eliminated, else not
if (!safeTerms) {
safeSelfJoinElimination = false;
// 4. if parent subject or all child terms are safe, the self join can be eliminated, else not
if (!safeTerms) {
safeSelfJoinElimination = false;
}
}
}
}
if (safeSelfJoinElimination) {
// now we rewrite the mapping file to eliminate the self-join
boolean termTypeAdded = false;
List<Quad> parentSubjectMapQuads = rmlStore.getQuads(parentSubjectMap, null, null);
for (Quad parentSubjectMapQuad : parentSubjectMapQuads) {
Term predicate = parentSubjectMapQuad.getPredicate();
if (predicate.equals(new NamedNode(NAMESPACES.FNML + "functionValue"))
|| predicate.equals(new NamedNode(NAMESPACES.RML2 + "termType"))
|| predicate.equals(new NamedNode(NAMESPACES.RML2 + "reference"))
|| predicate.equals(new NamedNode(NAMESPACES.RML2 + "template"))
|| predicate.equals(new NamedNode(NAMESPACES.RML2 + "constant"))) {
rmlStore.addQuad(childObjectMap, predicate, parentSubjectMapQuad.getObject());
if (safeSelfJoinElimination) {
// now we rewrite the mapping file to eliminate the self-join
boolean termTypeAdded = false;
List<Quad> parentSubjectMapQuads = rmlStore.getQuads(parentSubjectMap, null, null);
for (Quad parentSubjectMapQuad : parentSubjectMapQuads) {
Term predicate = parentSubjectMapQuad.getPredicate();
if (predicate.equals(new NamedNode(NAMESPACES.FNML + "functionValue"))
|| predicate.equals(new NamedNode(NAMESPACES.RML2 + "termType"))
|| predicate.equals(new NamedNode(NAMESPACES.RML2 + "reference"))
|| predicate.equals(new NamedNode(NAMESPACES.RML2 + "template"))
|| predicate.equals(new NamedNode(NAMESPACES.RML2 + "constant"))) {
rmlStore.addQuad(childObjectMap, predicate, parentSubjectMapQuad.getObject());
}
if (predicate.equals(new NamedNode(NAMESPACES.RML2 + "termType"))) {
termTypeAdded = true;
}
}
if (predicate.equals(new NamedNode(NAMESPACES.RML2 + "termType"))) {
termTypeAdded = true;
rmlStore.removeQuads(childObjectMap, new NamedNode(NAMESPACES.RML2 + "parentTriplesMap"), parentTriplesMap);
if (!termTypeAdded) {
rmlStore.addQuad(childObjectMap, new NamedNode(NAMESPACES.RML2 + "termType"), new NamedNode(NAMESPACES.RML2 + "IRI"));
}
}
rmlStore.removeQuads(childObjectMap, new NamedNode(NAMESPACES.RML2 + "parentTriplesMap"), parentTriplesMap);
if (!termTypeAdded) {
rmlStore.addQuad(childObjectMap, new NamedNode(NAMESPACES.RML2 + "termType"), new NamedNode(NAMESPACES.RML2 + "IRI"));
}
}
} catch (java.lang.IndexOutOfBoundsException e) {
continue;
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/be/ugent/rml/records/RecordsFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ public List<Record> createRecords(Term triplesMap, QuadStore rmlStore) throws Ex

return getRecords(access, logicalSource, referenceFormulation, rmlStore);
} else {
throw new Error("No Logical Source is found for " + triplesMap + ". Exactly one Logical Source is required per Triples Map.");
logger.error("No Logical Source is found for " + triplesMap + ". Exactly one Logical Source is required per Triples Map.");
return new ArrayList<>();
}
}

Expand Down