package org.openbel.framework.test; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.openbel.framework.api.AnnotationFilterCriteria; import org.openbel.framework.api.BelDocumentFilterCriteria; import org.openbel.framework.api.CitationFilterCriteria; import org.openbel.framework.api.FilterCriteria; import org.openbel.framework.api.RelationshipTypeFilterCriteria; import org.openbel.framework.api.internal.KAMStoreDao; import org.openbel.framework.api.internal.KAMCatalogDao.KamFilter; import org.openbel.framework.api.internal.KAMStoreDaoImpl.Annotation; import org.openbel.framework.api.internal.KAMStoreDaoImpl.BelDocumentInfo; import org.openbel.framework.api.internal.KAMStoreDaoImpl.BelStatement; import org.openbel.framework.api.internal.KAMStoreDaoImpl.Citation; import org.openbel.framework.api.internal.KAMStoreDaoImpl.KamProtoEdge; import org.openbel.framework.api.internal.KAMStoreDaoImpl.KamProtoNode; /** * KAM Filtering Helper * */ public class KAMFilterHelper { private KAMStoreDao kamStoreDao; // for supporting evidence lookup public KAMFilterHelper(KAMStoreDao kamStoreDao) { this.kamStoreDao = kamStoreDao; } /** * @param kamProtoEdgeMap * @param kamFilter */ public void filter(Map<Integer, KamProtoNode> kamProtoNodeMap, Map<Integer, KamProtoEdge> kamProtoEdgeMap, KamFilter kamFilter) throws SQLException { List<FilterCriteria> criteria = kamFilter.getFilterCriteria(); for (FilterCriteria criterion : criteria) { //process each criteria, number of edges to filter may go down in each loop Set<Integer> matched = null; if (criterion instanceof RelationshipTypeFilterCriteria) { matched = processRelationshipTypeFilterCriteria(kamProtoEdgeMap, (RelationshipTypeFilterCriteria) criterion); } else if (criterion instanceof BelDocumentFilterCriteria) { matched = processBelDocumentFilterCriteria(kamProtoEdgeMap, (BelDocumentFilterCriteria) criterion); } else if (criterion instanceof AnnotationFilterCriteria) { matched = processAnnotationFilterCriteria(kamProtoEdgeMap, (AnnotationFilterCriteria) criterion); } else if (criterion instanceof CitationFilterCriteria) { matched = processCitationFilterCriteria(kamProtoEdgeMap, (CitationFilterCriteria) criterion); } if( matched != null ) { if (criterion.isInclude()) { kamProtoEdgeMap.keySet().retainAll(matched); } else { // must be exclude kamProtoEdgeMap.keySet().removeAll(matched); } } } //post processing to remove orphaned nodes removeOrphanNodes(kamProtoNodeMap, kamProtoEdgeMap); } /** * remove all nodes from the proto node map that is not in at least one edge in the proto edge map * @param kamProtoNodeMap * @param kamProtoEdgeMap */ protected void removeOrphanNodes(Map<Integer, KamProtoNode> kamProtoNodeMap, Map<Integer, KamProtoEdge> kamProtoEdgeMap) { Set<Integer> nodesInUse = new HashSet<Integer>(); for (Entry<Integer, KamProtoEdge> entry : kamProtoEdgeMap.entrySet()) { KamProtoEdge edge = entry.getValue(); nodesInUse.add(edge.getSourceNode().getId()); nodesInUse.add(edge.getTargetNode().getId()); } kamProtoNodeMap.keySet().retainAll(nodesInUse); } protected Set<Integer> processCitationFilterCriteria(Map<Integer, KamProtoEdge> kamProtoEdgeMap, CitationFilterCriteria c) throws SQLException { Set<Integer> matched = new HashSet<Integer>(); Set<Citation> citations = c.getValues(); Set<String> referenceIds = new HashSet<String>(); for (Citation citation : citations) { referenceIds.add(citation.getId()); } // statement level filter: edge is removed if no statement supports it for (Entry<Integer, KamProtoEdge> entry : kamProtoEdgeMap.entrySet()) { List<BelStatement> statements = kamStoreDao.getSupportingEvidence(entry.getValue().getId()); boolean hasSupport = false; if( c.isInclude() ) { for (BelStatement statement : statements) { if (referenceIds.contains(statement.getCitation().getId())) { hasSupport = true; break; } } if( hasSupport ) { matched.add(entry.getKey()); } } else { for (BelStatement statement : statements) { //try to find at least one statement not in the exclude set if ( ! referenceIds.contains(statement.getCitation().getId())) { hasSupport = true; break; } } if( !hasSupport ) { matched.add(entry.getKey()); } } } return matched; } /** * If filter type is include, return list of edges to be included. * If filter type is exclude, return list of edges to be excluded. * * @param kamProtoEdgeMap * @param c * @return * @throws SQLException */ protected Set<Integer> processAnnotationFilterCriteria(Map<Integer, KamProtoEdge> kamProtoEdgeMap, AnnotationFilterCriteria c) throws SQLException { Set<Integer> matched = new HashSet<Integer>(); // annotation level filter: supported statement is remove if no other annotation of the same type exists for (Entry<Integer, KamProtoEdge> entry : kamProtoEdgeMap.entrySet()) { List<BelStatement> statements = kamStoreDao.getSupportingEvidence(entry.getValue().getId()); boolean hasStatementSupport = false; for (BelStatement statement : statements) { if( isStatementSupported(statement.getAnnotationList(), c) ) { hasStatementSupport = true; break; } } if( c.isInclude() ) { if( hasStatementSupport ) { matched.add(entry.getKey()); } } else { if( !hasStatementSupport ) { //added the edge to list of edges to be removed matched.add(entry.getKey()); } } } return matched; } /** * Statement is considered supported according to the following: * if filter type is include: if it has at least one annotation matching the specified values * if filter type is exclude: if it has at least one annotation not match the specified values, or * if it has no annotations of the specified annotation type * @param statementAnnotations * @param c * @return */ private boolean isStatementSupported(List<Annotation> statementAnnotations, AnnotationFilterCriteria c) { boolean isStatementSupported = false; List<Annotation> matchAnnotationsSubset = new ArrayList<Annotation>(); for(Annotation annotation : statementAnnotations) { //identify annotations relevant to our filtering criterion if (c.getAnnotationType().getId().equals(annotation.getAnnotationType().getId())) { matchAnnotationsSubset.add(annotation); } } if( matchAnnotationsSubset.size() > 0 ) { if( c.isInclude() ) { for(Annotation annotation : matchAnnotationsSubset) { if (c.getValues().contains(annotation.getValue())) { //at least one annotation matched the specified values, statement is supported isStatementSupported = true; break; } } } else { for(Annotation annotation : matchAnnotationsSubset) { if (!c.getValues().contains(annotation.getValue())) { //at least one annotation doesn't match the specified values to exclude, statement is supported isStatementSupported = true; break; } } } } else { if( c.isInclude() ) { isStatementSupported = false; //include filter, no match annotation type on statement } else { isStatementSupported = true; } } return isStatementSupported; } /** * @param kamProtoEdgeMap * @param c * @return * @throws SQLException */ protected Set<Integer> processBelDocumentFilterCriteria(Map<Integer, KamProtoEdge> kamProtoEdgeMap, BelDocumentFilterCriteria c) throws SQLException { Set<Integer> matched = new HashSet<Integer>(); Set<BelDocumentInfo> docInfos = c.getValues(); Set<Integer> docInfoIds = new HashSet<Integer>(); for (BelDocumentInfo info : docInfos) { docInfoIds.add(info.getId()); } // statement level filter: edge is removed if no statement supports it for (Entry<Integer, KamProtoEdge> entry : kamProtoEdgeMap.entrySet()) { List<BelStatement> statements = kamStoreDao.getSupportingEvidence(entry.getValue().getId()); boolean hasSupport = false; if( c.isInclude() ) { for (BelStatement statement : statements) { if (docInfoIds.contains(statement.getBelDocumentInfo().getId())) { hasSupport = true; break; } } if( hasSupport ) { matched.add(entry.getKey()); } } else { for (BelStatement statement : statements) { //try to find at least one statement not in the exclude set if ( ! docInfoIds.contains(statement.getBelDocumentInfo().getId())) { hasSupport = true; break; } } if( !hasSupport ) { matched.add(entry.getKey()); } } } return matched; } /** * @param kamProtoEdgeMap * @param c * @return */ protected Set<Integer> processRelationshipTypeFilterCriteria(Map<Integer, KamProtoEdge> kamProtoEdgeMap, RelationshipTypeFilterCriteria c) { Set<Integer> matched = new HashSet<Integer>(); // edge level filtering: filter based on type match for (Entry<Integer, KamProtoEdge> entry : kamProtoEdgeMap.entrySet()) { if (c.getValues().contains(entry.getValue().getRelationship())) { matched.add(entry.getKey()); } } return matched; } }