package at.ac.univie.mminf.qskos4j.issues.clusters; import at.ac.univie.mminf.qskos4j.issues.Issue; import at.ac.univie.mminf.qskos4j.issues.concepts.InvolvedConcepts; import at.ac.univie.mminf.qskos4j.progress.MonitoredIterator; import at.ac.univie.mminf.qskos4j.util.graph.NamedEdge; import at.ac.univie.mminf.qskos4j.util.vocab.SparqlPrefix; import org.jgrapht.DirectedGraph; import org.jgrapht.alg.ConnectivityInspector; import org.jgrapht.graph.DirectedMultigraph; import org.openrdf.OpenRDFException; import org.openrdf.model.Resource; import org.openrdf.model.URI; import org.openrdf.model.Value; import org.openrdf.model.impl.URIImpl; import org.openrdf.query.BindingSet; import org.openrdf.query.QueryLanguage; import org.openrdf.query.TupleQuery; import org.openrdf.query.TupleQueryResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; /** * Created by christian * Date: 26.01.13 * Time: 15:43 * * Finds all <a href="https://github.com/cmader/qSKOS/wiki/Quality-Issues#wiki-Disconnected_Concept_Clusters"> * Disconnected Concept Clusters</a>. */ public class DisconnectedConceptClusters extends Issue<ClustersResult> { private final Logger logger = LoggerFactory.getLogger(DisconnectedConceptClusters.class); private DirectedGraph<Resource, NamedEdge> graph; private InvolvedConcepts involvedConcepts; public DisconnectedConceptClusters(InvolvedConcepts involvedConcepts) { super(involvedConcepts, "dcc", "Disconnected Concept Clusters", "Finds sets of concepts that are isolated from the rest of the vocabulary", IssueType.ANALYTICAL, new URIImpl("https://github.com/cmader/qSKOS/wiki/Quality-Issues#disconnected-concept-clusters") ); this.involvedConcepts = involvedConcepts; } @Override protected ClustersResult invoke() throws OpenRDFException { createGraph(); Collection<Collection<Resource>> connectedSets = new ArrayList<>(); connectedSets.addAll(new ConnectivityInspector<>(graph).connectedSets()); return new ClustersResult(connectedSets, graph); } private void createGraph() throws OpenRDFException { graph = new DirectedMultigraph<>(NamedEdge.class); Iterator<Resource> conceptIt = new MonitoredIterator<>(involvedConcepts.getResult().getData(), progressMonitor); while (conceptIt.hasNext()) { Resource concept = conceptIt.next(); Collection<Relation> relations = findRelations(concept); for (Relation relation : relations) { addNodesToGraph( relation.sourceConcept, relation.targetConcept, relation.property); } } } private Collection<Relation> findRelations(Resource concept) { Collection<Relation> allRelations = new ArrayList<>(); try { TupleQuery query = repCon.prepareTupleQuery(QueryLanguage.SPARQL, createConnectionsQuery(concept)); TupleQueryResult result = query.evaluate(); while (result.hasNext()) { BindingSet bindingSet = result.next(); Resource otherConcept = (Resource) bindingSet.getValue("otherConcept"); URI semanticRelation = (URI) bindingSet.getValue("semanticRelation"); if (otherConcept != null && semanticRelation != null) { allRelations.add(new Relation(concept, otherConcept, semanticRelation)); } } } catch (OpenRDFException e) { logger.error("Error finding relations of concept '" +concept+ "'"); } return allRelations; } private String createConnectionsQuery(Value concept) { return SparqlPrefix.SKOS +" "+ SparqlPrefix.RDFS+ "SELECT DISTINCT ?otherConcept ?semanticRelation WHERE " + "{" + "<" +concept.stringValue()+ "> ?semanticRelation ?otherConcept . " + "?semanticRelation rdfs:subPropertyOf skos:semanticRelation" + "}"; } private void addNodesToGraph( Resource skosResource, Resource otherResource, Resource skosRelation) { graph.addVertex(skosResource); if (otherResource != null) { graph.addVertex(otherResource); graph.addEdge(skosResource, otherResource, new NamedEdge(extractFragmentString(skosRelation))); } } private String extractFragmentString(Value skosRelation) { int hashIndex = skosRelation.stringValue().indexOf("#"); if (hashIndex != -1) { return skosRelation.stringValue().substring(hashIndex + 1); } return skosRelation.stringValue(); } private class Relation { private Resource sourceConcept, targetConcept, property; private Relation(Resource sourceConcept, Resource targetConcept, Resource property) { this.sourceConcept = sourceConcept; this.targetConcept = targetConcept; this.property = property; } @Override public String toString() { return sourceConcept.stringValue() +" -- "+ property +" --> "+ targetConcept; } } }