/* * Concept profile generation tool suite * Copyright (C) 2015 Biosemantics Group, Erasmus University Medical Center, * Rotterdam, The Netherlands * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/> */ package org.erasmusmc.ontology; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import org.erasmusmc.collections.IntList; import org.erasmusmc.ids.DatabaseID; import org.erasmusmc.rmi.ontology.conceptrelations.ConceptRelation; /** * Class for storing an ontology in memory * * @author Schuemie * */ public class OntologyStore extends Ontology { private Map<Integer, Concept> id2concept = new TreeMap<Integer, Concept>(); private String name = ""; private Map<Integer, List<Relation>> id2subjectrelations = new HashMap<Integer, List<Relation>>(); private Map<Integer, List<Relation>> id2objectrelations = new HashMap<Integer, List<Relation>>(); private Map<Integer, List<DatabaseID>> id2DatabaseID = new HashMap<Integer, List<DatabaseID>>(); private Map<DatabaseID, Set<Integer>> databaseID2id = null; /** * Creates an index from database IDs to concepts. Will drastically speed up * the getConceptIDs method, but will cost more memory. */ public void createIndexForDatabaseIDs() { databaseID2id = new HashMap<DatabaseID, Set<Integer>>(); for (Map.Entry<Integer, List<DatabaseID>> entry: id2DatabaseID.entrySet()) for (DatabaseID databaseID: entry.getValue()) { Set<Integer> conceptIDs = databaseID2id.get(databaseID); if (conceptIDs == null) { conceptIDs = new HashSet<Integer>(); databaseID2id.put(databaseID, conceptIDs); } conceptIDs.add(entry.getKey()); } } /** * Removes the index created with the createIndexForDatabaseIDs method and * frees the memory used. */ public void deleteIndexForDatabaseIDs() { databaseID2id = null; System.gc(); } public Map<Integer, Concept> getConcepts(Collection<Integer> ids) { Map<Integer, Concept> map = new HashMap<Integer, Concept>(); for (int i: ids) { map.put(i, getConcept(i)); } return map; } public Map<Integer, Concept> getConceptSubset(int offset, int limit) { Map<Integer, Concept> map = new HashMap<Integer, Concept>(); Object[] collection = id2concept.values().toArray(); for (int i = offset; i < offset + limit; i++) { map.put(i, (Concept) collection[i]); } return map; } public int size() { return id2concept.size(); } @Override public Concept getConcept(int id) { return id2concept.get(id); } @Override public void setConcept(Concept concept) { id2concept.put(concept.getID(), concept); } @Override public String getName() { return name; } @Override public void setName(String name) { this.name = name; } @Override public Iterator<Concept> getConceptIterator() { return new ConceptIterator(); } public class ConceptIterator implements Iterator<Concept> { List<Integer> ids; Integer last = null; Iterator<Integer> it; public ConceptIterator() { ids = new ArrayList<Integer>(id2concept.keySet()); it = ids.iterator(); } public boolean hasNext() { return it.hasNext(); } public Concept next() { last = it.next(); return getConcept(last); } public void remove() { it.remove(); removeConcept(last); } } @Override public void setRelation(Relation relation) { if (!existsRelation(relation)) { List<Relation> subjectrelations = id2subjectrelations.get(relation.subject); if (subjectrelations == null) { subjectrelations = new ArrayList<Relation>(); id2subjectrelations.put(relation.subject, subjectrelations); } subjectrelations.add(relation); List<Relation> objectrelations = id2objectrelations.get(relation.object); if (objectrelations == null) { objectrelations = new ArrayList<Relation>(); id2objectrelations.put(relation.object, objectrelations); } objectrelations.add(relation); } } public void removeRelation(Relation relation){ List<Relation> subjectrelations = id2subjectrelations.get(relation.subject); subjectrelations.remove(relation); if (subjectrelations.size() == 0) id2subjectrelations.remove(relation.subject); List<Relation> objectrelations = id2objectrelations.get(relation.object); objectrelations.remove(relation); if (objectrelations.size() == 0) id2objectrelations.remove(relation.object); } public boolean existsRelation(Relation relation) { List<Relation> subjectrelations = id2subjectrelations.get(relation.subject); List<Relation> objectrelations = id2objectrelations.get(relation.object); if (subjectrelations != null && objectrelations != null) { if (subjectrelations.size() < objectrelations.size()) { for (Relation testRelation: subjectrelations) { if (testRelation.equals(relation)) { return true; } } } else { for (Relation testRelation: objectrelations) { if (testRelation.equals(relation)) { return true; } } } } return false; } @Override public List<Relation> getRelationsForConceptAsObject(int id) { List<Relation> relations = id2objectrelations.get(id); if (relations == null) return new ArrayList<Relation>(); return relations; } @Override public List<Relation> getRelationsForConceptAsObject(int id, int relationtype) { List<Relation> relations = id2objectrelations.get(id); if (relations == null) return new ArrayList<Relation>(); List<Relation> result = new ArrayList<Relation>(); for (Relation relation: relations) if (relation.predicate == relationtype) result.add(relation); return result; } @Override public List<Relation> getRelationsForConceptAsSubject(int id) { List<Relation> relations = id2subjectrelations.get(id); if (relations == null) return new ArrayList<Relation>(); return relations; } @Override public List<Relation> getRelationsForConceptAsSubject(int id, int relationtype) { List<Relation> relations = id2subjectrelations.get(id); if (relations == null) return new ArrayList<Relation>(); List<Relation> result = new ArrayList<Relation>(); for (Relation relation: relations) if (relation.predicate == relationtype) result.add(relation); return result; } @Override public List<Relation> getRelations() { List<Relation> result = new ArrayList<Relation>(); for (List<Relation> relations: id2subjectrelations.values()) result.addAll(relations); return result; } @Override public void removeConcept(int id) { id2concept.remove(id); List<Relation> relations = id2subjectrelations.remove(id); if (relations != null) { for (Relation relation: relations) { List<Relation> checkrelations = id2objectrelations.get(relation.object); Iterator<Relation> relationIterator = checkrelations.iterator(); while (relationIterator.hasNext()) { Relation checkRelation = relationIterator.next(); if (checkRelation.subject == id) { relationIterator.remove(); } } } } List<Relation> objectRelations = id2objectrelations.remove(id); if (objectRelations != null) { for (Relation relation: objectRelations) { List<Relation> checkrelations = id2subjectrelations.get(relation.subject); Iterator<Relation> relationIterator = checkrelations.iterator(); while (relationIterator.hasNext()) { Relation checkRelation = relationIterator.next(); if (checkRelation.object == id) { relationIterator.remove(); } } } } id2DatabaseID.remove(id); } @Override public List<DatabaseID> getDatabaseIDsForConcept(int id) { List<DatabaseID> dbids = id2DatabaseID.get(id); if (dbids == null) { dbids = new ArrayList<DatabaseID>(); } return dbids; } @Override public void setDatabaseIDForConcept(int id, DatabaseID databaseID) { List<DatabaseID> databaseIDs = id2DatabaseID.get(id); if (databaseIDs == null) { databaseIDs = new ArrayList<DatabaseID>(); id2DatabaseID.put(id, databaseIDs); } boolean present = false; for (DatabaseID databaseID2: databaseIDs) { if (databaseID2.equals(databaseID)) { present = true; } } if (!present) { databaseIDs.add(databaseID); // add to index if exists: if (databaseID2id != null) { Set<Integer> conceptIDs = databaseID2id.get(databaseID); if (conceptIDs == null) { conceptIDs = new HashSet<Integer>(); databaseID2id.put(databaseID, conceptIDs); } conceptIDs.add(id); } } } @Override public Set<Integer> getConceptIDs(DatabaseID databaseID) { // first check if index exists: if (databaseID2id != null) { Set<Integer> result = databaseID2id.get(databaseID); if (result == null) return new HashSet<Integer>(); else return result; } else { // Run through the whole thesaurus Set<Integer> result = new HashSet<Integer>(); for (Map.Entry<Integer, List<DatabaseID>> entry: id2DatabaseID.entrySet()) { for (DatabaseID otherDatabaseID: entry.getValue()) if (otherDatabaseID.equals(databaseID)) result.add(entry.getKey()); } return result; } } @Override public Set<ConceptRelation> getParentRelationsForConceptSet(IntList ids) { Set<ConceptRelation> set = new HashSet<ConceptRelation>(); Set<Integer> seenSet = new HashSet<Integer>(); for (int id: ids) { getParentRelationsForConcept(id, set, seenSet); } return set; } private void getParentRelationsForConcept(int conceptid, Set<ConceptRelation> set, Set<Integer> seenSet) { List<Relation> parentlist = getRelationsForConceptAsObject(conceptid, DefaultTypes.isParentOf); seenSet.add(conceptid); for (Relation relation: parentlist) { if (set.add(new ConceptRelation(relation.subject, conceptid))) { // Avoid circulair references : If a parent is already seen, do not // traverse up anymore. if (!seenSet.contains(relation.subject)) getParentRelationsForConcept(relation.subject, set, seenSet); } } } public Iterator<Concept> iterator() { return getConceptIterator(); } }