Skip to content

Commit 9cc3538

Browse files
authored
Merge pull request #3676 from graphql-java/schema-diffing-improve
schema diffing improvements
2 parents 2ae1479 + ec8bafb commit 9cc3538

File tree

2 files changed

+48
-69
lines changed

2 files changed

+48
-69
lines changed

src/main/java/graphql/schema/diffing/DiffImpl.java

Lines changed: 45 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -444,41 +444,9 @@ private double calcLowerBoundMappingCost(Vertex v,
444444

445445
boolean equalNodes = v.getType().equals(u.getType()) && v.getProperties().equals(u.getProperties());
446446

447-
Collection<Edge> adjacentEdgesV = completeSourceGraph.getAdjacentEdgesNonCopy(v);
448-
Multiset<String> multisetLabelsV = HashMultiset.create();
449-
450-
for (Edge edge : adjacentEdgesV) {
451-
// test if this is an inner edge (meaning it not part of the subgraph induced by the partial mapping)
452-
// we know that v is not part of the mapped vertices, therefore we only need to test the "to" vertex
453-
if (!partialMapping.containsSource(edge.getTo())) {
454-
multisetLabelsV.add(edge.getLabel());
455-
}
456-
}
457-
458-
Collection<Edge> adjacentEdgesU = completeTargetGraph.getAdjacentEdgesNonCopy(u);
459-
Multiset<String> multisetLabelsU = HashMultiset.create();
460-
for (Edge edge : adjacentEdgesU) {
461-
// test if this is an inner edge (meaning it not part of the subgraph induced by the partial mapping)
462-
// we know that u is not part of the mapped vertices, therefore we only need to test the "to" vertex
463-
if (!partialMapping.containsTarget(edge.getTo())) {
464-
multisetLabelsU.add(edge.getLabel());
465-
}
466-
}
467-
468-
int anchoredVerticesCost = calcAnchoredVerticesCost(v, u, partialMapping);
469-
470-
Multiset<String> intersection = Multisets.intersection(multisetLabelsV, multisetLabelsU);
471-
int multiSetEditDistance = Math.max(multisetLabelsV.size(), multisetLabelsU.size()) - intersection.size();
472-
473-
double result = (equalNodes ? 0 : 1) + multiSetEditDistance + anchoredVerticesCost;
474-
return result;
475-
}
476-
477-
478-
private int calcAnchoredVerticesCost(Vertex v,
479-
Vertex u,
480-
Mapping partialMapping) {
481447
int anchoredVerticesCost = 0;
448+
Multiset<String> multisetInnerEdgeLabelsV = HashMultiset.create();
449+
Multiset<String> multisetInnerEdgeLabelsU = HashMultiset.create();
482450

483451
Collection<Edge> adjacentEdgesV = completeSourceGraph.getAdjacentEdgesNonCopy(v);
484452
Collection<Edge> adjacentEdgesU = completeTargetGraph.getAdjacentEdgesNonCopy(u);
@@ -489,55 +457,60 @@ private int calcAnchoredVerticesCost(Vertex v,
489457
Set<Edge> matchedTargetEdges = new LinkedHashSet<>();
490458
Set<Edge> matchedTargetEdgesInverse = new LinkedHashSet<>();
491459

492-
outer:
493460
for (Edge edgeV : adjacentEdgesV) {
494-
// we are only interested in edges from anchored vertices
495-
if (!partialMapping.containsSource(edgeV.getTo())) {
461+
462+
Vertex targetTo = partialMapping.getTarget(edgeV.getTo());
463+
if (targetTo == null) {
464+
// meaning it is an inner edge(not part of the subgraph induced by the partial mapping)
465+
multisetInnerEdgeLabelsV.add(edgeV.getLabel());
496466
continue;
497467
}
498-
for (Edge edgeU : adjacentEdgesU) {
499-
// looking for an adjacent edge from u matching it
500-
if (partialMapping.getTarget(edgeV.getTo()) == edgeU.getTo()) {
501-
matchedTargetEdges.add(edgeU);
502-
// found two adjacent edges, comparing the labels
503-
if (!Objects.equals(edgeV.getLabel(), edgeU.getLabel())) {
504-
anchoredVerticesCost++;
505-
}
506-
continue outer;
468+
/* question is if the edge from v is mapped onto an edge from u
469+
(also edge are not mapped directly, but the vertices are)
470+
and if the adjacent edge is mapped onto an adjacent edge,
471+
we need to check the labels of the edges
472+
*/
473+
Edge matchedTargetEdge = completeTargetGraph.getEdge(u, targetTo);
474+
if (matchedTargetEdge != null) {
475+
matchedTargetEdges.add(matchedTargetEdge);
476+
if (!Objects.equals(edgeV.getLabel(), matchedTargetEdge.getLabel())) {
477+
anchoredVerticesCost++;
507478
}
479+
} else {
480+
// // no matching adjacent edge from u found means there is no
481+
// // edge from edgeV.getTo() to mapped(edgeV.getTo())
482+
// // and we need to increase the costs
483+
anchoredVerticesCost++;
508484
}
509-
// no matching adjacent edge from u found means there is no
510-
// edge from edgeV.getTo() to mapped(edgeV.getTo())
511-
// and we need to increase the costs
512-
anchoredVerticesCost++;
513485

514486
}
515487

516-
outer:
517488
for (Edge edgeV : adjacentEdgesInverseV) {
489+
490+
Vertex targetFrom = partialMapping.getTarget(edgeV.getFrom());
518491
// we are only interested in edges from anchored vertices
519-
if (!partialMapping.containsSource(edgeV.getFrom())) {
492+
if (targetFrom == null) {
520493
continue;
521494
}
522-
for (Edge edgeU : adjacentEdgesInverseU) {
523-
if (partialMapping.getTarget(edgeV.getFrom()) == edgeU.getFrom()) {
524-
matchedTargetEdgesInverse.add(edgeU);
525-
if (!Objects.equals(edgeV.getLabel(), edgeU.getLabel())) {
526-
anchoredVerticesCost++;
527-
}
528-
continue outer;
495+
Edge matachedTargetEdge = completeTargetGraph.getEdge(targetFrom, u);
496+
if (matachedTargetEdge != null) {
497+
matchedTargetEdgesInverse.add(matachedTargetEdge);
498+
if (!Objects.equals(edgeV.getLabel(), matachedTargetEdge.getLabel())) {
499+
anchoredVerticesCost++;
529500
}
501+
} else {
502+
anchoredVerticesCost++;
530503
}
531-
anchoredVerticesCost++;
532-
533504
}
534505

535-
/**
536-
* what is missing now is all edges from u (and inverse), which have not been matched.
537-
*/
538506
for (Edge edgeU : adjacentEdgesU) {
539-
// we are only interested in edges from anchored vertices
540-
if (!partialMapping.containsTarget(edgeU.getTo()) || matchedTargetEdges.contains(edgeU)) {
507+
// test if this is an inner edge (meaning it not part of the subgraph induced by the partial mapping)
508+
// we know that u is not part of the mapped vertices, therefore we only need to test the "to" vertex
509+
if (!partialMapping.containsTarget(edgeU.getTo())) {
510+
multisetInnerEdgeLabelsU.add(edgeU.getLabel());
511+
continue;
512+
}
513+
if (matchedTargetEdges.contains(edgeU)) {
541514
continue;
542515
}
543516
anchoredVerticesCost++;
@@ -551,7 +524,12 @@ private int calcAnchoredVerticesCost(Vertex v,
551524
anchoredVerticesCost++;
552525
}
553526

554-
return anchoredVerticesCost;
527+
528+
Multiset<String> intersectionInnerEdgeLabels = Multisets.intersection(multisetInnerEdgeLabelsV, multisetInnerEdgeLabelsU);
529+
int multiSetEditDistanceForInnerEdges = Math.max(multisetInnerEdgeLabelsV.size(), multisetInnerEdgeLabelsU.size()) - intersectionInnerEdgeLabels.size();
530+
531+
int result = (equalNodes ? 0 : 1) + multiSetEditDistanceForInnerEdges + anchoredVerticesCost;
532+
return result;
555533
}
556534

557535

@@ -578,5 +556,4 @@ private double calcLowerBoundMappingCostForIsolated(Vertex vertex,
578556
return 1 + adjacentEdges.size() + anchoredInverseEdges;
579557
}
580558

581-
582559
}

src/main/java/graphql/schema/diffing/SchemaDiffing.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,17 @@ private DiffImpl.OptimalEdit diffImpl(SchemaGraph sourceGraph, SchemaGraph targe
9696
Multimaps.invertFrom(possibleMappings.possibleMappings, invertedPossibleOnes);
9797
possibleMappings.possibleMappings = invertedPossibleOnes;
9898

99+
sortVertices(nonMappedTarget, targetGraph, possibleMappings);
100+
99101
List<Vertex> sourceVertices = new ArrayList<>();
100102
sourceVertices.addAll(possibleMappings.fixedOneToOneSources);
101103
sourceVertices.addAll(nonMappedSource);
102104

105+
103106
List<Vertex> targetVertices = new ArrayList<>();
104107
targetVertices.addAll(possibleMappings.fixedOneToOneTargets);
105108
targetVertices.addAll(nonMappedTarget);
106109

107-
sortVertices(nonMappedTarget, targetGraph, possibleMappings);
108110

109111
DiffImpl diffImpl = new DiffImpl(possibleMappingsCalculator, targetGraph, sourceGraph, possibleMappings, runningCheck);
110112
DiffImpl.OptimalEdit optimalEdit = diffImpl.diffImpl(startMappingInverted, targetVertices, sourceVertices, algoIterationCount);

0 commit comments

Comments
 (0)