package eu.fbk.knowledgestore.server.http.jaxrs; import java.io.IOException; import java.util.List; import java.util.Set; import javax.annotation.Nullable; import com.google.common.collect.HashMultiset; import com.google.common.collect.Lists; import com.google.common.collect.Multiset; import com.google.common.collect.Ordering; import com.google.common.collect.Sets; import org.openrdf.model.URI; import org.openrdf.model.Value; import eu.fbk.knowledgestore.Session; import eu.fbk.knowledgestore.data.Data; import eu.fbk.knowledgestore.data.Record; import eu.fbk.knowledgestore.data.Stream; import eu.fbk.knowledgestore.vocabulary.KS; public class TableQuery { private static final int MAX_MENTIONS = 10000; private final Session session; public TableQuery(final Session session) { this.session = session; } public void renderPropertyOccurrencesTable(final Appendable out, final URI entityURI) throws Throwable { // Compute the # of occurrences of each property URI in entity mentions final Multiset<URI> propertyURIs = HashMultiset.create(); for (final Record mention : getEntityMentions(entityURI, MAX_MENTIONS)) { propertyURIs.addAll(mention.getProperties()); } // Render the table renderMultisetTable(out, propertyURIs); } public void renderValueOccurrencesTable(final Appendable out, final URI entityURI, final URI propertyURI) throws Throwable { // Compute the # of occurrences of all the values of the given property in entity mentions final Multiset<Value> propertyValues = HashMultiset.create(); for (final Record mention : getEntityMentions(entityURI, MAX_MENTIONS)) { propertyValues.addAll(mention.get(propertyURI, Value.class)); } // Render the table renderMultisetTable(out, propertyValues); } public void renderMentionTable(final URI entity, final URI property, final String value, final Appendable out) throws Throwable { // Retrieve all the mentions satisfying the property[=value] optional filter final List<Record> mentions = Lists.newArrayList(); for (final Record mention : getEntityMentions(entity, MAX_MENTIONS)) { if (property == null || !mention.isNull(property) && (value == null || mention.get(property).contains(value))) { mentions.add(mention); } } // Render the mention table, including column toggling functionality renderRecordsTable(out, mentions, null, true); } public Stream<Record> getEntityMentions(final URI entityURI, final int maxResults) throws Throwable { // First retrieve all the URIs of the mentions denoting the entity, via SPARQL query final List<URI> mentionURIs = this.session .sparql("SELECT ?mention WHERE { $$ gaf:denotedBy ?mention}", entityURI) .execTuples().transform(URI.class, true, "mention").toList(); // Then return a stream that returns the mention records as they are fetched from the KS return this.session.retrieve(KS.MENTION).limit((long) maxResults).ids(mentionURIs).exec(); } public static <T extends Appendable> T renderMultisetTable(final T out, final Multiset<?> multiset) throws IOException { out.append("<table class=\"display datatable\">\n"); out.append("<thead>\n<tr><th>Values</th><th>Occurrences</th></tr>\n</thead>\n"); out.append("<tbody>\n"); for (final Object element : multiset.elementSet()) { final int occurrences = multiset.count(element); out.append("<tr><td>").append(RenderUtils.render(element)).append("</td><td>") .append(Integer.toString(occurrences)).append("</td></tr>\n"); } out.append("</tbody>\n</table>\n"); return out; } public static <T extends Appendable> T renderRecordsTable(final T out, final Iterable<Record> records, @Nullable List<URI> propertyURIs, final boolean toggleColumns) throws IOException { // Extract the properties to show if not explicitly supplied if (propertyURIs == null) { final Set<URI> uriSet = Sets.newHashSet(); for (final Record record : records) { uriSet.addAll(record.getProperties()); } propertyURIs = Ordering.from(Data.getTotalComparator()).sortedCopy(propertyURIs); } // Emit the panel for toggling displayed columns out.append("<div>Toggle column: | <a class=\"toggle-vis\" data-column=\"0\">mentionURI</a> |"); for (int i = 0; i < propertyURIs.size(); ++i) { final String qname = RenderUtils.shortenURI(propertyURIs.get(i)); out.append(" <a class=\"toggle-vis\" data-column=\"").append(Integer.toString(i + 1)) .append("\">").append(qname).append("</a> | "); } out.append("</div>"); // Emit the table out.append("<table class=\"display datatable\">\n<thead>\n<tr><th>URI</th>"); for (final URI propertyURI : propertyURIs) { out.append("<th>").append(RenderUtils.shortenURI(propertyURI)).append("</th>"); } out.append("</tr>\n</thead>\n<tbody>\n"); for (final Record record : records) { out.append("<tr><td>").append(RenderUtils.render(record.getID())).append("</td>"); for (final URI propertyURI : propertyURIs) { out.append("<td>").append(RenderUtils.render(record.get(propertyURI))) .append("</td>"); } out.append("</tr>\n"); } out.append("</tbody>\n</table>\n"); return out; } }