All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
ai.stapi.graphoperations.synchronization.IdentifyingGraphSynchronizer Maven / Gradle / Ivy
package ai.stapi.graphoperations.synchronization;
import ai.stapi.graph.EdgeRepository;
import ai.stapi.graph.Graph;
import ai.stapi.graph.NodeIdAndType;
import ai.stapi.graph.NodeRepository;
import ai.stapi.graph.exceptions.GraphException;
import ai.stapi.graph.graphelements.Edge;
import ai.stapi.graph.graphelements.Node;
import ai.stapi.graph.inMemoryGraph.EdgeBuilder;
import ai.stapi.graph.inMemoryGraph.InMemoryGraphRepository;
import ai.stapi.graph.traversableGraphElements.TraversableEdge;
import ai.stapi.graph.traversableGraphElements.TraversableNode;
import ai.stapi.graphoperations.graphLoader.GraphLoader;
import ai.stapi.graphoperations.graphLoader.inmemory.InMemoryGenericSearchOptionResolver;
import ai.stapi.graphoperations.graphLoader.inmemory.InMemoryGraphLoader;
import ai.stapi.graphoperations.synchronization.nodeIdentificator.NodeIdentifyingFiltersResolver;
import ai.stapi.identity.UniqueIdentifier;
import ai.stapi.schema.structureSchemaProvider.StructureSchemaFinder;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections4.map.LinkedMap;
public class IdentifyingGraphSynchronizer implements GraphSynchronizer {
private final NodeRepository nodeRepository;
private final EdgeRepository edgeRepository;
private final NodeIdentifyingFiltersResolver nodeIdentifyingFiltersResolver;
private final GraphLoader graphLoader;
private final InMemoryGenericSearchOptionResolver searchOptionResolver;
private final ObjectMapper objectMapper;
private final StructureSchemaFinder structureSchemaFinder;
public IdentifyingGraphSynchronizer(
NodeRepository nodeRepository,
EdgeRepository edgeRepository,
NodeIdentifyingFiltersResolver nodeIdentifyingFiltersResolver,
GraphLoader graphLoader,
InMemoryGenericSearchOptionResolver searchOptionResolver,
ObjectMapper objectMapper,
StructureSchemaFinder structureSchemaFinder
) {
this.nodeRepository = nodeRepository;
this.edgeRepository = edgeRepository;
this.nodeIdentifyingFiltersResolver = nodeIdentifyingFiltersResolver;
this.graphLoader = graphLoader;
this.searchOptionResolver = searchOptionResolver;
this.objectMapper = objectMapper;
this.structureSchemaFinder = structureSchemaFinder;
}
@Override
public void synchronize(Graph graph) throws GraphException {
var newGraph = new InMemoryGraphRepository(graph);
var idChanges = this.synchronizeNodes(newGraph);
this.synchronizeEdges(newGraph, idChanges);
}
public InMemoryGraphRepository mergeDuplicateNodesByIdentificators(
InMemoryGraphRepository graphWithDuplications
) {
Map processedNodes = new LinkedMap<>();
var resultingGraph = new InMemoryGraphRepository();
var inMemoryGraphLoader = new InMemoryGraphLoader(
resultingGraph,
this.searchOptionResolver,
this.structureSchemaFinder,
this.objectMapper
);
for (Node mergingNode : graphWithDuplications.getGraph().getAllNodes()) {
var identifyingQuery = this.nodeIdentifyingFiltersResolver.resolve(
mergingNode,
graphWithDuplications
);
var identfiedNodes = inMemoryGraphLoader.findAsTraversable(identifyingQuery);
var sameTypeIdentifiedNodes = identfiedNodes.stream()
.map(TraversableNode.class::cast)
.map(Node::new)
.filter(graphNode -> mergingNode.getType().equals(graphNode.getType()))
.toList();
if (sameTypeIdentifiedNodes.isEmpty()) {
resultingGraph.save(mergingNode);
processedNodes.put(
mergingNode.getId(),
mergingNode
);
continue;
}
if (sameTypeIdentifiedNodes.size() == 1) {
var existingNode = sameTypeIdentifiedNodes.get(0);
var newNode = (Node) existingNode.mergeAttributesWithAttributesOf(mergingNode);
resultingGraph.replace(newNode);
processedNodes.put(mergingNode.getId(), newNode);
continue;
}
throw new GraphException(
"Multiple nodes found by identificators. This should never happen. " +
"If occurs, it MUST BE investigated."
);
}
List fixedEdges = graphWithDuplications.loadAllEdges().stream().map(
oldEdge ->
{
Node fixedNodeFrom = processedNodes.get(oldEdge.getNodeFromId());
Node fixedNodeTo = processedNodes.get(oldEdge.getNodeToId());
return new EdgeBuilder()
.setEdgeId(oldEdge.getId())
.setEdgeType(oldEdge.getType())
.setNodeFromId(fixedNodeFrom.getId())
.setNodeToId(fixedNodeTo.getId())
.setNodeFromType(fixedNodeFrom.getType())
.setNodeToType(fixedNodeTo.getType())
.setVersionedAttributes(oldEdge.getVersionedAttributes())
.create();
}
).toList();
List mergedEdges = new ArrayList<>();
fixedEdges.forEach(fixedEdge -> {
List foundEdges = mergedEdges.stream().filter(processedEdge ->
processedEdge.getNodeFromId().equals(fixedEdge.getNodeFromId()) &&
processedEdge.getNodeToId().equals(fixedEdge.getNodeToId()) &&
processedEdge.getType().equals(fixedEdge.getType())
).toList();
if (foundEdges.isEmpty()) {
resultingGraph.save(fixedEdge);
mergedEdges.add(fixedEdge);
return;
}
if (foundEdges.size() == 1) {
Edge edge =
(Edge) foundEdges.get(0).mergeAttributesWithAttributesOf(fixedEdge);
resultingGraph.replace(edge);
return;
}
throw new GraphException("Multiple edges found by end nodes and attributes.");
});
return resultingGraph.getGraph().traversable();
}
private LinkedMap> synchronizeNodes(
InMemoryGraphRepository newGraph
) {
var nodeIdChangesMap = new LinkedMap>();
for (var node : newGraph.getGraph().getAllNodes()) {
this.synchronizeNode(
newGraph,
node,
nodeIdChangesMap
);
}
return nodeIdChangesMap;
}
private void synchronizeNode(
InMemoryGraphRepository newGraph,
Node inMemoryNode,
LinkedMap> nodeIdChangesMap
) {
var identifyingQuery = this.nodeIdentifyingFiltersResolver.resolve(
inMemoryNode,
newGraph
);
var foundNodes = this.graphLoader.findAsTraversable(identifyingQuery);
if (foundNodes.size() > 1) {
throw new GraphException(
"Multiple nodes found by identificators. This should never happen. " +
"If occurs, it MUST BE investigated."
);
}
if (foundNodes.isEmpty()) {
this.nodeRepository.save(
new Node(
inMemoryNode.getId(),
inMemoryNode.getType(),
inMemoryNode.getVersionedAttributes()
)
);
return;
}
var foundNode = (TraversableNode) foundNodes.get(0);
foundNode = (TraversableNode) foundNode.mergeAttributesWithAttributesOf(inMemoryNode);
this.nodeRepository.replace(
new Node(
foundNode.getId(),
foundNode.getType(),
foundNode.getVersionedAttributes()
)
);
var nodeTypeMap = nodeIdChangesMap.computeIfAbsent(inMemoryNode.getType(), (key) -> new LinkedMap<>());
nodeTypeMap.put(
inMemoryNode.getId(),
foundNode.getId()
);
}
private void synchronizeEdges(
InMemoryGraphRepository newGraph,
LinkedMap> nodeIdChangeMap
) {
newGraph.getGraph().getAllEdges().forEach(
potentiallyRottenEdge ->
{
var fixedNodeFromId = nodeIdChangeMap.getOrDefault(
potentiallyRottenEdge.getNodeFromType(),
new LinkedMap<>()
).getOrDefault(
potentiallyRottenEdge.getNodeFromId(),
potentiallyRottenEdge.getNodeFromId()
);
var fixedNodeFrom = new Node(fixedNodeFromId, potentiallyRottenEdge.getNodeFromType());
var fixedNodeToId = nodeIdChangeMap.getOrDefault(
potentiallyRottenEdge.getNodeToType(),
new LinkedMap<>()
).getOrDefault(
potentiallyRottenEdge.getNodeToId(),
potentiallyRottenEdge.getNodeToId()
);
var fixedNodeTo = new Node(fixedNodeToId, potentiallyRottenEdge.getNodeToType());
var fixedEdge = new Edge(
potentiallyRottenEdge.getId(),
fixedNodeFrom,
potentiallyRottenEdge.getType(),
fixedNodeTo
);
fixedEdge = (Edge) fixedEdge.mergeAttributesWithAttributesOf(potentiallyRottenEdge);
var foundEdge = edgeRepository.findEdgeByTypeAndNodes(
fixedEdge.getType(),
new NodeIdAndType(fixedEdge.getNodeFromId(), fixedEdge.getNodeFromType()),
new NodeIdAndType(fixedEdge.getNodeToId(), fixedEdge.getNodeToType())
);
if (foundEdge != null) {
foundEdge = (TraversableEdge) foundEdge.mergeAttributesWithAttributesOf(fixedEdge);
edgeRepository.replace(
new Edge(
foundEdge.getId(),
foundEdge.getType(),
new Node(foundEdge.getNodeFrom().getId(), foundEdge.getNodeFrom().getType()),
new Node(foundEdge.getNodeTo().getId(), foundEdge.getNodeTo().getType()),
foundEdge.getVersionedAttributes()
)
);
} else {
edgeRepository.save(fixedEdge);
}
}
);
}
}