Skip to content

Commit

Permalink
Merge pull request #2771 from Micheleboychuk/DS-4504_UpdatePerformanc…
Browse files Browse the repository at this point in the history
…eFindingCollections

DS-4504 Performance issues with finding Collections a user can submit to
  • Loading branch information
tdonohue committed Jun 19, 2020
2 parents 124117c + eef6868 commit 69df9b0
Show file tree
Hide file tree
Showing 8 changed files with 524 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Set;
import java.util.UUID;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.apache.solr.client.solrj.util.ClientUtils;
import org.dspace.app.util.AuthorizeUtil;
import org.dspace.authorize.AuthorizeConfiguration;
import org.dspace.authorize.AuthorizeException;
Expand All @@ -40,6 +42,13 @@
import org.dspace.core.I18nUtil;
import org.dspace.core.LogManager;
import org.dspace.core.service.LicenseService;
import org.dspace.discovery.DiscoverQuery;
import org.dspace.discovery.DiscoverResult;
import org.dspace.discovery.IndexableObject;
import org.dspace.discovery.SearchService;
import org.dspace.discovery.SearchServiceException;
import org.dspace.discovery.indexobject.IndexableCollection;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.eperson.service.GroupService;
import org.dspace.eperson.service.SubscribeService;
Expand Down Expand Up @@ -100,6 +109,9 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl<Collection> i
@Autowired(required = true)
protected CollectionRoleService collectionRoleService;

@Autowired(required = true)
protected SearchService searchService;

protected CollectionServiceImpl() {
super();
}
Expand Down Expand Up @@ -907,4 +919,77 @@ public Group createDefaultReadGroup(Context context, Collection collection, Stri
return role;
}

@Override
public List<Collection> findCollectionsWithSubmit(String q, Context context, Community community,
int offset, int limit) throws SQLException, SearchServiceException {

List<Collection> collections = new ArrayList<Collection>();
DiscoverQuery discoverQuery = new DiscoverQuery();
discoverQuery.setDSpaceObjectFilter(IndexableCollection.TYPE);
discoverQuery.setStart(offset);
discoverQuery.setMaxResults(limit);
DiscoverResult resp = retrieveCollectionsWithSubmit(context, discoverQuery,community, q);
for (IndexableObject solrCollections : resp.getIndexableObjects()) {
Collection c = ((IndexableCollection) solrCollections).getIndexedObject();
collections.add(c);
}
return collections;
}

@Override
public int countCollectionsWithSubmit(String q, Context context, Community community)
throws SQLException, SearchServiceException {

DiscoverQuery discoverQuery = new DiscoverQuery();
discoverQuery.setMaxResults(0);
discoverQuery.setDSpaceObjectFilter(IndexableCollection.TYPE);
DiscoverResult resp = retrieveCollectionsWithSubmit(context, discoverQuery,community,q);
return (int)resp.getTotalSearchResults();
}

