/*******************************************************************************
* Copyright 2012 University of Southern California
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This code was developed by the Information Integration Group as part
* of the Karma project at the Information Sciences Institute of the
* University of Southern California. For more information, publications,
* and related projects, please see: http://www.isi.edu/integration
******************************************************************************/
package edu.isi.karma.modeling.alignment;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jgrapht.UndirectedGraph;
import org.jgrapht.graph.AsUndirectedGraph;
import org.jgrapht.graph.DirectedWeightedMultigraph;
import org.jgrapht.graph.WeightedMultigraph;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.rits.cloning.Cloner;
import edu.isi.karma.config.ModelingConfiguration;
import edu.isi.karma.config.ModelingConfigurationRegistry;
import edu.isi.karma.modeling.Namespaces;
import edu.isi.karma.modeling.Prefixes;
import edu.isi.karma.modeling.Uris;
import edu.isi.karma.modeling.alignment.learner.LinkCoherence;
import edu.isi.karma.modeling.alignment.learner.ModelLearner;
import edu.isi.karma.modeling.alignment.learner.ModelLearningGraph;
import edu.isi.karma.modeling.alignment.learner.ModelLearningGraphType;
import edu.isi.karma.modeling.ontology.OntologyManager;
import edu.isi.karma.modeling.ontology.OntologyUpdateListener;
import edu.isi.karma.rep.HNode;
import edu.isi.karma.rep.HNodePath;
import edu.isi.karma.rep.Worksheet;
import edu.isi.karma.rep.alignment.ClassInstanceLink;
import edu.isi.karma.rep.alignment.ColumnNode;
import edu.isi.karma.rep.alignment.ColumnSemanticTypeStatus;
import edu.isi.karma.rep.alignment.ColumnSubClassLink;
import edu.isi.karma.rep.alignment.DataPropertyLink;
import edu.isi.karma.rep.alignment.DataPropertyOfColumnLink;
import edu.isi.karma.rep.alignment.DefaultLink;
import edu.isi.karma.rep.alignment.InternalNode;
import edu.isi.karma.rep.alignment.Label;
import edu.isi.karma.rep.alignment.LabeledLink;
import edu.isi.karma.rep.alignment.LinkKeyInfo;
import edu.isi.karma.rep.alignment.LinkStatus;
import edu.isi.karma.rep.alignment.LinkType;
import edu.isi.karma.rep.alignment.LiteralNode;
import edu.isi.karma.rep.alignment.Node;
import edu.isi.karma.rep.alignment.NodeType;
import edu.isi.karma.rep.alignment.ObjectPropertyLink;
import edu.isi.karma.rep.alignment.ObjectPropertySpecializationLink;
import edu.isi.karma.rep.alignment.SemanticType;
import edu.isi.karma.rep.alignment.SubClassLink;
import edu.isi.karma.webserver.ContextParametersRegistry;
public class Alignment implements OntologyUpdateListener {
static Logger logger = LoggerFactory.getLogger(Alignment.class);
private OntologyManager ontologyManager;
private GraphBuilder graphBuilder;
private DirectedWeightedMultigraph<Node, LabeledLink> steinerTree = null;
private Node root = null;
private NodeIdFactory nodeIdFactory;
private Set<ColumnNode> sourceColumnNodes;
private String contextId;
public Alignment(OntologyManager ontologyManager) {
this.contextId = ontologyManager.getContextId();
this.ontologyManager = ontologyManager;
this.ontologyManager.subscribeListener(this);
this.sourceColumnNodes = new HashSet<>();
ModelingConfiguration conf = ModelingConfigurationRegistry.getInstance().
getModelingConfiguration(ContextParametersRegistry.getInstance().getContextParameters(contextId).getKarmaHome());
if (conf.getKnownModelsAlignment()) {
this.graphBuilder =
ModelLearningGraph.getInstance(ontologyManager, ModelLearningGraphType.Compact).getGraphBuilderClone();
} else {
this.graphBuilder = new GraphBuilder(this.ontologyManager, true);
}
this.nodeIdFactory = this.graphBuilder.getNodeIdFactory();
logger.debug("loading learning graph ...");
}
public boolean isEmpty() {
return (this.graphBuilder.getGraph().edgeSet().isEmpty() || this.steinerTree == null);
}
public Node GetTreeRoot() {
return this.root;
}
public GraphBuilder getGraphBuilder() {
return this.graphBuilder;
}
public Set<ColumnNode> getSourceColumnNodes() {
return sourceColumnNodes;
}
public Alignment getAlignmentClone() {
Cloner cloner = new Cloner();
// cloner.setDumpClonedClasses(true);
cloner.dontClone(OntologyManager.class);
cloner.dontCloneInstanceOf(OntologyManager.class);
cloner.dontClone(DirectedWeightedMultigraph.class);
cloner.dontCloneInstanceOf(DirectedWeightedMultigraph.class);
return cloner.deepClone(this);
}
public DirectedWeightedMultigraph<Node, LabeledLink> getSteinerTree() {
if (this.steinerTree == null) align();
// GraphUtil.printGraph(this.steinerTree);
if (this.steinerTree == null)
steinerTree = new DirectedWeightedMultigraph<>(LabeledLink.class);
return this.steinerTree;
}
public DirectedWeightedMultigraph<Node, DefaultLink> getGraph() {
return this.graphBuilder.getGraph();
}
public void setGraph(DirectedWeightedMultigraph<Node, DefaultLink> graph) {
this.graphBuilder.setGraph(graph);
}
public Set<Node> getGraphNodes() {
return this.graphBuilder.getGraph().vertexSet();
}
// public Set<DefaultLink> getGraphLinks() {
// return this.graphBuilder.getGraph().edgeSet();
// }
public Node getNodeById(String nodeId) {
return this.graphBuilder.getIdToNodeMap().get(nodeId);
}
public Set<Node> getNodesByUri(String uri) {
return this.graphBuilder.getUriToNodesMap().get(uri);
}
public Set<Node> getNodesByType(NodeType type) {
return this.graphBuilder.getTypeToNodesMap().get(type);
}
public Set<Node> getForcedNodes() {
return this.graphBuilder.getForcedNodes();
}
public LabeledLink getLinkById(String linkId) {
return this.graphBuilder.getIdToLinkMap().get(linkId);
}
public Set<LabeledLink> getLinksByUri(String uri) {
return this.graphBuilder.getUriToLinksMap().get(uri);
}
public Set<LabeledLink> getLinksByType(LinkType type) {
return this.graphBuilder.getTypeToLinksMap().get(type);
}
public Set<LabeledLink> getLinksByStatus(LinkStatus status) {
return this.graphBuilder.getStatusToLinksMap().get(status);
}
public int getLastIndexOfNodeUri(String uri) {
return this.nodeIdFactory.lastIndexOf(uri);
}
// public int getLastIndexOfLinkUri(String uri) {
// return this.linkIdFactory.lastIndexOf(uri);
// }
public ColumnNode getColumnNodeByHNodeId(String hNodeId) {
Node n = this.graphBuilder.getIdToNodeMap().get(hNodeId);
if (n != null && n instanceof ColumnNode)
return (ColumnNode)n;
else
return null;
// List<Node> columnNodes = this.getNodesByType(NodeType.ColumnNode);
// if (columnNodes == null) return null;
// for (Node cNode : columnNodes) {
// if (((ColumnNode)cNode).getHNodeId().equals(hNodeId))
// return (ColumnNode)cNode;
// }
// return null;
}
// AddNode methods
public ColumnNode addColumnNode(String hNodeId, String columnName, Label rdfLiteralType, String language) {
if(this.getNodeById(hNodeId) != null)
{
return null;
}
// use hNodeId as id of the node
ColumnNode node = new ColumnNode(hNodeId, hNodeId, columnName, rdfLiteralType, language);
if (this.graphBuilder.addNodeAndUpdate(node)) {
this.sourceColumnNodes.add(node);
return node;
}
return null;
}
public InternalNode addInternalNode(InternalNode node) {
Node n = this.getNodeById(node.getId());
if (n == null) {
if (this.graphBuilder.addNodeAndUpdate(node)) {
this.nodeIdFactory.addNodeId(node.getId(), node.getUri());
return node;
} else {
logger.error("error in adding the internal node " + node.getId() + " to the graph");
return null;
}
}
if (n instanceof InternalNode)
return (InternalNode)n;
return null;
}
public InternalNode addInternalNode(Label label) {
String id = nodeIdFactory.getNodeId(label.getUri());
InternalNode node = new InternalNode(id, label);
if (this.graphBuilder.addNodeAndUpdate(node)) return node;
return null;
}
public void addToForcedNodes(Node node) {
node.setForced(true);
this.graphBuilder.getForcedNodes().add(node);
}
// public InternalNode addForcedInternalNode(Label label) {
//
// final Set<String> steinerTreeNodeIds = new HashSet<String>();
//
// for (Node node: this.getSteinerTree().vertexSet()) {
// if (node.getType() == NodeType.InternalNode) {
// steinerTreeNodeIds.add(node.getId());
// }
// }
//
// String nodeUri = label.getUri();
// int graphLastIndex = this.getLastIndexOfNodeUri(nodeUri);
// String nodeId;
// // If the node exists in graph but not in tree then use the graph node id
// boolean alreadyInGraph = false;
// if (graphLastIndex != -1) {
// int i = 1;
// for (; i <= graphLastIndex && steinerTreeNodeIds.contains(nodeUri + i); i++) ;
// nodeId = nodeUri + i;
//
// if (i <= graphLastIndex) {
// alreadyInGraph = true;
// nodeId = nodeUri + i;
// Node node = this.getNodeById(nodeId);
// node.setForced(true);
// this.graphBuilder.getForcedNodes().add(node);
// return (InternalNode)node;
// }
// }
//
// if (!alreadyInGraph) {
// nodeId = nodeIdFactory.getNodeId(label.getUri());;
// InternalNode node = new InternalNode(nodeId, label);
// node.setForced(true);
// if (this.graphBuilder.addNodeAndUpdate(node))
// return node;
// }
//
//
// return null;
// }
public LiteralNode addLiteralNode(String value, String type, String language, boolean isUri) {
type = type.replace(Prefixes.XSD + ":", Namespaces.XSD);
Label literalType = new Label(type, Namespaces.XSD, Prefixes.XSD);
String id = nodeIdFactory.getNodeId(value);
if(isUri && value.startsWith("\"") && value.endsWith("\""))
value = value.substring(1, value.length()-1);
LiteralNode node = new LiteralNode(id, value, literalType, language, isUri);
if(this.graphBuilder.addNode(node)) return node;
return null;
}
public LiteralNode addLiteralNode(String nodeId, String value, String type, String language, boolean isUri) {
type = type.replace(Prefixes.XSD + ":", Namespaces.XSD);
Label literalType = new Label(type, Namespaces.XSD, Prefixes.XSD);
String id = nodeId;
if(isUri && value.startsWith("\"") && value.endsWith("\""))
value = value.substring(1, value.length()-1);
LiteralNode node = new LiteralNode(id, value, literalType, language, isUri);
if(this.graphBuilder.addNode(node)) return node;
return null;
}
public void updateLiteralNode(String nodeId, String value, String type, String language, boolean isUri) {
LiteralNode node = (LiteralNode) getNodeById(nodeId);
if(node != null) {
type = type.replace(Prefixes.XSD + ":", Namespaces.XSD);
Label literalType = new Label(type, Namespaces.XSD, Prefixes.XSD);
node.setDatatype(literalType);
node.setValue(value);
node.setLanguage(language);
node.setUri(isUri);
} else {
addLiteralNode(nodeId, value, type, language, isUri);
}
}
public void deleteForcedInternalNode(String nodeId) {
Node node = getNodeById(nodeId);
if(node != null) {
this.removeNode(nodeId);
// if (this.graphBuilder.removeNode(node))
// this.steinerTree.removeVertex(node);
}
}
// AddLink methods
public DataPropertyLink addDataPropertyLink(Node source, Node target, Label label, boolean isProvenance) {
String id = LinkIdFactory.getLinkId(label.getUri(), source.getId(), target.getId());
DataPropertyLink link = new DataPropertyLink(id, label, isProvenance);
if (this.graphBuilder.addLink(source, target, link)) return link;
return null;
}
public ObjectPropertyLink addObjectPropertyLink(Node source, Node target, Label label) {
String id = LinkIdFactory.getLinkId(label.getUri(), source.getId(), target.getId());
ObjectPropertyLink link = new ObjectPropertyLink(id, label,
this.graphBuilder.getOntologyManager().getObjectPropertyType(source.getLabel().getUri(), target.getLabel().getUri(), label.getUri()));
if (this.graphBuilder.addLink(source, target, link))
{
return link;
}
else if(this.graphBuilder.getIdToLinkMap().containsKey(link.getId()))
{
return (ObjectPropertyLink) this.graphBuilder.getIdToLinkMap().get(link.getId());
}
else
{
return null;
}
}
// Probably we don't need this function in the interface to GUI
public SubClassLink addSubClassOfLink(Node source, Node target) {
String id = LinkIdFactory.getLinkId(Uris.RDFS_SUBCLASS_URI, source.getId(), target.getId());
SubClassLink link = new SubClassLink(id);
if (this.graphBuilder.addLink(source, target, link)) return link;
return null;
}
public ClassInstanceLink addClassInstanceLink(Node source, Node target, LinkKeyInfo keyInfo) {
String id = LinkIdFactory.getLinkId(Uris.CLASS_INSTANCE_LINK_URI, source.getId(), target.getId());
ClassInstanceLink link = new ClassInstanceLink(id, keyInfo);
if (this.graphBuilder.addLink(source, target, link)) return link;
return null;
}
public DataPropertyOfColumnLink addDataPropertyOfColumnLink(Node source, Node target, String specializedColumnHNodeId, String specializedLinkId) {
String id = LinkIdFactory.getLinkId(Uris.DATAPROPERTY_OF_COLUMN_LINK_URI, source.getId(), target.getId());
DataPropertyOfColumnLink link = new DataPropertyOfColumnLink(id, specializedColumnHNodeId, specializedLinkId);
if (this.graphBuilder.addLink(source, target, link)) return link;
return null;
}
public ObjectPropertySpecializationLink addObjectPropertySpecializationLink(Node source, Node target, String specializedLinkId) {
String id = LinkIdFactory.getLinkId(Uris.OBJECTPROPERTY_SPECIALIZATION_LINK_URI, source.getId(), target.getId());
ObjectPropertySpecializationLink link = new ObjectPropertySpecializationLink(id, specializedLinkId);
if (this.graphBuilder.addLink(source, target, link)) return link;
return null;
}
public ColumnSubClassLink addColumnSubClassOfLink(Node source, Node target) {
String id = LinkIdFactory.getLinkId(Uris.COLUMN_SUBCLASS_LINK_URI, source.getId(), target.getId());
ColumnSubClassLink link = new ColumnSubClassLink(id);
if (this.graphBuilder.addLink(source, target, link)) return link;
return null;
}
public void changeLinkWeight(String linkId, double weight) {
LabeledLink link = this.getLinkById(linkId);
if (link == null) {
logger.error("Could not find the link with the id " + linkId);
return;
}
this.graphBuilder.changeLinkWeight(link, weight);
}
public void changeLinkStatus(String linkId, LinkStatus newStatus) {
logger.debug("changing the status of link " + linkId + " to " + newStatus.name());
LabeledLink link = this.getLinkById(linkId);
if (link == null) {
if (newStatus == LinkStatus.ForcedByUser) {
Node source = this.getNodeById(LinkIdFactory.getLinkSourceId(linkId));
Node target = this.getNodeById(LinkIdFactory.getLinkTargetId(linkId));
String linkUri = LinkIdFactory.getLinkUri(linkId);
LabeledLink newLink;
if (linkUri.equalsIgnoreCase(Uris.RDFS_SUBCLASS_URI))
newLink = new SubClassLink(linkId);
else
newLink = new ObjectPropertyLink(linkId,
this.graphBuilder.getOntologyManager().getUriLabel(linkUri),
this.graphBuilder.getOntologyManager().getObjectPropertyType(source.getLabel().getUri(), target.getLabel().getUri(), linkUri));
newLink.setStatus(LinkStatus.ForcedByUser);
this.graphBuilder.addLink(source, target, newLink);
}
} else
this.graphBuilder.changeLinkStatus(link, newStatus);
}
// // deletes the node directly from the graph (it also deleted all its incoming and outgoing links)
// public boolean removeNode(String nodeId) {
//
// Node node = this.getNodeById(nodeId);
// if (node != null) {
// if (this.graphBuilder.removeNode(node)) {
// this.steinerTree.removeVertex(node);
// return true;
// }
// }
// logger.debug("Cannot find the link " + nodeId + " in the graph.");
// return false;
// }
// only deletes the node from the model, not the alignment graph
public boolean removeNode(String nodeId) {
Node node = this.getNodeById(nodeId);
if (node != null) {
node.setForced(false);
this.graphBuilder.getForcedNodes().remove(node);
if (this.steinerTree != null && this.steinerTree.containsVertex(node)) {
Set<LabeledLink> links = this.steinerTree.edgesOf(node);
if (links != null) {
for (LabeledLink l : links) {
this.changeLinkStatus(l.getId(), LinkStatus.Normal);
}
}
this.steinerTree.removeVertex(node);
return true;
}
}
logger.debug("Cannot find the link " + nodeId + " in the graph.");
return false;
}
public boolean isNodeIsolatedInTree(String nodeId) {
Node node = this.getNodeById(nodeId);
if (node != null) {
if (this.steinerTree != null && this.steinerTree.containsVertex(node)) {
Set<LabeledLink> inLinks = this.steinerTree.edgesOf(node);
if (inLinks == null || inLinks.isEmpty())
return true;
}
}
logger.debug("Cannot find the link " + nodeId + " in the graph.");
return false;
}
/**
* This method just deletes the specified link from the graph and leaves the rest of the graph untouched.
* @param linkId
* @return
*/
public boolean removeLink(String linkId) {
LabeledLink link = this.getLinkById(linkId);
if (link != null) {
// return this.graphBuilder.removeLink(link);
if (this.graphBuilder.removeLink(link))
if (this.steinerTree != null) {
this.steinerTree.removeEdge(link);
return true;
}
}
logger.debug("Cannot find the link " + linkId + " in the graph.");
return false;
}
public Set<LabeledLink> getCurrentIncomingLinksToNode(String nodeId) {
Node node = this.getNodeById(nodeId);
if (node == null)
return null;
return this.graphBuilder.getIncomingLinksMap().get(nodeId);
}
public Set<LabeledLink> getCurrentOutgoingLinksToNode(String nodeId) {
Node node = this.getNodeById(nodeId);
if (node == null)
return null;
return this.graphBuilder.getOutgoingLinksMap().get(nodeId);
}
public List<LabeledLink> getPossibleLinks(String sourceId, String targetId) {
return this.graphBuilder.getPossibleLinks(sourceId, targetId);
}
public Set<LabeledLink> getIncomingLinksInTree(String nodeId) {
Set<LabeledLink> results = new HashSet<>();
if (steinerTree == null)
return results;
if (steinerTree.vertexSet().isEmpty())
return results;
Node node = null;
for (Node n : steinerTree.vertexSet()) {
if (n.getId().equals(nodeId)) {
node = n;
break;
}
}
if (node == null)
return results;
results = this.steinerTree.incomingEdgesOf(node);
return results;
}
public Set<LabeledLink> getOutgoingLinksInTree(String nodeId) {
Set<LabeledLink> results = new HashSet<>();
if (steinerTree == null)
return results;
if (steinerTree.vertexSet().isEmpty())
return results;
Node node = null;
for (Node n : steinerTree.vertexSet()) {
if (n.getId().equals(nodeId)) {
node = n;
break;
}
}
if (node == null)
return results;
results = this.steinerTree.outgoingEdgesOf(node);
return results;
}
// public List<LabeledLink> getIncomingLinksInGraph(String nodeId) {
//
// List<LabeledLink> possibleLinks = new ArrayList<LabeledLink>();
// List<DefaultLink> tempDefault = null;
// List<LabeledLink> tempLabeled = null;
// HashSet<DefaultLink> allLinks = new HashSet<DefaultLink>();
//
// Node node = this.getNodeById(nodeId);
// if (node == null) return possibleLinks;
//
// Set<DefaultLink> incomingLinks = this.graphBuilder.getGraph().incomingEdgesOf(node);
// if (incomingLinks != null) {
// tempDefault = Arrays.asList(incomingLinks.toArray(new DefaultLink[0]));
// allLinks.addAll(tempDefault);
// }
//
// if (node instanceof ColumnNode) {
// if (tempDefault != null) {
// for (DefaultLink l : tempDefault)
// if (l instanceof LabeledLink)
// possibleLinks.add((LabeledLink)l);
// }
// } else {
// Set<DefaultLink> outgoingLinks = this.graphBuilder.getGraph().outgoingEdgesOf(node);
// if (outgoingLinks != null) {
// tempDefault = Arrays.asList(outgoingLinks.toArray(new DefaultLink[0]));
// allLinks.addAll(outgoingLinks);
// }
//
// if (allLinks.size() == 0)
// return possibleLinks;
//
// String sourceId, targetId;
// for (DefaultLink e : allLinks) {
// if (e.getSource().getId().equals(nodeId)) { // outgoing link
// sourceId = e.getTarget().getId();
// targetId = nodeId;
// } else { // incoming link
// sourceId = e.getSource().getId();
// targetId = nodeId;
// }
// tempLabeled = getLinks(sourceId, targetId);
// if (tempLabeled != null)
// possibleLinks.addAll(tempLabeled);
// }
// }
//
// Collections.sort(possibleLinks, new LinkPriorityComparator());
//
// logger.debug("Finished obtaining the incoming links.");
// return possibleLinks;
// }
// public List<LabeledLink> getOutgoingLinksInGraph(String nodeId) {
//
// List<LabeledLink> possibleLinks = new ArrayList<LabeledLink>();
// List<DefaultLink> tempDefault = null;
// List<LabeledLink> tempLabeled = null;
// HashSet<DefaultLink> allLinks = new HashSet<DefaultLink>();
//
// Node node = this.getNodeById(nodeId);
// if (node == null || node instanceof ColumnNode) return possibleLinks;
//
// Set<DefaultLink> incomingLinks = this.graphBuilder.getGraph().incomingEdgesOf(node);
// if (incomingLinks != null) {
// tempDefault = Arrays.asList(incomingLinks.toArray(new DefaultLink[0]));
// allLinks.addAll(tempDefault);
// }
// Set<DefaultLink> outgoingLinks = this.graphBuilder.getGraph().outgoingEdgesOf(node);
// if (outgoingLinks != null) {
// tempDefault = Arrays.asList(outgoingLinks.toArray(new DefaultLink[0]));
// allLinks.addAll(outgoingLinks);
// }
//
// if (allLinks.size() == 0)
// return possibleLinks;
//
// String sourceId, targetId;
// for (DefaultLink e : allLinks) {
// if (e.getSource().getId().equals(nodeId)) { // outgoing link
// sourceId = nodeId;
// targetId = e.getTarget().getId();
// } else { // incoming link
// sourceId = nodeId;
// targetId = e.getSource().getId();
// }
// tempLabeled = getLinks(sourceId, targetId);
// if (tempLabeled != null)
// possibleLinks.addAll(tempLabeled);
// }
//
// Collections.sort(possibleLinks, new LinkPriorityComparator());
//
// logger.debug("Finished obtaining the outgoing links.");
// return possibleLinks;
// }
private void updateLinksPreferredByUI() {
if (this.steinerTree == null)
return;
// Change the status of previously preferred links to normal
Set<LabeledLink> linksInPreviousTree = this.getLinksByStatus(LinkStatus.PreferredByUI);
Set<LabeledLink> linksForcedByUser = this.getLinksByStatus(LinkStatus.ForcedByUser);
if (linksInPreviousTree != null) {
LabeledLink[] links = linksInPreviousTree.toArray(new LabeledLink[0]);
for (LabeledLink link : links)
this.graphBuilder.changeLinkStatus(link, LinkStatus.Normal);
}
for (LabeledLink link: this.steinerTree.edgeSet()) {
if (linksForcedByUser == null || !linksForcedByUser.contains(link)) {
this.graphBuilder.changeLinkStatus(link, LinkStatus.PreferredByUI);
logger.debug("link " + link.getId() + " has been added to preferred UI links.");
}
}
}
public List<Node> computeSteinerNodes() {
Set<Node> steinerNodes = new HashSet<>();
// Add column nodes and their domain
// it is better to set isForced flag when setting a semantic type
Set<ColumnNode> columnNodes = this.sourceColumnNodes;
if (columnNodes != null) {
for (ColumnNode n : columnNodes) {
if (n.getSemanticTypeStatus() == ColumnSemanticTypeStatus.UserAssigned ||
n.getSemanticTypeStatus() == ColumnSemanticTypeStatus.AutoAssigned)
steinerNodes.add(n);
if (n.getSemanticTypeStatus() == ColumnSemanticTypeStatus.UserAssigned) {
Map<SemanticType, LabeledLink> domainLinks =
GraphUtil.getDomainLinks(this.graphBuilder.getGraph(), n, n.getUserSemanticTypes());
if (domainLinks != null) {
for (LabeledLink l : domainLinks.values()) {
if (l.getSource() == null || !(l.getSource() instanceof InternalNode))
continue;
steinerNodes.add(l.getSource());
}
}
}
}
}
Set<Node> forcedNodes = this.getForcedNodes();
for (Node n : forcedNodes) {
if (!steinerNodes.contains(n))
steinerNodes.add(n);
}
// Add source and target of the links forced by the user
Set<LabeledLink> linksForcedByUser = this.getLinksByStatus(LinkStatus.ForcedByUser);
if (linksForcedByUser != null) {
for (LabeledLink link : linksForcedByUser) {
if (!steinerNodes.contains(link.getSource()))
steinerNodes.add(link.getSource());
if (!steinerNodes.contains(link.getTarget()))
steinerNodes.add(link.getTarget());
}
}
List<Node> result = new ArrayList<>();
result.addAll(steinerNodes);
return result;
}
public List<LabeledLink> suggestLinks(String nodeId) {
List<LabeledLink> suggestedLinks = new LinkedList<>();
if (this.steinerTree == null) {
logger.error("the model is null.");
return suggestedLinks;
}
Node n = this.getNodeById(nodeId);
if (n == null) {
logger.error("could not find the node " + nodeId + " in the model.");
return suggestedLinks;
}
Set<String> currentLinkIds = new HashSet<>();
Set<LabeledLink> currentIncomingLinks, currentOutgoingLinks;
currentIncomingLinks = this.getIncomingLinksInTree(nodeId);
currentOutgoingLinks = this.getOutgoingLinksInTree(nodeId);
if (currentIncomingLinks != null)
for (LabeledLink l : currentIncomingLinks)
currentLinkIds.add(l.getId());
if (currentOutgoingLinks != null)
for (LabeledLink l : currentOutgoingLinks)
currentLinkIds.add(l.getId());
Set<LabeledLink> candidateLinks = new HashSet<>();
List<LabeledLink> incomingLinks, outgoingLinks;
incomingLinks = ModelLearningGraph.getInstance(ontologyManager, ModelLearningGraphType.Compact).
getGraphBuilder().getIncomingLinks(nodeId);
outgoingLinks = ModelLearningGraph.getInstance(ontologyManager, ModelLearningGraphType.Compact).
getGraphBuilder().getOutgoingLinks(nodeId);
if (incomingLinks != null) candidateLinks.addAll(incomingLinks);
if (outgoingLinks != null) candidateLinks.addAll(outgoingLinks);
if (candidateLinks.isEmpty())
return suggestedLinks;
LinkCoherence modelCoherence = new LinkCoherence();
double modelCost = 0.0;
for (LabeledLink e : this.steinerTree.edgeSet()) {
// get the link from the graph
LabeledLink l = this.getLinkById(e.getId());
// modelCoherence.updateCoherence(this.steinerTree, l);
modelCoherence.updateCoherence(l);
modelCost += l.getWeight();
}
AlignmentScore currentScore = new AlignmentScore(modelCoherence, modelCost);
List<AlignmentScore> alignmentScores = new LinkedList<>();
for (LabeledLink l : candidateLinks) {
if (l.getModelIds() == null || l.getModelIds().isEmpty()) // ignore the links that are added by the user (not present in the known models)
continue;
// ignore the candidate links that are already in the model
if (currentLinkIds.contains(l.getId())) continue;
AlignmentScore a = new AlignmentScore(l, currentScore);
alignmentScores.add(a);
}
Collections.sort(alignmentScores);
for (AlignmentScore a : alignmentScores) {
suggestedLinks.add(a.getLink());
}
return suggestedLinks;
}
public List<LabeledLink> suggestAlternativeLinks(String linkId) {
List<LabeledLink> alternativeLinks = new LinkedList<>();
if (this.steinerTree == null) {
logger.error("the model is null.");
return alternativeLinks;
}
LabeledLink link = this.getLinkById(linkId);
if (link == null) {
logger.error("could not find the link " + linkId + " in the model.");
return alternativeLinks;
}
Node source = this.getNodeById(link.getSource().getId());
if (source == null) {
logger.error("could not find the source node " + link.getSource().getId() + " in the model.");
return alternativeLinks;
}
Node target = this.getNodeById(link.getTarget().getId());
if (target == null) {
logger.error("could not find the source node " + link.getTarget().getId() + " in the model.");
return alternativeLinks;
}
Set<LabeledLink> candidateLinks = new HashSet<>();
List<LabeledLink> incomingLinks, outgoingLinks;
incomingLinks = ModelLearningGraph.getInstance(ontologyManager, ModelLearningGraphType.Compact).
getGraphBuilder().getLinks(target.getId(), source.getId());
outgoingLinks = ModelLearningGraph.getInstance(ontologyManager, ModelLearningGraphType.Compact).
getGraphBuilder().getLinks(source.getId(), target.getId());
if (incomingLinks != null) candidateLinks.addAll(incomingLinks);
if (outgoingLinks != null) candidateLinks.addAll(outgoingLinks);
if (candidateLinks.isEmpty())
return alternativeLinks;
LinkCoherence modelCoherence = new LinkCoherence();
double modelCost = 0.0;
for (LabeledLink e : this.steinerTree.edgeSet()) {
// get the link from the graph
LabeledLink l = this.getLinkById(e.getId());
// modelCoherence.updateCoherence(this.steinerTree, l);
modelCoherence.updateCoherence(l);
modelCost += l.getWeight();
}
AlignmentScore currentScore = new AlignmentScore(modelCoherence, modelCost);
List<AlignmentScore> alignmentScores = new LinkedList<>();
for (LabeledLink l : candidateLinks) {
if (l.getModelIds() == null || l.getModelIds().isEmpty()) // ignore the links that are added by the user (not present in the known models)
continue;
// ignore the candidate links that are already in the model
if (l.getId().equalsIgnoreCase(link.getId())) continue;
AlignmentScore a = new AlignmentScore(l, currentScore);
alignmentScores.add(a);
}
Collections.sort(alignmentScores);
for (AlignmentScore a : alignmentScores) {
alternativeLinks.add(a.getLink());
}
return alternativeLinks;
}
public void align() {
// logger.debug("*** Graph ***");
// GraphUtil.printGraphSimple(this.graphBuilder.getGraph());
long start = System.currentTimeMillis();
logger.debug("updating UI preferred links ...");
this.updateLinksPreferredByUI();
logger.debug("forced links ...");
if (this.getLinksByStatus(LinkStatus.ForcedByUser) != null) {
for (LabeledLink link: this.getLinksByStatus(LinkStatus.ForcedByUser))
logger.debug("\t" + link.getId());
}
if (ModelingConfigurationRegistry.getInstance().getModelingConfiguration(ContextParametersRegistry.getInstance().getContextParameters(contextId).getKarmaHome()).getKnownModelsAlignment())
learnFromKnownSemanticModels();
else
learnFromOntology();
long elapsedTimeMillis = System.currentTimeMillis() - start;
float elapsedTimeSec = elapsedTimeMillis/1000F;
if (this.steinerTree != null) {
logger.debug("total number of nodes in steiner tree: " + this.steinerTree.vertexSet().size());
logger.debug("total number of edges in steiner tree: " + this.steinerTree.edgeSet().size());
}
logger.info(GraphUtil.labeledGraphToString(this.steinerTree));
logger.info("Time to compute the Alignment: " + elapsedTimeSec + "sec");
}
@Override
public void ontologyModelUpdated() {
this.graphBuilder.resetOntologyMaps();
}
public void cleanup() {
this.ontologyManager.unsubscribeListener(this);
this.steinerTree = null;
this.graphBuilder = new GraphBuilder(ontologyManager, false);
}
private void learnFromOntology() {
logger.debug("preparing G Prime for steiner algorithm input ...");
// GraphPreProcess graphPreProcess = new GraphPreProcess(this.graphBuilder.getGraph(),
// this.getLinksByStatus(LinkStatus.PreferredByUI),
// this.getLinksByStatus(LinkStatus.ForcedByUser));
UndirectedGraph<Node, DefaultLink> undirectedGraph = new AsUndirectedGraph<>(this.getGraph());
logger.debug("computing steiner nodes ...");
List<Node> steinerNodes = this.computeSteinerNodes();
logger.debug("steiner nodes ...");
if (steinerNodes != null) {
for (Node node: steinerNodes)
logger.debug("\t" + node.getId());
}
logger.debug("computing steiner tree ...");
SteinerTree steinerTree = new SteinerTree(undirectedGraph, steinerNodes);
WeightedMultigraph<Node, DefaultLink> tree = steinerTree.getDefaultSteinerTree();
if (tree == null) {
logger.debug("resulting tree is null ...");
return;
}
logger.debug("*** steiner tree before post processing step ***");
logger.debug(GraphUtil.defaultGraphToString(tree));
TreePostProcess treePostProcess = new TreePostProcess(this.graphBuilder, tree, getLinksByStatus(LinkStatus.ForcedByUser), true);
this.steinerTree = treePostProcess.getTree();
this.root = treePostProcess.getRoot();
logger.debug("*** steiner tree after post processing step ***");
logger.debug(GraphUtil.labeledGraphToString(this.steinerTree));
}
private void learnFromKnownSemanticModels() {
List<Node> steinerNodes = this.computeSteinerNodes();
if (steinerNodes == null || steinerNodes.isEmpty()) {
return;
}
ModelLearner modelLearner = new ModelLearner(this.graphBuilder, steinerNodes);
SemanticModel model = modelLearner.getModel();
if (model == null) {
logger.error("could not learn any model for this source!");
if (this.steinerTree == null)
{
this.steinerTree =
new DirectedWeightedMultigraph<>(LabeledLink.class);
}
this.addForcedNodes();
this.addForcedLinks(); //add new semantic type to the tree
// this.removeDeletedLinks();
this.root = TreePostProcess.selectRoot(GraphUtil.asDefaultGraph(this.steinerTree));
return ;
}
this.updateAlignment(model, null);
}
private void addForcedLinks() {
Set<LabeledLink> forcedLinks = getLinksByStatus(LinkStatus.ForcedByUser);
if (forcedLinks != null)
for (LabeledLink link : forcedLinks) {
if (!this.steinerTree.containsEdge(link)) {
if (!this.steinerTree.containsVertex(link.getSource())) {
this.steinerTree.addVertex(link.getSource());
}
if (!this.steinerTree.containsVertex(link.getTarget())) {
this.steinerTree.addVertex(link.getTarget());
}
this.steinerTree.addEdge(link.getSource(), link.getTarget(), link);
}
}
}
private void addForcedNodes() {
Set<Node> forcedNodes = this.graphBuilder.getForcedNodes();
if (forcedNodes != null)
for (Node node : forcedNodes) {
if (!this.steinerTree.containsVertex(node)) {
this.steinerTree.addVertex(node);
}
}
}
// private void removeDeletedLinks() {
// Set<LabeledLink> treeLinks = this.steinerTree.edgeSet();
// if (treeLinks != null) {
// LabeledLink[] linksArray = treeLinks.toArray(new LabeledLink[0]);
// for (LabeledLink l : linksArray) {
// if (this.getLinkById(l.getId()) == null)
// this.steinerTree.removeEdge(l);
// }
// }
// }
public void updateAlignment(SemanticModel model, List<SemanticType> semanticTypes) {
if (model == null)
return;
if (semanticTypes == null) semanticTypes = new LinkedList<>();
DirectedWeightedMultigraph<Node, LabeledLink> tree =
new DirectedWeightedMultigraph<>(LabeledLink.class);
Map<Node, Node> modelToAlignmentNode = new HashMap<>();
for (Node n : model.getGraph().vertexSet()) {
if (n instanceof InternalNode) {
InternalNode iNode;
iNode = (InternalNode)this.getNodeById(n.getId());
if (iNode != null) {
modelToAlignmentNode.put(n, iNode);
} else {
iNode = this.addInternalNode(n.getLabel());
modelToAlignmentNode.put(n, iNode);
}
tree.addVertex(iNode);
}
if (n instanceof ColumnNode && model.getMappingToSourceColumns() != null) {
ColumnNode cn = model.getMappingToSourceColumns().get(n);
modelToAlignmentNode.put(n, cn);
tree.addVertex(cn);
}
}
Node source, target;
for (LabeledLink l : model.getGraph().edgeSet()) {
if (!(l.getSource() instanceof InternalNode)) {
logger.error("column node cannot have an outgoing link!");
return;
}
source = modelToAlignmentNode.get(l.getSource());
target = modelToAlignmentNode.get(l.getTarget());
if (source == null || target == null)
continue;
String id = LinkIdFactory.getLinkId(l.getUri(), source.getId(), target.getId());
LabeledLink newLink = l.copy(id);
if (newLink == null) continue;
this.getGraphBuilder().addLink(source, target, newLink); // returns false if link already exists
tree.addEdge(source, target, newLink);
tree.setEdgeWeight(newLink, l.getWeight());
if (target instanceof ColumnNode) {
SemanticType st = new SemanticType(((ColumnNode)target).getHNodeId(),
newLink.getLabel(), source.getLabel(), source.getId(),
false,
SemanticType.Origin.User, 1.0);
semanticTypes.add(st);
}
}
this.steinerTree = tree;
this.addForcedNodes();
this.addForcedLinks();
this.root = TreePostProcess.selectRoot(GraphUtil.asDefaultGraph(tree));
}
public void updateColumnNodesInAlignment(Worksheet worksheet) {
for (HNodePath path : worksheet.getHeaders().getAllPaths()) {
HNode node = path.getLeaf();
String hNodeId = node.getId();
Node n = getNodeById(hNodeId);
if (n == null) {
addColumnNode(hNodeId, node.getColumnName(), null, null);
}
}
}
}