[VIVO-1071] Add simple short-lived cache to reduce the number of expensive queries in generating the co-authorship / investigator graphs.

This commit is contained in:
grahamtriggs 2015-10-02 14:44:51 +01:00
parent d6bfa6dd6c
commit 5b80c748ae
2 changed files with 189 additions and 46 deletions

View file

@ -4,11 +4,13 @@ package edu.cornell.mannlib.vitro.webapp.visualization.coauthorship;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -401,12 +403,12 @@ public class CoAuthorshipQueryRunner implements QueryRunner<CollaborationData> {
+ " core:relatedBy ?authorshipNode . \n" + " core:relatedBy ?authorshipNode . \n"
+ "?authorshipNode rdf:type core:Authorship ;" + "?authorshipNode rdf:type core:Authorship ;"
+ " core:relates ?document . \n" + " core:relates ?document . \n"
+ "?document rdf:type bibo:Document . \n" + "?document rdf:type bibo:Document ; \n"
+ "?document core:relatedBy ?coAuthorshipNode . \n" + "core:relatedBy ?coAuthorshipNode . \n"
+ "?coAuthorshipNode rdf:type core:Authorship . \n" + "?coAuthorshipNode rdf:type core:Authorship ; \n"
+ "?coAuthorshipNode core:relates ?coAuthorPerson . \n" + "core:relates ?coAuthorPerson . \n"
+ "?coAuthorPerson rdf:type foaf:Person . \n" + "?coAuthorPerson rdf:type foaf:Person ; \n"
+ "?coAuthorPerson rdfs:label ?coAuthorPersonLabel . \n" + "rdfs:label ?coAuthorPersonLabel . \n"
+ "OPTIONAL { ?document core:dateTimeValue ?dateTimeValue . \n" + "OPTIONAL { ?document core:dateTimeValue ?dateTimeValue . \n"
+ " ?dateTimeValue core:dateTime ?publicationDate } .\n" + " ?dateTimeValue core:dateTime ?publicationDate } .\n"
+ "} \n" + "} \n"
@ -421,6 +423,33 @@ public class CoAuthorshipQueryRunner implements QueryRunner<CollaborationData> {
public CollaborationData getQueryResult() public CollaborationData getQueryResult()
throws MalformedQueryParametersException { throws MalformedQueryParametersException {
CollaborationData data = getCachedData(this.egoURI);
if (data != null) {
return data;
}
return getQueryResultAndCache();
}
private CollaborationData getCachedData(String egoURI) {
CollaborationDataCacheEntry entry = collaborationDataCache.get(egoURI);
if (entry != null && !entry.hasExpired()) {
entry.accessTime = new Date().getTime();
expireCache();
return entry.data;
}
return null;
}
private synchronized CollaborationData getQueryResultAndCache()
throws MalformedQueryParametersException {
CollaborationData data = getCachedData(this.egoURI);
if (data != null) {
return data;
}
if (StringUtils.isNotBlank(this.egoURI)) { if (StringUtils.isNotBlank(this.egoURI)) {
/* /*
* To test for the validity of the URI submitted. * To test for the validity of the URI submitted.
@ -439,7 +468,51 @@ public class CoAuthorshipQueryRunner implements QueryRunner<CollaborationData> {
ResultSet resultSet = executeQuery(generateEgoCoAuthorshipSparqlQuery(this.egoURI), ResultSet resultSet = executeQuery(generateEgoCoAuthorshipSparqlQuery(this.egoURI),
this.dataset); this.dataset);
return createQueryResult(resultSet);
data = createQueryResult(resultSet);
CollaborationDataCacheEntry newEntry = new CollaborationDataCacheEntry();
newEntry.uri = this.egoURI;
newEntry.data = data;
newEntry.creationTime = newEntry.accessTime = new Date().getTime();
// Remove dead entries
expireCache();
// Cache the new entry
collaborationDataCache.put(this.egoURI, newEntry);
return data;
} }
private synchronized void expireCache() {
for (String key : collaborationDataCache.keySet()) {
CollaborationDataCacheEntry entry = collaborationDataCache.get(key);
if (entry != null && entry.hasExpired()) {
collaborationDataCache.remove(key);
}
}
}
private static final Map<String, CollaborationDataCacheEntry> collaborationDataCache = new ConcurrentHashMap<String, CollaborationDataCacheEntry>();
private static class CollaborationDataCacheEntry {
String uri;
CollaborationData data;
long creationTime;
long accessTime;
boolean hasExpired() {
long now = new Date().getTime();
// If it's older than five minutes, and it hasn't *just* been accessed, it's expired
if (creationTime < (now - 300000L) && accessTime < (now - 3000L)) {
return true;
}
// Otherwise, if it is more than 30 seconds old, expire it
return accessTime < (now - 30000L);
}
}
} }

View file

@ -4,11 +4,13 @@ package edu.cornell.mannlib.vitro.webapp.visualization.coprincipalinvestigator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -385,6 +387,33 @@ public class CoPIGrantCountQueryRunner implements QueryRunner<CollaborationData>
public CollaborationData getQueryResult() public CollaborationData getQueryResult()
throws MalformedQueryParametersException { throws MalformedQueryParametersException {
CollaborationData data = getCachedData(this.egoURI);
if (data != null) {
return data;
}
return getQueryResultAndCache();
}
private CollaborationData getCachedData(String egoURI) {
CollaborationDataCacheEntry entry = collaborationDataCache.get(egoURI);
if (entry != null && !entry.hasExpired()) {
entry.accessTime = new Date().getTime();
expireCache();
return entry.data;
}
return null;
}
private synchronized CollaborationData getQueryResultAndCache()
throws MalformedQueryParametersException {
CollaborationData data = getCachedData(this.egoURI);
if (data != null) {
return data;
}
if (StringUtils.isNotBlank(this.egoURI)) { if (StringUtils.isNotBlank(this.egoURI)) {
/* /*
* To test for the validity of the URI submitted. * To test for the validity of the URI submitted.
@ -402,14 +431,55 @@ public class CoPIGrantCountQueryRunner implements QueryRunner<CollaborationData>
} }
before = System.currentTimeMillis(); before = System.currentTimeMillis();
ResultSet resultSet = executeQuery(generateEgoCoPIquery(this.egoURI), this.dataSource); ResultSet resultSet = executeQuery(generateEgoCoPIquery(this.egoURI), this.dataSource);
after = System.currentTimeMillis(); after = System.currentTimeMillis();
log.debug("Time taken to execute the SELECT queries is in milliseconds: " + (after - before)); log.debug("Time taken to execute the SELECT queries is in milliseconds: " + (after - before));
return createQueryResult(resultSet); data = createQueryResult(resultSet);
CollaborationDataCacheEntry newEntry = new CollaborationDataCacheEntry();
newEntry.uri = this.egoURI;
newEntry.data = data;
newEntry.creationTime = newEntry.accessTime = new Date().getTime();
// Remove dead entries
expireCache();
// Cache the new entry
collaborationDataCache.put(this.egoURI, newEntry);
return data;
}
private synchronized void expireCache() {
for (String key : collaborationDataCache.keySet()) {
CollaborationDataCacheEntry entry = collaborationDataCache.get(key);
if (entry != null && entry.hasExpired()) {
collaborationDataCache.remove(key);
}
}
}
private static final Map<String, CollaborationDataCacheEntry> collaborationDataCache = new ConcurrentHashMap<String, CollaborationDataCacheEntry>();
private static class CollaborationDataCacheEntry {
String uri;
CollaborationData data;
long creationTime;
long accessTime;
boolean hasExpired() {
long now = new Date().getTime();
// If it's older than five minutes, and it hasn't *just* been accessed, it's expired
if (creationTime < (now - 300000L) && accessTime < (now - 3000L)) {
return true;
}
// Otherwise, if it is more than 30 seconds old, expire it
return accessTime < (now - 30000L);
}
} }