Merge pull request #334 from helix84/DS-1409-ItemCountDAOSolr

DS-1409 add ItemCountDAOSolr, make it default
This commit is contained in:
Andrea Bollini
2013-10-20 10:43:51 -07:00
9 changed files with 308 additions and 86 deletions

View File

@@ -15,12 +15,13 @@ import org.dspace.core.ConfigurationManager;
* item count information * item count information
* *
* @author Richard Jones * @author Richard Jones
* @author Ivan Masár
* *
*/ */
public class ItemCountDAOFactory public class ItemCountDAOFactory
{ {
/** /**
* Get an instance of ItemCountDAO which supports the correct database * Get an instance of ItemCountDAO which supports the correct storage backend
* for the specific DSpace instance. * for the specific DSpace instance.
* *
* @param context * @param context
@@ -29,19 +30,28 @@ public class ItemCountDAOFactory
public static ItemCountDAO getInstance(Context context) public static ItemCountDAO getInstance(Context context)
throws ItemCountException throws ItemCountException
{ {
String db = ConfigurationManager.getProperty("db.name");
ItemCountDAO dao; /** Log4j logger */
if ("postgres".equals(db)) ItemCountDAO dao = null;
String className = ConfigurationManager.getProperty("ItemCountDAO.class");
// SOLR implementation is the default since DSpace 4.0
if (className == null)
{ {
dao = new ItemCountDAOPostgres(); dao = new ItemCountDAOSolr();
}
else if ("oracle".equals(db))
{
dao = new ItemCountDAOOracle();
} }
else else
{ {
throw new ItemCountException("Database type: " + db + " is not currently supported"); try
{
dao = (ItemCountDAO) Class
.forName(className.trim()).newInstance();
}
catch (Exception e)
{
throw new ItemCountException("The configuration for ItemCountDAO is invalid: " + className, e);
}
} }
dao.setContext(context); dao.setContext(context);

View File

@@ -0,0 +1,189 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.browse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.core.Context;
import org.dspace.discovery.DiscoverFacetField;
import org.dspace.discovery.DiscoverQuery;
import org.dspace.discovery.DiscoverResult;
import org.dspace.discovery.DiscoverResult.FacetResult;
import org.dspace.discovery.SearchService;
import org.dspace.discovery.SearchServiceException;
import org.dspace.discovery.configuration.DiscoveryConfigurationParameters;
import org.dspace.utils.DSpace;
/**
* Discovery (Solr) driver implementing ItemCountDAO interface to look up item
* count information in communities and collections. Caching operations are
* intentionally not implemented because Solr already is our cache.
*
* @author Ivan Masár, Andrea Bollini
*
*/
public class ItemCountDAOSolr implements ItemCountDAO
{
/** Log4j logger */
private static Logger log = Logger.getLogger(ItemCountDAOSolr.class);
/** DSpace context */
private Context context;
/**
* Hold the communities item count obtained from SOLR after the first query. This only works
* well if the ItemCountDAO lifecycle is bound to the request lifecycle as
* it is now. If we switch to a Spring-based instantiation we should mark
* this bean as prototype
**/
private Map<String, Integer> communitiesCount = null;
/** Hold the collection item count obtained from SOLR after the first query **/
private Map<String, Integer> collectionsCount = null;
/** DSpace helper services access object */
DSpace dspace = new DSpace();
/** Solr search service */
SearchService searcher = dspace.getServiceManager().getServiceByName(SearchService.class.getName(), SearchService.class);
/**
* Throw an ItemCountException as caching is not supported by ItemCountDAOSolr.
*
* @param collection
* @param count
* @throws ItemCountException
*/
public void collectionCount(Collection collection, int count) throws ItemCountException
{
throw new ItemCountException("Caching is not supported by the ItemCountDAOSolr as it is not really needed, Solr is faster!");
}
/**
* Throw an ItemCountException as caching is not supported by ItemCountDAOSolr.
*
* @param community
* @param count
* @throws ItemCountException
*/
public void communityCount(Community community, int count) throws ItemCountException
{
throw new ItemCountException("Caching is not supported by the ItemCountDAOSolr as it is not really needed, Solr is faster!");
}
/**
* Set the dspace context to use
*
* @param context
* @throws ItemCountException
*/
public void setContext(Context context) throws ItemCountException
{
this.context = context;
}
/**
* Get the count of the items in the given container.
*
* @param dso
* @throws ItemCountException
*/
public int getCount(DSpaceObject dso) throws ItemCountException
{
loadCount();
DiscoverQuery query = new DiscoverQuery();
Integer val = null;
if (dso instanceof Collection)
{
val = collectionsCount.get(String.valueOf(((Collection) dso).getID()));
}
else if (dso instanceof Community)
{
val = communitiesCount.get(String.valueOf(((Community) dso).getID()));
}
else
{
throw new ItemCountException("We can only count items in Communities or Collections");
}
if (val != null)
{
return val.intValue();
}
else
{
return 0;
}
}
/**
* remove the cache for the given container (does nothing in the Solr backend)
*
* @param dso
* @throws ItemCountException
*/
public void remove(DSpaceObject dso) throws ItemCountException
{
}
/**
* make sure that the counts are actually fetched from Solr (if haven't been
* cached in a Map yet)
*
* @throws ItemCountException
*/
private void loadCount() throws ItemCountException
{
if (communitiesCount != null || collectionsCount != null)
{
return;
}
communitiesCount = new HashMap<String, Integer>();
collectionsCount = new HashMap<String, Integer>();
DiscoverQuery query = new DiscoverQuery();
query.setFacetMinCount(1);
query.addFacetField(new DiscoverFacetField("location.comm",
DiscoveryConfigurationParameters.TYPE_STANDARD, -1,
DiscoveryConfigurationParameters.SORT.COUNT));
query.addFacetField(new DiscoverFacetField("location.coll",
DiscoveryConfigurationParameters.TYPE_STANDARD, -1,
DiscoveryConfigurationParameters.SORT.COUNT));
query.addFilterQueries("search.resourcetype:2"); // count only items
query.addFilterQueries("NOT(discoverable:false)"); // only discoverable
query.setMaxResults(0);
DiscoverResult sResponse = null;
try
{
sResponse = searcher.search(context, query, false);
List<FacetResult> commCount = sResponse.getFacetResult("location.comm");
List<FacetResult> collCount = sResponse.getFacetResult("location.coll");
for (FacetResult c : commCount)
{
communitiesCount.put(c.getAsFilterQuery(),(int) c.getCount());
}
for (FacetResult c : collCount)
{
collectionsCount.put(c.getAsFilterQuery(),(int) c.getCount());
}
}
catch (SearchServiceException e)
{
log.error("caught exception: ", e);
throw new ItemCountException(e);
}
}
}

View File

@@ -110,7 +110,8 @@ public class ItemCounter
public int getCount(DSpaceObject dso) public int getCount(DSpaceObject dso)
throws ItemCountException throws ItemCountException
{ {
boolean useCache = ConfigurationManager.getBooleanProperty("webui.strengths.cache"); boolean useCache = ConfigurationManager.getBooleanProperty(
"webui.strengths.cache", true);
if (useCache) if (useCache)
{ {

View File

@@ -2178,6 +2178,10 @@ public class SolrServiceImpl implements SearchService, IndexingService {
} }
protected String transformAuthorityValue(Context context, String field, String value) throws SQLException { protected String transformAuthorityValue(Context context, String field, String value) throws SQLException {
if(field.equals("location.comm") || field.equals("location.coll"))
{
return value;
}
if (field.endsWith("_filter") || field.endsWith("_ac") if (field.endsWith("_filter") || field.endsWith("_ac")
|| field.endsWith("_acid")) || field.endsWith("_acid"))
{ {

View File

@@ -50,10 +50,9 @@
%> %>
<%! <%!
void showCommunity(Community c, JspWriter out, HttpServletRequest request, void showCommunity(Community c, JspWriter out, HttpServletRequest request, ItemCounter ic,
Map collectionMap, Map subcommunityMap) throws ItemCountException, IOException, SQLException Map collectionMap, Map subcommunityMap) throws ItemCountException, IOException, SQLException
{ {
ItemCounter ic = new ItemCounter(UIUtil.obtainContext(request));
out.println( "<li class=\"media well\">" ); out.println( "<li class=\"media well\">" );
Bitstream logo = c.getLogo(); Bitstream logo = c.getLogo();
if (logo != null) if (logo != null)
@@ -113,7 +112,7 @@
out.println("<ul class=\"media-list\">"); out.println("<ul class=\"media-list\">");
for (int k = 0; k < comms.length; k++) for (int k = 0; k < comms.length; k++)
{ {
showCommunity(comms[k], out, request, collectionMap, subcommunityMap); showCommunity(comms[k], out, request, ic, collectionMap, subcommunityMap);
} }
out.println("</ul>"); out.println("</ul>");
} }
@@ -156,7 +155,7 @@
<% <%
for (int i = 0; i < communities.length; i++) for (int i = 0; i < communities.length; i++)
{ {
showCommunity(communities[i], out, request, collectionMap, subcommunityMap); showCommunity(communities[i], out, request, ic, collectionMap, subcommunityMap);
} }
%> %>
</ul> </ul>

View File

@@ -139,8 +139,8 @@ public class CommunityBrowser extends AbstractDSpaceTransformer implements Cache
validity.add(node.getDSO()); validity.add(node.getDSO());
// If we are configured to use collection strengths (i.e. item counts) then include that number in the validity. // If we are configured to use collection strengths (i.e. item counts) then include that number in the validity.
boolean useCache = ConfigurationManager.getBooleanProperty("webui.strengths.cache"); boolean showCount = ConfigurationManager.getBooleanProperty("webui.strengths.show");
if (useCache) if (showCount)
{ {
try try
{ //try to determine Collection size (i.e. # of items) { //try to determine Collection size (i.e. # of items)

View File

@@ -123,9 +123,9 @@ public class CommunityViewer extends AbstractDSpaceTransformer implements Cachea
{ {
validity.add(subCommunity); validity.add(subCommunity);
// Include the item count in the validity, only if the value is cached. // Include the item count in the validity, only if the value is shown.
boolean useCache = ConfigurationManager.getBooleanProperty("webui.strengths.cache"); boolean showCount = ConfigurationManager.getBooleanProperty("webui.strengths.show");
if (useCache) if (showCount)
{ {
try { try {
int size = new ItemCounter(context).getCount(subCommunity); int size = new ItemCounter(context).getCount(subCommunity);
@@ -138,9 +138,9 @@ public class CommunityViewer extends AbstractDSpaceTransformer implements Cachea
{ {
validity.add(collection); validity.add(collection);
// Include the item count in the validity, only if the value is cached. // Include the item count in the validity, only if the value is shown.
boolean useCache = ConfigurationManager.getBooleanProperty("webui.strengths.cache"); boolean showCount = ConfigurationManager.getBooleanProperty("webui.strengths.show");
if (useCache) if (showCount)
{ {
try { try {
int size = new ItemCounter(context).getCount(collection); int size = new ItemCounter(context).getCount(collection);

View File

@@ -273,19 +273,18 @@ public class ContainerAdapter extends AbstractAdapter
createField("dc","rights","license",null,rights_license); createField("dc","rights","license",null,rights_license);
createField("dc","title",null,null,title); createField("dc","title",null,null,title);
boolean useCache = ConfigurationManager.getBooleanProperty("webui.strengths.cache"); boolean showCount = ConfigurationManager.getBooleanProperty("webui.strengths.show");
//To improve scalability, XMLUI only adds item counts if they are cached if (showCount)
if (useCache)
{ {
try try
{ //try to determine Collection size (i.e. # of items) { // try to determine Collection size (i.e. # of items)
int size = new ItemCounter(this.dspaceContext).getCount(collection); int size = new ItemCounter(this.dspaceContext).getCount(collection);
createField("dc","format","extent",null, String.valueOf(size)); createField("dc","format","extent",null, String.valueOf(size));
} }
catch(ItemCountException e) catch (ItemCountException e)
{ {
throw new IOException("Could not obtain Collection item-count", e); throw new IOException("Could not obtain Collection item count", e);
} }
} }
} }
@@ -307,19 +306,18 @@ public class ContainerAdapter extends AbstractAdapter
createField("dc","rights",null,null,rights); createField("dc","rights",null,null,rights);
createField("dc","title",null,null,title); createField("dc","title",null,null,title);
boolean useCache = ConfigurationManager.getBooleanProperty("webui.strengths.cache"); boolean showCount = ConfigurationManager.getBooleanProperty("webui.strengths.show");
//To improve scalability, XMLUI only adds item counts if they are cached if (showCount)
if (useCache)
{ {
try try
{ //try to determine Community size (i.e. # of items) { // try to determine Community size (i.e. # of items)
int size = new ItemCounter(this.dspaceContext).getCount(community); int size = new ItemCounter(this.dspaceContext).getCount(community);
createField("dc","format","extent",null, String.valueOf(size)); createField("dc","format","extent",null, String.valueOf(size));
} }
catch(ItemCountException e) catch (ItemCountException e)
{ {
throw new IOException("Could not obtain Collection item-count", e); throw new IOException("Could not obtain Collection item count", e);
} }
} }
} }

View File

@@ -928,34 +928,55 @@ webui.preview.brand.fontpoint = 12
#webui.preview.dc = rights #webui.preview.dc = rights
##### Settings for content count/strength information #### ##### Settings for item count (strength) information ####
# whether to display collection and community strengths # whether to display collection and community strengths
# (This configuration is not used by XMLUI. To show strengths in the # (Since DSpace 4.0, this config option is used by XMLUI, too.
# XMLUI, you just need to create a theme which displays them) # XMLUI only makes strengths available to themes if this is set to true!
# To show strengths in the XMLUI, you also need to create a theme which displays them)
webui.strengths.show = false webui.strengths.show = false
# if showing the strengths, should they be counted in real time or # if showing strengths, should they be counted in real time or
# fetched from cache? NOTE: To improve scaling/performance, # fetched from cache?
# the XMLUI only makes strengths available to themes if they are CACHED!
# #
# Counts fetched in real time will perform an actual count of the # Counts fetched in real time will perform an actual count of the
# database contents every time a page with this feature is requested, # database contents every time a page with this feature is requested,
# which will not scale. If the below setting is to use the cache, you # which will not scale. The default behaviour is to use a cache (see
# must run the following command periodically to update the count: # ItemCounter configuration)
# #
# [dspace]/bin/itemcounter # The default is to use a cache
# #
# The default is to count in real time # webui.strengths.cache = true
###### ItemCounter Configuration ######
# #
webui.strengths.cache = false # Define the DAO class to use. This must correspond to your choice of
# storage for the browse system (RDBMS: PostgreSQL or Oracle, Solr).
# By default, since DSpace 4.0, the Solr implementation is used.
#
# Only if you use a DBMS implementation and want to use the cache
# (recommended!), you must run the following command periodically
# to update the count:
#
# [dspace]/bin/itemcounter (NOT required if you use the Solr implementation)
#
#
# PostgreSQL:
# ItemCountDAO.class = org.dspace.browse.ItemCountDAOPostgres
#
# Oracle:
# ItemCountDAO.class = org.dspace.browse.ItemCountDAOOracle
#
# Solr:
# ItemCountDAO.class = org.dspace.browse.ItemCountDAOSolr
###### Browse Configuration ###### ###### Browse Configuration ######
# #
# Define the DAO class to use this must meet your storage choice for # Define the DAO class to use this must meet your storage choice for
# the browse system (RDBMS: PostgreSQL or Oracle, SOLR). # the browse system (RDBMS: PostgreSQL or Oracle, Solr).
# By default, since DSpace 4.0, the SOLR implementation is used # By default, since DSpace 4.0, the Solr implementation is used
# #
# PostgreSQL: # PostgreSQL:
# browseDAO.class = org.dspace.browse.BrowseDAOPostgres # browseDAO.class = org.dspace.browse.BrowseDAOPostgres
@@ -965,7 +986,7 @@ webui.strengths.cache = false
# browseDAO.class = org.dspace.browse.BrowseDAOOracle # browseDAO.class = org.dspace.browse.BrowseDAOOracle
# browseCreateDAO.class = org.dspace.browse.BrowseCreateDAOOracle # browseCreateDAO.class = org.dspace.browse.BrowseCreateDAOOracle
# #
# SOLR: # Solr:
# browseDAO.class = org.dspace.browse.SolrBrowseDAO # browseDAO.class = org.dspace.browse.SolrBrowseDAO
# browseCreateDAO.class = org.dspace.browse.SolrBrowseCreateDAO # browseCreateDAO.class = org.dspace.browse.SolrBrowseCreateDAO