diff --git a/productMods/css/visualization/personlevel/page.css b/productMods/css/visualization/personlevel/page.css
index 5dac214d..ef72968f 100644
--- a/productMods/css/visualization/personlevel/page.css
+++ b/productMods/css/visualization/personlevel/page.css
@@ -258,4 +258,4 @@ table.sparkline_wrapper_table td, th {
}
#table_heading {
width: 80%;
-}
\ No newline at end of file
+}
diff --git a/productMods/css/visualization/visualization.css b/productMods/css/visualization/visualization.css
index 9fe9a3bb..14d71aae 100644
--- a/productMods/css/visualization/visualization.css
+++ b/productMods/css/visualization/visualization.css
@@ -23,9 +23,6 @@ span.incomplete-data-holder,
margin-top: 1.6em;
font-size: 1em;
}
-#incomplete-data-small {
- margin-top: 1.6em;
-}
.collaboratorship-icon {
float: left;
padding-right: 8px;
@@ -90,6 +87,21 @@ span.incomplete-data-holder,
.infoIcon {
padding-right:30px;
}
+.cache-info-small {
+ padding: 5px;
+ font-size: .8em;
+ color: #444;
+ border: dotted 1px #eee;
+ background-color: #ffb;
+ float: right;
+}
+.cache-info-vis {
+ padding: 5px;
+ color: #444;
+ border: dotted 1px #eee;
+ background-color: #ffb;
+ float: right;
+}
/* ---------------------------*/
/* Visualization Tools -------*/
diff --git a/productMods/templates/freemarker/visualization/entitycomparison/entityComparisonOnGrantsStandalone.ftl b/productMods/templates/freemarker/visualization/entitycomparison/entityComparisonOnGrantsStandalone.ftl
index 4a50cc05..2ef0a962 100644
--- a/productMods/templates/freemarker/visualization/entitycomparison/entityComparisonOnGrantsStandalone.ftl
+++ b/productMods/templates/freemarker/visualization/entitycomparison/entityComparisonOnGrantsStandalone.ftl
@@ -46,6 +46,9 @@ $(document).ready(function () {
<#assign currentParameterObject = grantParameter>
+<#if (builtFromCacheTime??) >
+
${i18n().using_cache_time} ${builtFromCacheTime?time} (${builtFromCacheTime?date?string("MMM dd yyyy")})
+#if>
<#include "entityComparisonBody.ftl">
diff --git a/productMods/templates/freemarker/visualization/entitycomparison/entityComparisonOnPublicationsStandalone.ftl b/productMods/templates/freemarker/visualization/entitycomparison/entityComparisonOnPublicationsStandalone.ftl
index da47d15b..eebd3b0d 100644
--- a/productMods/templates/freemarker/visualization/entitycomparison/entityComparisonOnPublicationsStandalone.ftl
+++ b/productMods/templates/freemarker/visualization/entitycomparison/entityComparisonOnPublicationsStandalone.ftl
@@ -46,6 +46,9 @@ $(document).ready(function () {
<#assign currentParameterObject = publicationParameter>
+<#if (builtFromCacheTime??) >
+
${i18n().using_cache_time} ${builtFromCacheTime?time} (${builtFromCacheTime?date?string("MMM dd yyyy")})
+#if>
<#include "entityComparisonBody.ftl">
diff --git a/productMods/templates/freemarker/visualization/mapOfScience/mapOfScienceStandalone.ftl b/productMods/templates/freemarker/visualization/mapOfScience/mapOfScienceStandalone.ftl
index 95bfdef9..d84170a0 100644
--- a/productMods/templates/freemarker/visualization/mapOfScience/mapOfScienceStandalone.ftl
+++ b/productMods/templates/freemarker/visualization/mapOfScience/mapOfScienceStandalone.ftl
@@ -7,6 +7,9 @@ corresponding changes in the included Templates. -->
<#include "mapOfScienceSetup.ftl">
+ <#if (builtFromCacheTime??) >
+
${i18n().using_cache_time} ${builtFromCacheTime?time} (${builtFromCacheTime?date?string("MMM dd yyyy")})
+ #if>
<#--
@@ -83,4 +86,6 @@ corresponding changes in the included Templates. -->
-${headScripts.add('')}
\ No newline at end of file
+${headScripts.add('')}
+
+${stylesheets.add('
')}
diff --git a/productMods/templates/freemarker/visualization/personlevel/coAuthorPersonLevel.ftl b/productMods/templates/freemarker/visualization/personlevel/coAuthorPersonLevel.ftl
index fd13aa86..5101fcfe 100644
--- a/productMods/templates/freemarker/visualization/personlevel/coAuthorPersonLevel.ftl
+++ b/productMods/templates/freemarker/visualization/personlevel/coAuthorPersonLevel.ftl
@@ -150,7 +150,10 @@ $(document).ready(function(){
-
+
+ <#if (builtFromCacheTime??) >
+ ${i18n().using_cache_time} ${builtFromCacheTime?time} (${builtFromCacheTime?date?string("MMM dd yyyy")})
+ #if>
<#if (numOfAuthors?? && numOfAuthors > 0) >
diff --git a/productMods/templates/freemarker/visualization/personlevel/coAuthorPersonLevelD3.ftl b/productMods/templates/freemarker/visualization/personlevel/coAuthorPersonLevelD3.ftl
index 705b3442..1caa441d 100644
--- a/productMods/templates/freemarker/visualization/personlevel/coAuthorPersonLevelD3.ftl
+++ b/productMods/templates/freemarker/visualization/personlevel/coAuthorPersonLevelD3.ftl
@@ -266,8 +266,11 @@ $(document).ready(function(){
+ <#if (builtFromCacheTime??) >
+ ${i18n().using_cache_time} ${builtFromCacheTime?time} (${builtFromCacheTime?date?string("MMM dd yyyy")})
+ #if>
-
+
<#if (numOfAuthors?? && numOfAuthors > 0) >
<#else>
diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/CoAuthorshipQueryRunner.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/CoAuthorshipQueryRunner.java
index 04f907db..3bc10c65 100644
--- a/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/CoAuthorshipQueryRunner.java
+++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/CoAuthorshipQueryRunner.java
@@ -2,7 +2,6 @@
package edu.cornell.mannlib.vitro.webapp.visualization.coauthorship;
-import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@@ -15,14 +14,12 @@ import java.util.concurrent.ConcurrentHashMap;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
-import com.hp.hpl.jena.query.ResultSet;
-import com.hp.hpl.jena.query.ResultSetFactory;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
-import net.sf.jga.algorithms.Unique;
+import edu.cornell.mannlib.vitro.webapp.visualization.utilities.VisualizationCaches;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.jena.iri.IRI;
@@ -34,7 +31,6 @@ import com.hp.hpl.jena.query.Syntax;
import com.hp.hpl.jena.rdf.model.RDFNode;
import edu.cornell.mannlib.vitro.webapp.visualization.collaborationutils.CoAuthorshipData;
-import edu.cornell.mannlib.vitro.webapp.visualization.collaborationutils.CollaborationData;
import edu.cornell.mannlib.vitro.webapp.visualization.collaborationutils.CollaboratorComparator;
import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryFieldLabels;
@@ -58,6 +54,8 @@ public class CoAuthorshipQueryRunner implements QueryRunner {
protected static final Syntax SYNTAX = Syntax.syntaxARQ;
+ private static boolean preferCaches = false;
+
private String egoURI;
private RDFService rdfService;
@@ -90,34 +88,46 @@ public class CoAuthorshipQueryRunner implements QueryRunner {
@Override
protected void processQuerySolution(QuerySolution qs) {
+ RDFNode egoAuthorURLNode = qs.get(QueryFieldLabels.AUTHOR_URL);
+ RDFNode authorLabelNode = qs.get(QueryFieldLabels.AUTHOR_LABEL);
+ RDFNode documentNode = qs.get(QueryFieldLabels.DOCUMENT_URL);
+ RDFNode coAuthorURLNode = qs.get(QueryFieldLabels.CO_AUTHOR_URL);
+ RDFNode coAuthorLabelNode = qs.get(QueryFieldLabels.CO_AUTHOR_LABEL);
+ RDFNode publicationDateNode = qs.get(QueryFieldLabels.DOCUMENT_PUBLICATION_DATE);
+
+ String authorURI = egoAuthorURLNode == null ? null : egoAuthorURLNode.asLiteral().getString();
+ String authorName = authorLabelNode == null ? null : authorLabelNode.asLiteral().getString();
+ String documentURI = documentNode == null ? null : documentNode.asLiteral().getString();
+ String documentDate = publicationDateNode == null ? null : publicationDateNode.asLiteral().getString();
+ String coAuthorURI = coAuthorURLNode == null ? null : coAuthorURLNode.asLiteral().getString();
+ String coAuthorName = coAuthorLabelNode == null ? null : coAuthorLabelNode.asLiteral().getString();
+
+ processEntry(authorURI, authorName, documentURI, documentDate, coAuthorURI, coAuthorName);
+ }
+
+ public void processEntry(String authorURI, String authorName, String documentURI, String documentDate, String coAuthorURI, String coAuthorName) {
/*
* We only want to create only ONE ego node.
* */
- RDFNode egoAuthorURLNode = qs.get(QueryFieldLabels.AUTHOR_URL);
- if (nodeURLToVO.containsKey(egoAuthorURLNode.toString())) {
-
- egoNode = nodeURLToVO.get(egoAuthorURLNode.toString());
-
+ if (nodeURLToVO.containsKey(authorURI)) {
+ egoNode = nodeURLToVO.get(authorURI);
} else {
-
- egoNode = new Collaborator(egoAuthorURLNode.toString(), nodeIDGenerator);
+ egoNode = new Collaborator(authorURI, nodeIDGenerator);
nodes.add(egoNode);
- nodeURLToVO.put(egoAuthorURLNode.toString(), egoNode);
+ nodeURLToVO.put(authorURI, egoNode);
- RDFNode authorLabelNode = qs.get(QueryFieldLabels.AUTHOR_LABEL);
- if (authorLabelNode != null) {
- egoNode.setCollaboratorName(authorLabelNode.toString());
+ if (authorName != null) {
+ egoNode.setCollaboratorName(authorName);
}
}
- RDFNode documentNode = qs.get(QueryFieldLabels.DOCUMENT_URL);
Activity biboDocument;
- if (biboDocumentURLToVO.containsKey(documentNode.toString())) {
- biboDocument = biboDocumentURLToVO.get(documentNode.toString());
+ if (biboDocumentURLToVO.containsKey(documentURI)) {
+ biboDocument = biboDocumentURLToVO.get(documentURI);
} else {
- biboDocument = createDocumentVO(qs, documentNode.toString());
- biboDocumentURLToVO.put(documentNode.toString(), biboDocument);
+ biboDocument = createDocumentVO(documentURI, documentDate);
+ biboDocumentURLToVO.put(documentURI, biboDocument);
}
egoNode.addActivity(biboDocument);
@@ -127,27 +137,21 @@ public class CoAuthorshipQueryRunner implements QueryRunner {
* we do not want a co-author node or Collaboration if the publication has only one
* author and that happens to be the ego.
* */
- if (qs.get(QueryFieldLabels.AUTHOR_URL).toString().equalsIgnoreCase(
- qs.get(QueryFieldLabels.CO_AUTHOR_URL).toString())) {
+ if (authorURI.equalsIgnoreCase(coAuthorURI)) {
return;
}
Collaborator coAuthorNode;
- RDFNode coAuthorURLNode = qs.get(QueryFieldLabels.CO_AUTHOR_URL);
- if (nodeURLToVO.containsKey(coAuthorURLNode.toString())) {
-
- coAuthorNode = nodeURLToVO.get(coAuthorURLNode.toString());
-
+ if (nodeURLToVO.containsKey(coAuthorURI)) {
+ coAuthorNode = nodeURLToVO.get(coAuthorURI);
} else {
-
- coAuthorNode = new Collaborator(coAuthorURLNode.toString(), nodeIDGenerator);
+ coAuthorNode = new Collaborator(coAuthorURI, nodeIDGenerator);
nodes.add(coAuthorNode);
- nodeURLToVO.put(coAuthorURLNode.toString(), coAuthorNode);
+ nodeURLToVO.put(coAuthorURI, coAuthorNode);
- RDFNode coAuthorLabelNode = qs.get(QueryFieldLabels.CO_AUTHOR_LABEL);
- if (coAuthorLabelNode != null) {
- coAuthorNode.setCollaboratorName(coAuthorLabelNode.toString());
+ if (coAuthorName != null) {
+ coAuthorNode.setCollaboratorName(coAuthorName);
}
}
@@ -225,13 +229,12 @@ public class CoAuthorshipQueryRunner implements QueryRunner {
return new CoAuthorshipData(egoNode, nodes, edges, biboDocumentURLToVO);
}
- private Activity createDocumentVO(QuerySolution solution, String documentURL) {
+ private Activity createDocumentVO(String documentURL, String documentDate) {
Activity biboDocument = new Activity(documentURL);
- RDFNode publicationDateNode = solution.get(QueryFieldLabels.DOCUMENT_PUBLICATION_DATE);
- if (publicationDateNode != null) {
- biboDocument.setActivityDate(publicationDateNode.toString());
+ if (documentDate != null) {
+ biboDocument.setActivityDate(documentDate);
}
return biboDocument;
@@ -413,17 +416,17 @@ public class CoAuthorshipQueryRunner implements QueryRunner {
+ "WHERE\n"
+ "{\n"
+ " {\n"
- + " <" + queryURI + "> rdf:type foaf:Person ;"
- + " rdfs:label ?authorLabel ;"
- + " core:relatedBy ?authorshipNode . \n"
- + " ?authorshipNode rdf:type core:Authorship ;"
- + " core:relates ?document . \n"
- + " ?document rdf:type ; \n"
- + " core:relatedBy ?coAuthorshipNode . \n"
- + " ?coAuthorshipNode rdf:type core:Authorship ; \n"
- + " core:relates ?coAuthorPerson . \n"
- + " ?coAuthorPerson rdf:type foaf:Person ; \n"
- + " rdfs:label ?coAuthorPersonLabel . \n"
+ + " <" + queryURI + "> rdf:type foaf:Person ;"
+ + " rdfs:label ?authorLabel ;"
+ + " core:relatedBy ?authorshipNode . \n"
+ + " ?authorshipNode rdf:type core:Authorship ;"
+ + " core:relates ?document . \n"
+ + " ?document rdf:type ; \n"
+ + " core:relatedBy ?coAuthorshipNode . \n"
+ + " ?coAuthorshipNode rdf:type core:Authorship ; \n"
+ + " core:relates ?coAuthorPerson . \n"
+ + " ?coAuthorPerson rdf:type foaf:Person ; \n"
+ + " rdfs:label ?coAuthorPersonLabel . \n"
+ " }\n"
+ " UNION\n"
+ " {\n"
@@ -487,20 +490,60 @@ public class CoAuthorshipQueryRunner implements QueryRunner {
throw new MalformedQueryParametersException("URI parameter is either null or empty.");
}
- try {
- Model constructedModel = ModelFactory.createDefaultModel();
- rdfService.sparqlConstructQuery(generateEgoCoAuthorshipSparqlConstruct(this.egoURI), constructedModel);
- QueryResultConsumer consumer = new QueryResultConsumer();
- QueryExecution qe = QueryExecutionFactory.create(generateEgoCoAuthorshipSparqlQuery(this.egoURI), constructedModel);
- try {
- consumer.processResultSet(qe.execSelect());
- } finally {
- qe.close();
- }
- data = consumer.getCollaborationData();
- } catch (RDFServiceException e) {
- log.error("Unable to execute query", e);
- throw new RuntimeException(e);
+ Date cacheTime = null;
+ QueryResultConsumer consumer = new QueryResultConsumer();
+
+ // If we've had long running queries (preferCaches), and the caches are available, use the cache
+ if (preferCaches && VisualizationCaches.personToPublication.isCached()) {
+ cacheTime = VisualizationCaches.personToPublication.cachedWhen();
+
+ Map personLabelsMap = VisualizationCaches.personLabels.get(rdfService);
+ Map> personToPublicationMap = VisualizationCaches.personToPublication.get(rdfService).personToPublication;
+ Map> publicationToPersonMap = VisualizationCaches.personToPublication.get(rdfService).publicationToPerson;
+ Map publicationToYearMap = VisualizationCaches.publicationToYear.get(rdfService);
+
+ String authorURI = this.egoURI;
+ String authorName = personLabelsMap.get(authorURI);
+ for (String documentURI : personToPublicationMap.get(authorURI)) {
+ String documentDate = publicationToYearMap.get(documentURI);
+ for (String coAuthorURI : publicationToPersonMap.get(documentURI)) {
+ String coAuthorName = personLabelsMap.get(coAuthorURI);
+ consumer.processEntry(authorURI, authorName, documentURI, documentDate, coAuthorURI, coAuthorName);
+ }
+ }
+ consumer.endProcessing();
+ } else {
+ // Not use the caches, so query the triple store - recording the time it took
+ long queryStart = System.currentTimeMillis();
+ try {
+ Model constructedModel = ModelFactory.createDefaultModel();
+ rdfService.sparqlConstructQuery(generateEgoCoAuthorshipSparqlConstruct(this.egoURI), constructedModel);
+ QueryExecution qe = QueryExecutionFactory.create(generateEgoCoAuthorshipSparqlQuery(this.egoURI), constructedModel);
+ try {
+ consumer.processResultSet(qe.execSelect());
+ } finally {
+ qe.close();
+ }
+ } catch (RDFServiceException e) {
+ log.error("Unable to execute query", e);
+ throw new RuntimeException(e);
+ } finally {
+ // If the query took more than 5 seconds, start using the caches
+ if (System.currentTimeMillis() - queryStart > 5000) {
+ // If the caches haven't already been built, request a rebuild
+ if (!preferCaches && !VisualizationCaches.personToPublication.isCached()) {
+ VisualizationCaches.rebuildAll();
+ }
+
+ // Attempt to use caches next time
+ preferCaches = true;
+ }
+ }
+ }
+
+ data = consumer.getCollaborationData();
+ if (cacheTime != null) {
+ data.setBuiltFromCacheTime(cacheTime);
}
CollaborationDataCacheEntry newEntry = new CollaborationDataCacheEntry();
diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/collaborationutils/CollaborationData.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/collaborationutils/CollaborationData.java
index a28f8073..b5fdec18 100644
--- a/src/edu/cornell/mannlib/vitro/webapp/visualization/collaborationutils/CollaborationData.java
+++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/collaborationutils/CollaborationData.java
@@ -2,6 +2,7 @@
package edu.cornell.mannlib.vitro.webapp.visualization.collaborationutils;
+import java.util.Date;
import java.util.Map;
import java.util.Set;
@@ -15,6 +16,8 @@ public abstract class CollaborationData {
private Collaborator egoCollaborator;
private Set