/**
* Finds all Indexed Collections where the current user has submit rights. If the user is an Admin,
* this is all Indexed Collections. Otherwise, it includes those collections where
* an indexed "submit" policy lists either the eperson or one of the eperson's groups
*
* @param context DSpace context
* @param discoverQuery
* @param community parent community, could be null
* @param q limit the returned collection to those with metadata values matching the query
* terms. The terms are used to make also a prefix query on SOLR
* so it can be used to implement an autosuggest feature over the collection name
* @return discovery search result objects
* @throws SQLException if something goes wrong
* @throws SearchServiceException if search error
*/
private DiscoverResult retrieveCollectionsWithSubmit(Context context, DiscoverQuery discoverQuery,
Community community, String q) throws SQLException, SearchServiceException {

StringBuilder query = new StringBuilder();
EPerson currentUser = context.getCurrentUser();
if (!authorizeService.isAdmin(context)) {
String userId = "";
if (currentUser != null) {
userId = currentUser.getID().toString();
}
query.append("submit:(e").append(userId);
Set<Group> groups = groupService.allMemberGroupsSet(context, currentUser);
for (Group group : groups) {
query.append(" OR g").append(group.getID());
}
query.append(")");
discoverQuery.addFilterQueries(query.toString());
}
if (community != null) {
discoverQuery.addFilterQueries("location.comm:" + community.getID().toString());
}
if (StringUtils.isNotBlank(q)) {
StringBuilder buildQuery = new StringBuilder();
String escapedQuery = ClientUtils.escapeQueryChars(q);
buildQuery.append(escapedQuery).append(" OR ").append(escapedQuery).append("*");
discoverQuery.setQuery(buildQuery.toString());
}
DiscoverResult resp = searchService.search(context, discoverQuery);
return resp;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.core.Context;
import org.dspace.discovery.SearchServiceException;
import org.dspace.eperson.Group;


/**
* Service interface class for the Collection object.
* The implementation of this class is responsible for all business logic calls for the Collection object and is
Expand Down Expand Up @@ -354,4 +356,42 @@ public List<Collection> findAuthorized(Context context, Community community, int
*/
Group createDefaultReadGroup(Context context, Collection collection, String typeOfGroupString, int defaultRead)
throws SQLException, AuthorizeException;

/**
* Returns Collections for which the current user has 'submit' privileges.
* NOTE: for better performance, this method retrieves its results from an
* index (cache) and does not query the database directly.
* This means that results may be stale or outdated until DS-4524 is resolved"
*
* @param q limit the returned collection to those with metadata values matching the query terms.
* The terms are used to make also a prefix query on SOLR so it can be used to implement
* an autosuggest feature over the collection name
* @param context DSpace Context
* @param community parent community
* @param offset the position of the first result to return
* @param limit paging limit
* @return discovery search result objects
* @throws SQLException if something goes wrong
* @throws SearchServiceException if search error
*/
public List<Collection> findCollectionsWithSubmit(String q, Context context, Community community,
int offset, int limit) throws SQLException, SearchServiceException;

/**
* Counts the number of Collection for which the current user has 'submit' privileges.
* NOTE: for better performance, this method retrieves its results from an index (cache)
* and does not query the database directly.
* This means that results may be stale or outdated until DS-4524 is resolved."
*
* @param q limit the returned collection to those with metadata values matching the query terms.
* The terms are used to make also a prefix query on SOLR so it can be used to implement
* an autosuggest feature over the collection name
* @param context DSpace Context
* @param community parent community
* @return total collections found
* @throws SQLException if something goes wrong
* @throws SearchServiceException if search error
*/
public int countCollectionsWithSubmit(String q, Context context, Community community)
throws SQLException, SearchServiceException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* 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.discovery;

import java.sql.SQLException;
import java.util.List;

import org.apache.logging.log4j.Logger;
import org.apache.solr.common.SolrInputDocument;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.discovery.indexobject.IndexableCollection;
import org.springframework.beans.factory.annotation.Autowired;

/**
* The purpose of this plugin is to index all ADD type resource policies related to collections.
*
* @author Mykhaylo Boychuk (at 4science.it)
*/
public class SolrServiceIndexCollectionSubmittersPlugin implements SolrServiceIndexPlugin {

private static final Logger log = org.apache.logging.log4j.LogManager
.getLogger(SolrServiceIndexCollectionSubmittersPlugin.class);

@Autowired(required = true)
protected AuthorizeService authorizeService;

@Override
public void additionalIndex(Context context, IndexableObject idxObj, SolrInputDocument document) {
if (idxObj instanceof IndexableCollection) {
Collection col = ((IndexableCollection) idxObj).getIndexedObject();
if (col != null) {
try {
String fieldValue = null;
Community parent = (Community) ContentServiceFactory.getInstance().getDSpaceObjectService(col)
.getParentObject(context, col);
while (parent != null) {
if (parent.getAdministrators() != null) {
fieldValue = "g" + parent.getAdministrators().getID();
document.addField("submit", fieldValue);
}
parent = (Community) ContentServiceFactory.getInstance().getDSpaceObjectService(parent)
.getParentObject(context, parent);
}
List<ResourcePolicy> policies = authorizeService.getPoliciesActionFilter(context, col,
Constants.ADD);
for (ResourcePolicy resourcePolicy : policies) {
if (resourcePolicy.getGroup() != null) {
fieldValue = "g" + resourcePolicy.getGroup().getID();
} else {
fieldValue = "e" + resourcePolicy.getEPerson().getID();

}
document.addField("submit", fieldValue);
context.uncacheEntity(resourcePolicy);
}
} catch (SQLException e) {
log.error(LogManager.getHeader(context, "Error while indexing resource policies",
"Collection: (id " + col.getID() + " type " + col.getName() + ")" ));
}
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,10 @@ public Page<CollectionRest> findAll(Context context, Pageable pageable) {
}
}

@SearchRestMethod(name = "findAuthorizedByCommunity")
public Page<CollectionRest> findAuthorizedByCommunity(
@Parameter(value = "uuid", required = true) UUID communityUuid, Pageable pageable) {
@SearchRestMethod(name = "findSubmitAuthorizedByCommunity")
public Page<CollectionRest> findSubmitAuthorizedByCommunity(
@Parameter(value = "uuid", required = true) UUID communityUuid, Pageable pageable,
@Parameter(value = "query") String q) {
try {
Context context = obtainContext();
Community com = communityService.find(context, communityUuid);
Expand All @@ -174,19 +175,26 @@ public Page<CollectionRest> findAuthorizedByCommunity(
CommunityRest.CATEGORY + "." + CommunityRest.NAME + " with id: " + communityUuid
+ " not found");
}
List<Collection> collections = cs.findAuthorized(context, com, Constants.ADD);
return converter.toRestPage(collections, pageable, utils.obtainProjection());
} catch (SQLException e) {
List<Collection> collections = cs.findCollectionsWithSubmit(q, context, com,
Math.toIntExact(pageable.getOffset()),
Math.toIntExact(pageable.getOffset() + pageable.getPageSize()));
int tot = cs.countCollectionsWithSubmit(q, context, com);
return converter.toRestPage(collections, pageable, tot , utils.obtainProjection());
} catch (SQLException | SearchServiceException e) {
throw new RuntimeException(e.getMessage(), e);
}
}

@SearchRestMethod(name = "findAuthorized")
public Page<CollectionRest> findAuthorized(Pageable pageable) {
@SearchRestMethod(name = "findSubmitAuthorized")
public Page<CollectionRest> findSubmitAuthorized(@Parameter(value = "query") String q,
Pageable pageable) throws SearchServiceException {
try {
Context context = obtainContext();
List<Collection> collections = cs.findAuthorizedOptimized(context, Constants.ADD);
return converter.toRestPage(collections, pageable, utils.obtainProjection());
List<Collection> collections = cs.findCollectionsWithSubmit(q, context, null,
Math.toIntExact(pageable.getOffset()),
Math.toIntExact(pageable.getOffset() + pageable.getPageSize()));
int tot = cs.countCollectionsWithSubmit(q, context, null);
return converter.toRestPage(collections, pageable, tot, utils.obtainProjection());
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
Expand Down

0 comments on commit 69df9b0

Please sign in to comment.