Java tutorial
/****************************************************************************** * Copyright 2013-2014 LASIGE * * * * 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. * * * ******************************************************************************* * An alignment between three Ontologies, stored both as a list of Mappings and * * as a Table of indexes, and including methods for input and output. * * * * @author Daniel Faria * * @date 12-09-2014 * * @version 2.1 * ******************************************************************************/ package aml.match; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.PrintWriter; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.Vector; import org.apache.commons.lang.StringEscapeUtils; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import aml.AML; import aml.match.CompoundMapping; import aml.ontology.Ontology; import aml.ontology.RelationshipMap; import aml.ontology.URIMap; import aml.settings.MappingRelation; import aml.util.Table3Map; public class CompoundAlignment implements Iterable<CompoundMapping> { //Attributes //Term mappings organized in list private Vector<CompoundMapping> maps; //Term mappings organized by the source class (Source, Target 1 , Target 2) private Table3Map<Integer, Integer, Integer, CompoundMapping> sourceMaps; //Term mappings organized by the target 1 class (Target 1 , Source, Target 2) private Table3Map<Integer, Integer, Integer, CompoundMapping> targetMaps1; //Term mappings organized by the target 2 class (Target 2, Source, Target 1) private Table3Map<Integer, Integer, Integer, CompoundMapping> targetMaps2; private boolean internal; //Constructors /** * Creates a new empty Alignment */ public CompoundAlignment() { maps = new Vector<CompoundMapping>(0, 1); sourceMaps = new Table3Map<Integer, Integer, Integer, CompoundMapping>(); targetMaps1 = new Table3Map<Integer, Integer, Integer, CompoundMapping>(); targetMaps2 = new Table3Map<Integer, Integer, Integer, CompoundMapping>(); internal = false; } /** * Creates a new empty Alignment * @return */ public CompoundAlignment(boolean internal) { maps = new Vector<CompoundMapping>(0, 1); sourceMaps = new Table3Map<Integer, Integer, Integer, CompoundMapping>(); targetMaps1 = new Table3Map<Integer, Integer, Integer, CompoundMapping>(); targetMaps2 = new Table3Map<Integer, Integer, Integer, CompoundMapping>(); this.internal = internal; } /** * Reads an Alignment from an input file * @param file: the path to the input file */ public CompoundAlignment(String file) throws Exception { this(); if (file.endsWith(".rdf")) loadMappingsRDF(file); else if (file.endsWith(".tsv")) loadMappingsTSV(file); else throw new Exception("Unrecognized alignment format!"); } /** * Creates a new Alignment that is a copy of the input alignment * @param a: the Alignment to copy */ public CompoundAlignment(CompoundAlignment a) { this(); addAll(a); } //Public Methods /** * Adds a new Mapping to the alignment if it is non-redundant * Otherwise, updates the similarity of the already present Mapping * to the maximum similarity of the two redundant Mappings * @param sourceId: the index of the source class to add to the alignment * @param targetId1: the index of the target 1 class to add to the alignment * @param targetId2: the index of the target 2 class to add to the alignment * @param sim: the similarity between the classes */ public void add(int sourceId, int targetId1, int targetId2, double sim) { //Unless the alignment is internal, we can't have a mapping //between entities with the same id (which corresponds to URI) if (!internal && sourceId == targetId1 || sourceId == targetId2 || targetId1 == targetId2) return; //Construct the Mapping CompoundMapping m = new CompoundMapping(sourceId, targetId1, targetId2, sim, MappingRelation.EQUIVALENCE); //If it isn't listed yet, add it if (!sourceMaps.contains(sourceId, targetId1, targetId2)) { maps.add(m); sourceMaps.add(sourceId, targetId1, targetId2, m); targetMaps1.add(targetId1, sourceId, targetId2, m); targetMaps2.add(targetId2, sourceId, targetId1, m); } //Otherwise update the similarity else { m = sourceMaps.get(sourceId, targetId1, targetId2); if (m.getSimilarity() < sim) m.setSimilarity(sim); if (!m.getRelationship().equals(MappingRelation.EQUIVALENCE)) m.setRelationship(MappingRelation.EQUIVALENCE); } } /** * Adds a new Mapping to the alignment if it is non-redundant * Otherwise, updates the similarity of the already present Mapping * to the maximum similarity of the two redundant Mappings * @param sourceId: the index of the source class to add to the alignment * @param targetId1: the index of the target 1 class to add to the alignment * @param targetId2: the index of the target 2 class to add to the alignment * @param sim: the similarity between the classes * @param r: the mapping relationship between the classes */ public void add(int sourceId, int targetId1, int targetId2, double sim, MappingRelation r) { //We can't have a mapping between entities with the same URI if (sourceId == targetId1 || sourceId == targetId2 || targetId1 == targetId2) return; //Construct the Mapping CompoundMapping m = new CompoundMapping(sourceId, targetId1, targetId2, sim, r); //If it isn't listed yet, add it if (sourceMaps == null || !sourceMaps.contains(sourceId, targetId1, targetId2)) { maps.add(m); sourceMaps.add(sourceId, targetId1, targetId2, m); targetMaps1.add(targetId1, sourceId, targetId2, m); targetMaps2.add(targetId2, sourceId, targetId1, m); } //Otherwise update the similarity else { CompoundMapping map = sourceMaps.get(sourceId, targetId1, targetId2); if (map.getSimilarity() < sim) map.setSimilarity(sim); if (!map.getRelationship().equals(r)) map.setRelationship(r); } } /** * Adds a clone of the given Mapping to the alignment if it is non-redundant * Otherwise, updates the similarity of the already present Mapping * to the maximum similarity of the two redundant Mappings * @param m: the Mapping to add to the alignment */ public void add(CompoundMapping m) { add(m.getSourceId(), m.getTargetId1(), m.getTargetId2(), m.getSimilarity(), m.getRelationship()); } /** * Adds all Mappings in a to this Alignment * @param a: the CompoundAlignment to add to this Alignment */ public void addAll(CompoundAlignment a) { addAll(a.maps); } /** * Adds all CompoundMappings in the given list to this CompoundAlignment * @param maps: the list of CompoundMappings to add to this CompoundAlignment */ public void addAll(List<CompoundMapping> maps) { for (CompoundMapping m : maps) add(m); } /** * Adds all CompoundMappings in a to this CompoundAlignment as long as * they don't conflict with any CompoundMapping in a * @param a: the CompoundAlignment to add to this ACompoundlignment */ public void addAllNonConflicting(CompoundAlignment a) { Vector<CompoundMapping> nonConflicting = new Vector<CompoundMapping>(); for (CompoundMapping m : a.maps) if (!this.containsConflict(m)) nonConflicting.add(m); addAll(nonConflicting); } /** * @return the average cardinality of this alignment */ public double cardinality() { double cardinality = 0.0; Set<Integer> sources = sourceMaps.keySet(); for (Integer i : sources) cardinality += sourceMaps.keySet(i).size(); Set<Integer> targets1 = targetMaps1.keySet(); for (Integer i : targets1) cardinality += targetMaps1.keySet(i).size(); Set<Integer> targets2 = targetMaps2.keySet(); for (Integer i : targets2) cardinality += targetMaps2.keySet(i).size(); cardinality /= sources.size() + targets1.size() + targets2.size(); return cardinality; } /** * @param sourceId: the index of the source class to check in the alignment * @param targetId1: the index of the target 1 class to add to the alignment * @param targetId2: the index of the target 2 class to add to the alignment * @return whether the alignment contains a CompoundMapping that is ancestral to the given pair of classes * (i.e. includes one ancestor of sourceId and one ancestor of targetId) */ public boolean containsAncestralMapping(int sourceId, int targetId1, int targetId2) { AML aml = AML.getInstance(); RelationshipMap rels = aml.getRelationshipMap(); Set<Integer> sourceAncestors = rels.getAncestors(sourceId); Set<Integer> targetAncestors1 = rels.getAncestors(targetId1); Set<Integer> targetAncestors2 = rels.getAncestors(targetId2); for (Integer sa : sourceAncestors) { Set<Integer> over = getSourceMappings(sa); for (Integer ta1 : targetAncestors1) if (over.contains(ta1)) return true; for (Integer ta2 : targetAncestors2) if (over.contains(ta2)) return true; } return false; } /** * @param m: the CompoundMapping to check in the alignment * @return whether the CompoundAlignment contains a CompoundMapping that conflicts with the given * Mapping and has a higher similarity */ public boolean containsBetterMapping(CompoundMapping m) { int source = m.getSourceId(); int target1 = m.getTargetId1(); int target2 = m.getTargetId2(); double sim = m.getSimilarity(); if (containsSource(source)) { Set<Integer> targets = sourceMaps.keySet(source); for (Integer i : targets) { for (Integer j : sourceMaps.keySet(source, i)) { if (getSimilarity(source, i, j) > sim) return true; } } } if (containsTarget1(target1)) { Set<Integer> sources = targetMaps1.keySet(target1); for (Integer i : sources) { for (Integer j : targetMaps1.keySet(target1, i)) { if (getSimilarity(i, target1, j) > sim) return true; } } } if (containsTarget2(target2)) { Set<Integer> sources = targetMaps2.keySet(target2); for (Integer i : sources) for (Integer j : targetMaps2.keySet(target2, i)) { if (getSimilarity(i, j, target2) > sim) return true; } } return false; } /** * @param classId: the index of the class to check in the alignment * @return whether the CompoundAlignment contains a CompoundMapping with that class * (either as a source or as a target class) */ public boolean containsClass(int classId) { return containsSource(classId) || containsTarget1(classId) || containsTarget2(classId); } /** * @param sourceId: the index of the source class to check in the alignment * @param targetId1: the index of the target 1 class to check in the alignment * @param targetId2: the index of the target 2 class to check in the alignment * @return whether the CompoundAlignment contains a CompoundMapping for sourceId or for targetId */ public boolean containsConflict(int sourceId, int targetId1, int targetId2) { return containsSource(sourceId) || containsTarget1(targetId1) || containsTarget2(targetId2); } /** * @param m: the CompoundMapping to check in the alignment * @return whether the CompoundAlignment contains a CompoundMapping involving either class in m */ public boolean containsConflict(CompoundMapping m) { return containsConflict(m.getSourceId(), m.getTargetId1(), m.getTargetId2()); } /** * @param sourceId: the index of the source class to check in the alignment * @param targetId1: the index of the target 1 class to check in the alignment * @param targetId2: the index of the target 2 class to check in the alignment * @return whether the alignment contains a CompoundMapping that is descendant of the given pair of classes * (i.e. includes one descendant of sourceId and one descendant of targetId) */ public boolean containsDescendantMapping(int sourceId, int targetId1, int targetId2) { AML aml = AML.getInstance(); RelationshipMap rels = aml.getRelationshipMap(); Set<Integer> sourceDescendants = rels.getDescendants(sourceId); Set<Integer> targetDescendants1 = rels.getDescendants(targetId1); Set<Integer> targetDescendants2 = rels.getDescendants(targetId2); for (Integer sa : sourceDescendants) { Set<Integer> over = getSourceMappings(sa); for (Integer ta : targetDescendants1) if (over.contains(ta)) return true; for (Integer ta2 : targetDescendants2) if (over.contains(ta2)) return true; } return false; } /** * @param sourceId: the index of the source class to check in the alignment * @param targetId1: the index of the target 1 class to check in the alignment * @param targetId2: the index of the target 2 class to check in the alignment * @return whether the CompoundAlignment contains a CompoundMapping between sourceId and targetId */ public boolean containsMapping(int sourceId, int targetId1, int targetId2) { return sourceMaps.contains(sourceId, targetId1, targetId2); } /** * @param m: the CompoundMapping to check in the alignment * @return whether the CompoundAlignment contains a CompoundMapping equivalent to m */ public boolean containsMapping(CompoundMapping m) { return sourceMaps.contains(m.getSourceId(), m.getTargetId1(), m.getTargetId2()); } /** * @param lm: the List of CompoundMapping to check in the alignment * @return whether the CompoundAlignment contains all the CompoundMapping listed in m */ public boolean containsMappings(List<CompoundMapping> lm) { for (CompoundMapping m : lm) if (!containsMapping(m)) return false; return true; } /** * @param sourceId: the index of the source class to check in the alignment * @param targetId1: the index of the target 1 class to check in the alignment * @param targetId2: the index of the target 2 class to check in the alignment * @return whether the alignment contains a Mapping that is parent to the * given pair of classes on one side only */ public boolean containsParentMapping(int sourceId, int targetId1, int targetId2) { AML aml = AML.getInstance(); RelationshipMap rels = aml.getRelationshipMap(); Set<Integer> sourceAncestors = rels.getParents(sourceId); Set<Integer> targetAncestors1 = rels.getParents(targetId1); Set<Integer> targetAncestors2 = rels.getParents(targetId2); for (Integer sa : sourceAncestors) if (containsMapping(sa, targetId1, targetId2)) return true; for (Integer ta : targetAncestors1) if (containsMapping(sourceId, ta, targetId2)) return true; for (Integer ta2 : targetAncestors2) if (containsMapping(sourceId, targetId1, ta2)) return true; return false; } /** * @param sourceId: the index of the source class to check in the alignment * @return whether the Alignment contains a Mapping for sourceId */ public boolean containsSource(int sourceId) { return sourceMaps.contains(sourceId); } /** * @param targetId1: the index of the target 1 class to check in the alignment * @return whether the CompoundAlignment contains a CompoundMapping for targetId1 */ public boolean containsTarget1(int targetId1) { return targetMaps1.contains(targetId1); } /** * * @param targetId2: the index of the target 2 class to check in the alignment * @return whether the CompoundAlignment contains a CompoundMapping for targetId2 */ public boolean containsTarget2(int targetId2) { return targetMaps2.contains(targetId2); } /** * @param a: the Alignment to subtract from this Alignment * @return the Alignment corresponding to the difference between this Alignment and a */ public CompoundAlignment difference(CompoundAlignment a) { CompoundAlignment diff = new CompoundAlignment(); for (CompoundMapping m : maps) if (!a.containsMapping(m)) diff.add(m); return diff; } /** * @param ref: the reference Alignment to evaluate this Alignment * @param forGUI: whether the evaluation is for display in the GUI * or for output to the console * @return the evaluation of this Alignment */ public String evaluate(CompoundAlignment ref, boolean forGUI) { int found = size(); int correct = 0; int total = 0; int conflict = 0; for (CompoundMapping m : maps) { if (ref.containsMapping(m)) { if (ref.getRelationship(m.getSourceId(), m.getTargetId1(), m.getTargetId2()) .equals(MappingRelation.UNKNOWN)) conflict++; else correct++; } } for (CompoundMapping m : ref) if (!m.getRelationship().equals(MappingRelation.UNKNOWN)) total++; double precision = 1.0 * correct / (found - conflict); String prc = Math.round(precision * 1000) / 10.0 + "%"; double recall = 1.0 * correct / total; String rec = Math.round(recall * 1000) / 10.0 + "%"; double fmeasure = 2 * precision * recall / (precision + recall); String fms = Math.round(fmeasure * 1000) / 10.0 + "%"; if (forGUI) return "Precision: " + prc + "; Recall: " + rec + "; F-measure: " + fms; else return "Precision\tRecall\tF-measure\tFound\tCorrect\tReference\n" + prc + "\t" + rec + "\t" + fms + "\t" + found + "\t" + correct + "\t" + total; } public Double[] evaluateNoPrint(CompoundAlignment ref) { double found = size(); double correct = 0; double total = 0; double conflict = 0; for (CompoundMapping m : maps) { if (ref.containsMapping(m)) { if (ref.getRelationship(m.getSourceId(), m.getTargetId1(), m.getTargetId2()) .equals(MappingRelation.UNKNOWN)) conflict++; else correct++; } } for (CompoundMapping m : ref) if (!m.getRelationship().equals(MappingRelation.UNKNOWN)) total++; double precision = 1.0 * correct / (found - conflict); double recall = 1.0 * correct / total; double fmeasure = 2 * precision * recall / (precision + recall); return new Double[] { precision, recall, fmeasure, found, correct, total, }; } /** * @param a: the base Alignment to which this Alignment will be compared * @return the gain (i.e. the fraction of new Mappings) of this Alignment * in comparison with the base Alignment */ public double gain(CompoundAlignment a) { double gain = 0.0; for (CompoundMapping m : maps) if (!a.containsMapping(m)) gain++; gain /= a.size(); return gain; } /** * @param a: the base Alignment to which this Alignment will be compared * @return the gain (i.e. the fraction of new Mappings) of this Alignment * in comparison with the base Alignment */ /* public double gainOneToOne(CompoundAlignment a) { double sourceGain = 0.0; Set<Integer> sources = sourceMaps.keySet(); for(Integer i : sources) if(!a.containsSource(i)) sourceGain++; sourceGain /= a.sourceCount(); double targetGain1 = 0.0; Set<Integer> targets1 = targetMaps1.keySet(); for(Integer i : targets1) if(!a.containsTarget1(i)) targetGain1++; double targetGain2 = 0.0; Set<Integer> targets2 = targetMaps2.keySet(); for(Integer i : targets2) if(!a.containsTarget2(i))) targetGain2++; targetGain1 /= a.targetCount(); return Math.min(sourceGain, targetGain); } */ /** * @param index: the index of the Mapping to return in the list of Mappings * @return the Mapping at the input index (note that the index will change * during sorting) or null if the index falls outside the list */ public CompoundMapping get(int index) { if (index < 0 || index >= maps.size()) return null; return maps.get(index); } /** * @param sourceId: the index of the source class to check in the alignment * @param targetId: the index of the target class to check in the alignment * @return the Mapping between the source and target classes or null if no * such Mapping exists */ public CompoundMapping get(int sourceId, int targetId1, int targetId2) { return sourceMaps.get(sourceId, targetId1, targetId2); } /** * @param id1: the index of the first class to check in the alignment * @param targetId: the index of the second class to check in the alignment * @return the Mapping between the classes or null if no such Mapping exists * in either direction */ public CompoundMapping getBidirectional(int id1, int id2, int id3) { if (sourceMaps.contains(id1, id2, id3)) return sourceMaps.get(id1, id2, id3); else if (sourceMaps.contains(id2, id1, id3)) return sourceMaps.get(id2, id1, id3); else if (sourceMaps.contains(id3, id1, id2)) return sourceMaps.get(id3, id1, id2); else if (sourceMaps.contains(id2, id1, id3)) return sourceMaps.get(id2, id3, id1); else return null; } public CompoundMapping getBestSourceCompoundMatch(CompoundMapping m) { double max = 0; CompoundMapping target = new CompoundMapping(m.getSourceId()); Set<Integer> targets1 = sourceMaps.keySet(m.getSourceId()); for (Integer i : targets1) { Set<Integer> targets2 = sourceMaps.keySet(m.getSourceId(), i); for (Integer j : targets2) { double sim = getSimilarity(m.getSourceId(), i, j); if (sim > max) { max = sim; target.setTargetId1(i); target.setTargetId2(j); target.setSimilarity(max); } } } return target; } /** * @param sourceId: the index of the source class * @param targetId: the index of the target class * @return the index of the Mapping between the given classes in * the list of Mappings, or -1 if the Mapping doesn't exist */ public int getIndex(int sourceId, int targetId1, int targetId2) { if (sourceMaps.contains(sourceId, targetId1, targetId2)) return maps.indexOf(sourceMaps.get(sourceId, targetId1, targetId2)); else return -1; } /** * @param id1: the index of the first class * @param id2: the index of the second class * @return the index of the Mapping between the given classes in * the list of Mappings (in any order), or -1 if the Mapping doesn't exist */ /* public int getIndexBidirectional(int id1, int id2, int id3) { if(sourceMaps.contains(id1, id2, id3)) return maps.indexOf(sourceMaps.get(id1, id2)); else if(targetMaps.contains(id1, id2)) return maps.indexOf(targetMaps.get(id1, id2)); else return -1; } */ /** * @param id: the index of the class to check in the alignment * @return the list of all classes mapped to the given class */ public Set<Integer> getMappingsBidirectional(int id) { HashSet<Integer> mappings = new HashSet<Integer>(); if (sourceMaps.contains(id)) mappings.addAll(sourceMaps.keySet(id)); if (targetMaps1.contains(id)) mappings.addAll(targetMaps1.keySet(id)); if (targetMaps2.contains(id)) mappings.addAll(targetMaps2.keySet(id)); return mappings; } /** * @param sourceId: the index of the source class to check in the alignment * @return the index of the target class that best matches source */ /* public double getMaxSourceSim(int sourceId) { double max = 0; Set<Integer> targets = sourceMaps.keySet(sourceId); for(Integer i : targets) { double sim = getSimilarity(sourceId,i); if(sim > max) max = sim; } return max; } */ /** * @param targetId: the index of the target class to check in the alignment * @return the index of the source class that best matches target */ /* public double getMaxTargetSim(int targetId) { double max = 0; Set<Integer> sources = targetMaps.keySet(targetId); for(Integer i : sources) { double sim = getSimilarity(i,targetId); if(sim > max) max = sim; } return max; } */ /** * @param sourceId: the index of the source class in the alignment * @param targetId: the index of the target class in the alignment * @return the mapping relationship between source and target */ public MappingRelation getRelationship(int sourceId, int targetId1, int targetId2) { CompoundMapping m = sourceMaps.get(sourceId, targetId1, targetId2); if (m == null) return null; return m.getRelationship(); } /** * @param sourceId: the index of the source class in the alignment * @param targetId: the index of the target class in the alignment * @return the similarity between source and target */ public double getSimilarity(int sourceId, int targetId1, int targetId2) { CompoundMapping m = sourceMaps.get(sourceId, targetId1, targetId2); if (m == null) return 0.0; return m.getSimilarity(); } /** * @param sourceId: the index of the source class to check in the alignment * @return the list of all target classes mapped to the source class */ public Set<Integer> getSourceMappings(int sourceId) { if (sourceMaps.contains(sourceId)) return sourceMaps.keySet(sourceId); return new HashSet<Integer>(); } /** * @return the list of all source classes that have mappings */ public Set<Integer> getSources() { HashSet<Integer> sMaps = new HashSet<Integer>(); sMaps.addAll(sourceMaps.keySet()); return sMaps; } /** * @param targetId: the index of the target class to check in the alignment * @return the list of all source classes mapped to the target class */ public Set<Integer> getTarget1Mappings(int targetId1) { if (targetMaps1.contains(targetId1)) return targetMaps1.keySet(targetId1); return new HashSet<Integer>(); } /** * @param targetId: the index of the target class to check in the alignment * @return the list of all source classes mapped to the target class */ public Set<Integer> getTarget2Mappings(int targetId2) { if (targetMaps2.contains(targetId2)) return targetMaps2.keySet(targetId2); return new HashSet<Integer>(); } /** * @return the list of all target classes that have mappings */ public Set<Integer> getTargets1() { HashSet<Integer> tMaps = new HashSet<Integer>(); tMaps.addAll(targetMaps1.keySet()); return tMaps; } /** * @return the list of all target classes that have mappings */ public Set<Integer> getTargets2() { HashSet<Integer> tMaps = new HashSet<Integer>(); tMaps.addAll(targetMaps2.keySet()); return tMaps; } /** * @param a: the Alignment to intersect with this Alignment * @return the Alignment corresponding to the intersection between this Alignment and a */ public CompoundAlignment intersection(CompoundAlignment a) { //Otherwise, compute the intersection CompoundAlignment intersection = new CompoundAlignment(); for (CompoundMapping m : maps) if (a.containsMapping(m)) intersection.add(m); return intersection; } @Override /** * @return an Iterator over the list of class Mappings */ public Iterator<CompoundMapping> iterator() { return maps.iterator(); } /** * @return the maximum cardinality of this alignment */ public double maxCardinality() { double cardinality; double max = 0.0; Set<Integer> sources = sourceMaps.keySet(); for (Integer i : sources) { cardinality = sourceMaps.keySet(i).size(); if (cardinality > max) max = cardinality; } Set<Integer> targets1 = targetMaps1.keySet(); for (Integer i : targets1) { cardinality = targetMaps1.keySet(i).size(); if (cardinality > max) max = cardinality; } Set<Integer> targets2 = targetMaps2.keySet(); for (Integer i : targets2) { cardinality = targetMaps2.keySet(i).size(); if (cardinality > max) max = cardinality; } return max; } /** * Removes the given Mapping from the Alignment * @param m: the Mapping to remove from the Alignment */ public void remove(CompoundMapping m) { int sourceId = m.getSourceId(); int targetId1 = m.getTargetId1(); int targetId2 = m.getTargetId2(); sourceMaps.remove(sourceId, targetId1); targetMaps1.remove(targetId1, sourceId); targetMaps2.remove(targetId2, sourceId); maps.remove(m); } /** * Removes the Mapping between the given classes from the Alignment * @param sourceId: the source class to remove from the Alignment * @param targetId: the target class to remove from the Alignment */ public void remove(int sourceId, int targetId1, int targetId2) { CompoundMapping m = new CompoundMapping(sourceId, targetId1, targetId2, 1.0); sourceMaps.remove(sourceId, targetId1); targetMaps1.remove(targetId1, sourceId); targetMaps2.remove(targetId2, sourceId); maps.remove(m); } /** * Removes a list of Mappings from the alignment. * @param maps: the list of Mappings to remove to this Alignment */ public void removeAll(List<CompoundMapping> maps) { for (CompoundMapping m : maps) remove(m); } /** * Saves the alignment into an .rdf file in OAEI format * @param file: the output file */ public void saveRDF(String file) throws FileNotFoundException { AML aml = AML.getInstance(); String sourceURI = aml.getSource().getURI(); String target1URI = aml.getTarget().getURI(); String target2URI = aml.getTarget2().getURI(); URIMap uris = aml.getURIMap(); PrintWriter outStream = new PrintWriter(new FileOutputStream(file)); outStream.println("<?xml version='1.0' encoding='utf-8'?>"); outStream.println("<rdf:RDF xmlns='http://knowledgeweb.semanticweb.org/heterogeneity/alignment'"); outStream.println("\t xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' "); outStream.println("\t xmlns:xsd='http://www.w3.org/2001/XMLSchema#' "); outStream.println("\t alignmentSource='AgreementMakerLight'>\n"); outStream.println("<Alignment>"); outStream.println("\t<xml>yes</xml>"); outStream.println("\t<level>0</level>"); double card = cardinality(); if (card < 1.02) outStream.println("\t<type>11</type>"); else outStream.println("\t<type>??</type>"); outStream.println("\t<onto1>" + sourceURI + "</onto1>"); outStream.println("\t<onto2>" + target1URI + "</onto2>"); outStream.println("\t<onto3>" + target2URI + "</onto3>"); outStream.println("\t<uri1>" + sourceURI + "</uri1>"); outStream.println("\t<uri2>" + target1URI + "</uri2>"); outStream.println("\t<uri3>" + target2URI + "</uri3>"); for (CompoundMapping m : maps) { outStream.println("\t<map>"); outStream.println("\t\t<Cell>"); outStream.println("\t\t\t<entity1 rdf:resource=\"" + uris.getURI(m.getSourceId()) + "\"/>"); outStream.println("\t\t\t<entity2 rdf:resource=\"" + uris.getURI(m.getTargetId1()) + "\"/>"); outStream.println("\t\t\t<entity3 rdf:resource=\"" + uris.getURI(m.getTargetId2()) + "\"/>"); outStream.println("\t\t\t<measure rdf:datatype=\"http://www.w3.org/2001/XMLSchema#float\">" + m.getSimilarity() + "</measure>"); outStream.println("\t\t\t<relation>" + StringEscapeUtils.escapeXml(m.getRelationship().toString()) + "</relation>"); outStream.println("\t\t</Cell>"); outStream.println("\t</map>"); } outStream.println("</Alignment>"); outStream.println("</rdf:RDF>"); outStream.close(); } /** * Saves the alignment into a .tsv file in AML format * @param file: the output file */ public void saveTSV(String file) throws FileNotFoundException { AML aml = AML.getInstance(); Ontology source = aml.getSource(); Ontology target1 = aml.getTarget(); Ontology target2 = aml.getTarget2(); URIMap uris = aml.getURIMap(); PrintWriter outStream = new PrintWriter(new FileOutputStream(file)); outStream.println("#AgreementMakerLight Alignment File"); outStream.println("#Source ontology:\t" + source.getURI()); outStream.println("#First Target ontology:\t" + target1.getURI()); outStream.println("#Second Target ontology:\t" + target2.getURI()); outStream.println("Source URI\tSource Label\t" + "Target 1 URI\tTarget 1 Label\t" + "Target 2 URI\tTarget 2Label\tSimilarity\tRelationship"); for (CompoundMapping m : maps) { outStream.println(uris.getURI(m.getSourceId()) + "\t" + source.getName(m.getSourceId()) + "\t" + uris.getURI(m.getTargetId1()) + "\t" + target1.getName(m.getTargetId1()) + "\t" + uris.getURI(m.getTargetId2()) + "\t" + target2.getName(m.getTargetId2()) + "\t" + m.getSimilarity() + "\t" + m.getRelationship().toString()); } outStream.close(); } /** * Saves the alignment into a .tsv file in AML format. Also shows the ancestors for each class * @param file: the output file */ public void saveTSV2(String file) throws FileNotFoundException { AML aml = AML.getInstance(); RelationshipMap rels = aml.getRelationshipMap(); Ontology source = aml.getSource(); Ontology target1 = aml.getTarget(); Ontology target2 = aml.getTarget2(); URIMap uris = aml.getURIMap(); PrintWriter outStream = new PrintWriter(new FileOutputStream(file)); outStream.println("#AgreementMakerLight Alignment File"); outStream.println("#Source ontology:\t" + source.getURI()); outStream.println("#First Target ontology:\t" + target1.getURI()); outStream.println("#Second Target ontology:\t" + target2.getURI()); outStream.println("Source URI\tSource Label\tSource Ancestors\t" + "Target 1 URI\tTarget 1 Label\tTarget 1 Ancestors\t" + "Target 2 URI\tTarget 2Label\tTarget 2 Ancestors\tSimilarity\tRelationship"); for (CompoundMapping m : maps) { Set<Integer> srcAnc = rels.getAncestors(m.getSourceId(), 1); Set<Integer> tgtAnc1 = rels.getAncestors(m.getTargetId1(), 1); Set<Integer> tgtAnc2 = rels.getAncestors(m.getTargetId2(), 1); String a1 = ""; String a2 = ""; String a3 = ""; for (Integer s : srcAnc) { a1 += source.getName(s); if (!a1.equals("")) break; } for (Integer t : tgtAnc1) { a2 += target1.getName(t); if (!a2.equals("")) break; } for (Integer t2 : tgtAnc2) { a3 += target2.getName(t2); if (!a3.equals("")) break; } outStream.println(uris.getURI(m.getSourceId()) + "\t" + source.getName(m.getSourceId()) + "\t" + a1 + "\t" + uris.getURI(m.getTargetId1()) + "\t" + target1.getName(m.getTargetId1()) + "\t" + a2 + "\t" + uris.getURI(m.getTargetId2()) + "\t" + target2.getName(m.getTargetId2()) + "\t" + a3 + "\t" + m.getSimilarity() + "\t" + m.getRelationship().toString()); } outStream.close(); } public void saveTSV3(String file) throws FileNotFoundException { AML aml = AML.getInstance(); Ontology source = aml.getSource(); Ontology target1 = aml.getTarget(); Ontology target2 = aml.getTarget2(); URIMap uris = aml.getURIMap(); PrintWriter outStream = new PrintWriter(new FileOutputStream(file)); outStream.println("#AgreementMakerLight Alignment File"); outStream.println("#Source ontology:\t" + source.getURI()); outStream.println("#First Target ontology:\t" + target1.getURI()); outStream.println("#Second Target ontology:\t" + target2.getURI()); outStream.println("Source URI\tSource Label\t" + "Target 1 URI\tTarget 1 Label\t" + "Target 2 URI\tTarget 2Label\tSimilarity\tRelationship"); for (CompoundMapping m : maps) { outStream.println(uris.getURI(m.getSourceId()) + "\t" + source.getLexicon().getCorrectedName(m.getSourceId()) + "\t" + uris.getURI(m.getTargetId1()) + "\t" + target1.getLexicon().getCorrectedName(m.getTargetId1()) + "\t" + uris.getURI(m.getTargetId2()) + "\t" + target2.getLexicon().getCorrectedName(m.getTargetId2()) + "\t" + m.getSimilarity() + "\t" + m.getRelationship().toString()); } outStream.close(); } /** * @return the number of Mappings in this Alignment */ public int size() { return maps.size(); } /** * Sorts the Alignment descendingly, by similarity */ public void sort() { Collections.sort(maps, new Comparator<CompoundMapping>() { public int compare(CompoundMapping m1, CompoundMapping m2) { double diff = m2.getSimilarity() - m1.getSimilarity(); if (diff < 0) return -1; if (diff > 0) return 1; return 0; } }); } /** * @return the number of source classes mapped in this Alignment */ public int sourceCount() { return sourceMaps.keyCount(); } /** * @return the fraction of source classes mapped in this Alignment */ public double sourceCoverage() { AML aml = AML.getInstance(); double coverage = sourceMaps.keyCount(); int count = aml.getSource().classCount(); coverage /= count; return coverage; } /** * @return the number of target classes mapped in this Alignment */ public int targetCount1() { return targetMaps1.keyCount(); } public int targetCount2() { return targetMaps2.keyCount(); } /** * @return the fraction of target classes mapped in this Alignment */ public double[] targetCoverage() { AML aml = AML.getInstance(); double coverage1 = targetMaps1.keyCount(); int count1 = aml.getTarget().classCount(); double coverage2 = targetMaps2.keyCount(); int count2 = aml.getTarget2().classCount(); coverage1 /= count1; coverage2 /= count2; return new double[] { coverage1, coverage2 }; } //Private Methods private void loadMappingsRDF(String file) throws DocumentException { AML aml = AML.getInstance(); URIMap uris = aml.getURIMap(); //Open the alignment file using SAXReader SAXReader reader = new SAXReader(); File f = new File(file); Document doc = reader.read(f); //Read the root, then go to the "Alignment" element Element root = doc.getRootElement(); Element align = root.element("Alignment"); //Get an iterator over the mappings Iterator<?> map = align.elementIterator("map"); while (map.hasNext()) { //Get the "Cell" in each mapping Element e = ((Element) map.next()).element("Cell"); if (e == null) { continue; } //Get the source class String sourceURI = e.element("entity1").element("Class").attributeValue("about"); uris.addURI(sourceURI); //Get the target class //Get the both target classes List<Element> elements = e.element("entity2").element("Class").element("and").elements("Class"); //Get the target 1 String targetURI = elements.get(0).attributeValue("about"); uris.addURI(targetURI); //Get the target 2 String target2URI = elements.get(1).attributeValue("about"); uris.addURI(target2URI); //Get the similarity measure String measure = e.elementText("measure"); //Parse it, assuming 1 if a valid measure is not found double similarity = 1; if (measure != null) { try { similarity = Double.parseDouble(measure); if (similarity < 0 || similarity > 1) similarity = 1; } catch (Exception ex) { /*Do nothing - use the default value*/} ; } //Get the relation String r = e.elementText("relation"); if (r == null) r = "?"; MappingRelation rel = MappingRelation.parseRelation(StringEscapeUtils.unescapeXml(r)); //Check if the URIs are listed in the URI map int sourceIndex = uris.getIndex(sourceURI); int targetIndex = uris.getIndex(targetURI); int targetIndex2 = uris.getIndex(target2URI); //If they are, add the mapping to the maps and proceed to next mapping if (sourceIndex > -1 && targetIndex > -1 && targetIndex2 > -1) { if (sourceIndex < targetIndex) add(sourceIndex, targetIndex, targetIndex2, similarity, rel); else add(targetIndex, sourceIndex, targetIndex2, similarity, rel); } } } private void loadMappingsTSV(String file) throws Exception { AML aml = AML.getInstance(); URIMap uris = aml.getURIMap(); BufferedReader inStream = new BufferedReader(new FileReader(file)); //First line contains the reference to AML inStream.readLine(); //Second line contains the source ontology inStream.readLine(); //Third line contains the target ontology inStream.readLine(); //Fourth line contains the headers inStream.readLine(); //And from the fifth line forward we have mappings String line; while ((line = inStream.readLine()) != null) { String[] col = line.split("\t"); //First column contains the source uri String sourceURI = col[0]; //Third contains the target uri String targetURI = col[2]; //Fifth contains the similarity String target2URI = col[4]; String measure = col[6]; //Parse it, assuming 1 if a valid measure is not found double similarity = 1; if (measure != null) { try { similarity = Double.parseDouble(measure); if (similarity < 0 || similarity > 1) similarity = 1; } catch (Exception ex) { /*Do nothing - use the default value*/} ; } //Finally, sixth column contains the type of relation MappingRelation rel; if (col.length > 5) rel = MappingRelation.parseRelation(col[5]); //For compatibility with previous tsv format without listed relation else rel = MappingRelation.EQUIVALENCE; //Get the indexes int sourceIndex = uris.getIndex(sourceURI); int targetIndex = uris.getIndex(targetURI); int targetIndex2 = uris.getIndex(target2URI); //If they are, add the mapping to the maps and proceed to next mapping if (sourceIndex > -1 && targetIndex > -1 && targetIndex2 > -1) { if (sourceIndex < targetIndex && sourceIndex < targetIndex2) add(sourceIndex, targetIndex, targetIndex2, similarity, rel); else add(targetIndex, sourceIndex, targetIndex2, similarity, rel); } } inStream.close(); } }