search(Context context, String query, String orderfield, boolean ascending, int offset,
int max, String... filterquery);
diff --git a/dspace-api/src/main/java/org/dspace/discovery/SearchUtils.java b/dspace-api/src/main/java/org/dspace/discovery/SearchUtils.java
index ce3567e916..90afb09eca 100644
--- a/dspace-api/src/main/java/org/dspace/discovery/SearchUtils.java
+++ b/dspace-api/src/main/java/org/dspace/discovery/SearchUtils.java
@@ -32,6 +32,15 @@ import org.dspace.workflow.WorkflowItem;
* @author Ben Bosman (ben at atmire dot com)
*/
public class SearchUtils {
+
+ public static final String AUTHORITY_SEPARATOR = "###";
+ public static final String LAST_INDEXED_FIELD = "SolrIndexer.lastIndexed";
+ public static final String RESOURCE_UNIQUE_ID = "search.uniqueid";
+ public static final String RESOURCE_TYPE_FIELD = "search.resourcetype";
+ public static final String RESOURCE_ID_FIELD = "search.resourceid";
+ public static final String NAMED_RESOURCE_TYPE = "namedresourcetype";
+ public static final String FILTER_SEPARATOR = "\n|||\n";
+
/**
* Cached search service
**/
@@ -161,5 +170,4 @@ public class SearchUtils {
DiscoveryConfiguration configurationExtra = getDiscoveryConfigurationByName(confName);
result.add(configurationExtra);
}
-
}
diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrSearchCore.java b/dspace-api/src/main/java/org/dspace/discovery/SolrSearchCore.java
new file mode 100644
index 0000000000..f61287ac87
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/SolrSearchCore.java
@@ -0,0 +1,87 @@
+/**
+ * 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.io.IOException;
+
+import org.apache.commons.validator.routines.UrlValidator;
+import org.apache.log4j.Logger;
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.dspace.discovery.indexobject.IndexableItem;
+import org.dspace.services.ConfigurationService;
+import org.dspace.services.factory.DSpaceServicesFactory;
+import org.dspace.storage.rdbms.DatabaseUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * Bean containing the SolrClient for the search core
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public class SolrSearchCore {
+
+ private final Logger log = Logger.getLogger(SolrSearchCore.class);
+ @Autowired
+ protected IndexingService indexingService;
+ @Autowired
+ protected ConfigurationService configurationService;
+
+ /**
+ * SolrServer for processing indexing events.
+ */
+ protected SolrClient solr = null;
+
+ public SolrClient getSolr() {
+ if (solr == null) {
+ initSolr();
+ }
+ return solr;
+ }
+
+ /**
+ * Initialize the solr search core
+ */
+ protected void initSolr() {
+ if (solr == null) {
+ String solrService = DSpaceServicesFactory.getInstance().getConfigurationService()
+ .getProperty("discovery.search.server");
+
+ UrlValidator urlValidator = new UrlValidator(UrlValidator.ALLOW_LOCAL_URLS);
+ if (urlValidator.isValid(solrService) || configurationService
+ .getBooleanProperty("discovery.solr.url.validation.enabled", true)) {
+ try {
+ log.debug("Solr URL: " + solrService);
+ HttpSolrClient solrServer = new HttpSolrClient.Builder(solrService).build();
+
+ solrServer.setBaseURL(solrService);
+ solrServer.setUseMultiPartPost(true);
+ // Dummy/test query to search for Item (type=2) of ID=1
+ SolrQuery solrQuery = new SolrQuery()
+ .setQuery(SearchUtils.RESOURCE_TYPE_FIELD + ":" + IndexableItem.TYPE +
+ " AND " + SearchUtils.RESOURCE_ID_FIELD + ":1");
+ // Only return obj identifier fields in result doc
+ solrQuery.setFields(SearchUtils.RESOURCE_TYPE_FIELD, SearchUtils.RESOURCE_ID_FIELD);
+ solrServer.query(solrQuery, SolrRequest.METHOD.POST);
+
+ // As long as Solr initialized, check with DatabaseUtils to see
+ // if a reindex is in order. If so, reindex everything
+ DatabaseUtils.checkReindexDiscovery(indexingService);
+
+ solr = solrServer;
+ } catch (SolrServerException | IOException e) {
+ log.error("Error while initializing solr server", e);
+ }
+ } else {
+ log.error("Error while initializing solr, invalid url: " + solrService);
+ }
+ }
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceContentInOriginalBundleFilterPlugin.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceContentInOriginalBundleFilterPlugin.java
index d389b53538..3d94350f1c 100644
--- a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceContentInOriginalBundleFilterPlugin.java
+++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceContentInOriginalBundleFilterPlugin.java
@@ -14,6 +14,7 @@ import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Item;
import org.dspace.core.Context;
+import org.dspace.discovery.indexobject.IndexableItem;
/**
* This plugin adds three fields to the solr index to make a facet with/without
@@ -29,9 +30,9 @@ import org.dspace.core.Context;
public class SolrServiceContentInOriginalBundleFilterPlugin implements SolrServiceIndexPlugin {
@Override
- public void additionalIndex(Context context, IndexableObject dso, SolrInputDocument document) {
- if (dso instanceof Item) {
- Item item = (Item) dso;
+ public void additionalIndex(Context context, IndexableObject indexableObject, SolrInputDocument document) {
+ if (indexableObject instanceof IndexableItem) {
+ Item item = ((IndexableItem) indexableObject).getIndexedObject();
boolean hasOriginalBundleWithContent = hasOriginalBundleWithContent(item);
// _keyword and _filter because
diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceFileInfoPlugin.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceFileInfoPlugin.java
index e14aa1dbc3..3f5e765b0e 100644
--- a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceFileInfoPlugin.java
+++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceFileInfoPlugin.java
@@ -14,6 +14,7 @@ import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Item;
import org.dspace.core.Context;
+import org.dspace.discovery.indexobject.IndexableItem;
/**
*
@@ -40,9 +41,9 @@ public class SolrServiceFileInfoPlugin implements SolrServiceIndexPlugin {
private static final String SOLR_FIELD_NAME_FOR_DESCRIPTIONS = "original_bundle_descriptions";
@Override
- public void additionalIndex(Context context, IndexableObject dso, SolrInputDocument document) {
- if (dso instanceof Item) {
- Item item = (Item) dso;
+ public void additionalIndex(Context context, IndexableObject indexableObject, SolrInputDocument document) {
+ if (indexableObject instanceof IndexableItem) {
+ Item item = ((IndexableItem) indexableObject).getIndexedObject();
List bundles = item.getBundles();
if (bundles != null) {
for (Bundle bundle : bundles) {
diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java
index 00865f919c..6af1564830 100644
--- a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java
@@ -7,11 +7,8 @@
*/
package org.dspace.discovery;
-import static org.dspace.discovery.configuration.DiscoverySortConfiguration.SCORE;
-
import java.io.IOException;
import java.io.PrintWriter;
-import java.io.Serializable;
import java.io.StringWriter;
import java.sql.SQLException;
import java.text.ParseException;
@@ -19,36 +16,26 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
-import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
-import java.util.Vector;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.collections4.Transformer;
-import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.time.DateFormatUtils;
-import org.apache.commons.validator.routines.UrlValidator;
import org.apache.logging.log4j.Logger;
-import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
-import org.apache.solr.client.solrj.impl.HttpSolrClient;
-import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
-import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.util.ClientUtils;
@@ -57,64 +44,36 @@ import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.FacetParams;
import org.apache.solr.common.params.HighlightParams;
-import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.MoreLikeThisParams;
import org.apache.solr.common.params.SpellingParams;
import org.apache.solr.common.util.NamedList;
-import org.apache.solr.handler.extraction.ExtractingParams;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
-import org.dspace.content.MetadataField;
-import org.dspace.content.MetadataSchema;
-import org.dspace.content.MetadataValue;
-import org.dspace.content.WorkspaceItem;
-import org.dspace.content.authority.Choices;
-import org.dspace.content.authority.service.ChoiceAuthorityService;
-import org.dspace.content.authority.service.MetadataAuthorityService;
import org.dspace.content.factory.ContentServiceFactory;
-import org.dspace.content.service.CollectionService;
-import org.dspace.content.service.CommunityService;
-import org.dspace.content.service.ItemService;
-import org.dspace.content.service.WorkspaceItemService;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.Email;
import org.dspace.core.I18nUtil;
import org.dspace.core.LogManager;
-import org.dspace.discovery.configuration.DiscoveryConfiguration;
import org.dspace.discovery.configuration.DiscoveryConfigurationParameters;
-import org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration;
-import org.dspace.discovery.configuration.DiscoveryHitHighlightingConfiguration;
import org.dspace.discovery.configuration.DiscoveryMoreLikeThisConfiguration;
-import org.dspace.discovery.configuration.DiscoveryRecentSubmissionsConfiguration;
-import org.dspace.discovery.configuration.DiscoverySearchFilter;
import org.dspace.discovery.configuration.DiscoverySearchFilterFacet;
import org.dspace.discovery.configuration.DiscoverySortConfiguration;
-import org.dspace.discovery.configuration.DiscoverySortFieldConfiguration;
-import org.dspace.discovery.configuration.HierarchicalSidebarFacetConfiguration;
+import org.dspace.discovery.indexobject.IndexableCollection;
+import org.dspace.discovery.indexobject.IndexableCommunity;
+import org.dspace.discovery.indexobject.IndexableItem;
+import org.dspace.discovery.indexobject.factory.IndexFactory;
+import org.dspace.discovery.indexobject.factory.IndexObjectFactoryFactory;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.GroupService;
-import org.dspace.handle.service.HandleService;
import org.dspace.services.factory.DSpaceServicesFactory;
-import org.dspace.storage.rdbms.DatabaseUtils;
-import org.dspace.util.MultiFormatDateParser;
-import org.dspace.util.SolrUtils;
-import org.dspace.workflow.WorkflowItem;
-import org.dspace.xmlworkflow.WorkflowConfigurationException;
-import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
-import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
-import org.dspace.xmlworkflow.storedcomponents.PoolTask;
-import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
-import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService;
-import org.dspace.xmlworkflow.storedcomponents.service.PoolTaskService;
-import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -153,94 +112,20 @@ public class SolrServiceImpl implements SearchService, IndexingService {
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(SolrServiceImpl.class);
- protected static final String LAST_INDEXED_FIELD = "SolrIndexer.lastIndexed";
- protected static final String HANDLE_FIELD = "handle";
- protected static final String RESOURCE_UNIQUE_ID = "search.uniqueid";
- protected static final String RESOURCE_TYPE_FIELD = "search.resourcetype";
- protected static final String RESOURCE_ID_FIELD = "search.resourceid";
- protected static final String NAMED_RESOURCE_TYPE = "namedresourcetype";
-
- public static final String FILTER_SEPARATOR = "\n|||\n";
-
- public static final String AUTHORITY_SEPARATOR = "###";
-
- public static final String STORE_SEPARATOR = "\n|||\n";
-
- public static final String VARIANTS_STORE_SEPARATOR = "###";
-
- @Autowired(required = true)
+ @Autowired
protected ContentServiceFactory contentServiceFactory;
- @Autowired(required = true)
- protected ChoiceAuthorityService choiceAuthorityService;
- @Autowired(required = true)
- protected CommunityService communityService;
- @Autowired(required = true)
- protected CollectionService collectionService;
- @Autowired(required = true)
- protected ItemService itemService;
- @Autowired(required = true)
- protected HandleService handleService;
- @Autowired(required = true)
- protected MetadataAuthorityService metadataAuthorityService;
- @Autowired(required = true)
- protected WorkspaceItemService workspaceItemService;
- @Autowired(required = true)
- protected XmlWorkflowItemService workflowItemService;
- @Autowired(required = true)
- protected ClaimedTaskService claimedTaskService;
- @Autowired(required = true)
- protected PoolTaskService poolTaskService;
- @Autowired(required = true)
- protected XmlWorkflowFactory workflowFactory;
- @Autowired(required = true)
+ @Autowired
protected GroupService groupService;
-
- /**
- * Non-Static SolrServer for processing indexing events.
- */
- protected SolrClient solr = null;
-
+ @Autowired
+ protected IndexObjectFactoryFactory indexObjectServiceFactory;
+ @Autowired
+ protected SolrSearchCore solrSearchCore;
protected SolrServiceImpl() {
}
- protected SolrClient getSolr() {
- if (solr == null) {
- String solrService = DSpaceServicesFactory.getInstance().getConfigurationService()
- .getProperty("discovery.search.server");
- UrlValidator urlValidator = new UrlValidator(UrlValidator.ALLOW_LOCAL_URLS);
- if (urlValidator.isValid(solrService) || ConfigurationManager
- .getBooleanProperty("discovery", "solr.url.validation.enabled", true)) {
- try {
- log.debug("Solr URL: " + solrService);
- HttpSolrClient solrServer = new HttpSolrClient.Builder(solrService).build();
-
- solrServer.setBaseURL(solrService);
- solrServer.setUseMultiPartPost(true);
- // Dummy/test query to search for Item (type=2) of ID=1
- SolrQuery solrQuery = new SolrQuery()
- .setQuery(RESOURCE_TYPE_FIELD + ":2 AND " + RESOURCE_ID_FIELD + ":1");
- // Only return obj identifier fields in result doc
- solrQuery.setFields(RESOURCE_TYPE_FIELD, RESOURCE_ID_FIELD);
- solrServer.query(solrQuery, SolrRequest.METHOD.POST);
-
- // As long as Solr initialized, check with DatabaseUtils to see
- // if a reindex is in order. If so, reindex everything
- DatabaseUtils.checkReindexDiscovery(this);
-
- solr = solrServer;
- } catch (SolrServerException | IOException e) {
- log.error("Error while initializing solr server", e);
- }
- } else {
- log.error("Error while initializing solr, invalid url: " + solrService);
- }
- }
-
- return solr;
- }
/**
* If the handle for the "dso" already exists in the index, and the "dso"
@@ -263,62 +148,32 @@ public class SolrServiceImpl implements SearchService, IndexingService {
* then it is updated, otherwise a new document is added.
*
* @param context Users Context
- * @param dso DSpace Object (Item, Collection or Community
+ * @param indexableObject The object we want to index
* @param force Force update even if not stale.
* @throws SQLException if error
*/
@Override
- public void indexContent(Context context, IndexableObject dso,
- boolean force) throws SQLException {
+ public void indexContent(Context context, IndexableObject indexableObject,
+ boolean force) {
try {
- String uuid = dso.getID().toString();
- switch (dso.getType()) {
- case Constants.ITEM:
- Item item = (Item) dso;
- if (item.isArchived() || item.isWithdrawn()) {
- /**
- * If the item is in the repository now, add it to the index
- */
- if (force || requiresIndexing(dso.getUniqueIndexID(), ((Item) dso).getLastModified())) {
- unIndexContent(context, dso);
- buildDocument(context, (Item) dso);
- }
- } else {
- /**
- * Make sure the item is not in the index if it is not in
- * archive or withdrawn.
- */
- unIndexContent(context, dso);
- log.info("Removed Item: " + uuid + " from Index");
-
- /**
- * reindex any in progress submission tasks associated with the item
- */
- indexInProgressSubmissionItem(context, (Item) dso);
- }
- break;
-
- case Constants.COLLECTION:
- buildDocument(context, (Collection) dso);
- log.info("Wrote Collection: " + uuid + " to Index");
- break;
-
- case Constants.COMMUNITY:
- buildDocument(context, (Community) dso);
- log.info("Wrote Community: " + uuid + " to Index");
- break;
-
- default:
- log
- .error("Only Items, Collections and Communities can be Indexed");
+ final IndexFactory indexableObjectFactory = indexObjectServiceFactory.
+ getIndexableObjectFactory(indexableObject);
+ if (force || requiresIndexing(indexableObject.getUniqueIndexID(), indexableObject.getLastModified())) {
+ update(context, indexableObjectFactory, indexableObject);
+ log.info(LogManager.getHeader(context, "indexed_object", indexableObject.getUniqueIndexID()));
}
-
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
+ protected void update(Context context, IndexFactory indexableObjectService,
+ IndexableObject indexableObject) throws IOException, SQLException, SolrServerException {
+ final SolrInputDocument solrInputDocument = indexableObjectService.buildDocument(context, indexableObject);
+ indexableObjectService.writeDocument(context, indexableObject, solrInputDocument);
+ }
+
/**
* unIndex removes an Item, Collection, or Community
*
@@ -337,26 +192,23 @@ public class SolrServiceImpl implements SearchService, IndexingService {
* unIndex removes an Item, Collection, or Community
*
* @param context The relevant DSpace Context.
- * @param dso extension of DSpace Object, can be Community, Item, Collection or InProgressSubmission
+ * @param indexableObject The object to be indexed
* @param commit if true
force an immediate commit on SOLR
* @throws SQLException if database error
* @throws IOException if IO error
*/
@Override
- public void unIndexContent(Context context, IndexableObject dso, boolean commit)
+ public void unIndexContent(Context context, IndexableObject indexableObject, boolean commit)
throws SQLException, IOException {
try {
- if (dso == null) {
+ if (indexableObject == null) {
return;
}
- String uniqueID = dso.getUniqueIndexID();
- log.debug("Try to delete uniqueID:" + uniqueID);
- getSolr().deleteById(uniqueID);
- if (Constants.ITEM == dso.getType()) {
- deleteInProgressSubmissionByItemID(uniqueID);
- }
+ String uniqueID = indexableObject.getUniqueIndexID();
+ log.info("Try to delete uniqueID:" + uniqueID);
+ indexObjectServiceFactory.getIndexableObjectFactory(indexableObject).delete(indexableObject);
if (commit) {
- getSolr().commit();
+ solrSearchCore.getSolr().commit();
}
} catch (Exception exception) {
log.error(exception.getMessage(), exception);
@@ -388,13 +240,10 @@ public class SolrServiceImpl implements SearchService, IndexingService {
throws IOException {
try {
- if (getSolr() != null) {
- getSolr().deleteById(searchUniqueID);
- if (searchUniqueID.startsWith(Constants.ITEM + "-")) {
- deleteInProgressSubmissionByItemID(searchUniqueID);
- }
+ if (solrSearchCore.getSolr() != null) {
+ indexObjectServiceFactory.getIndexableObjectFactory(searchUniqueID).delete(searchUniqueID);
if (commit) {
- getSolr().commit();
+ solrSearchCore.getSolr().commit();
}
}
} catch (SolrServerException e) {
@@ -460,53 +309,26 @@ public class SolrServiceImpl implements SearchService, IndexingService {
*/
@Override
public void updateIndex(Context context, boolean force) {
- updateIndex(context, force, Constants.ITEM);
- updateIndex(context, force, Constants.COLLECTION);
- updateIndex(context, force, Constants.COMMUNITY);
+ updateIndex(context, force, null);
}
-
@Override
- public void updateIndex(Context context, boolean force, int type) {
+ public void updateIndex(Context context, boolean force, String type) {
try {
- switch (type) {
- case Constants.ITEM:
- Iterator- items = itemService.findAllUnfiltered(context);
- while (items.hasNext()) {
- Item item = items.next();
- indexContent(context, item, force);
- //To prevent memory issues, discard an object from the cache after processing
- context.uncacheEntity(item);
+ final List indexableObjectServices = indexObjectServiceFactory.
+ getIndexFactories();
+ for (IndexFactory indexableObjectService : indexableObjectServices) {
+ if (type == null || StringUtils.equals(indexableObjectService.getType(), type)) {
+ final Iterator indexableObjects = indexableObjectService.findAll(context);
+ while (indexableObjects.hasNext()) {
+ final IndexableObject indexableObject = indexableObjects.next();
+ indexContent(context, indexableObject, force);
+ context.uncacheEntity(indexableObject.getIndexedObject());
}
- for (WorkspaceItem wsi : workspaceItemService.findAll(context)) {
- indexContent(context, wsi.getItem(), force);
- //To prevent memory issues, discard an object from the cache after processing
- context.uncacheEntity(wsi);
- }
- for (WorkflowItem wfi : workflowItemService.findAll(context)) {
- indexContent(context, wfi.getItem(), force);
- //To prevent memory issues, discard an object from the cache after processing
- context.uncacheEntity(wfi);
- }
- break;
- case Constants.COLLECTION:
- List collections = collectionService.findAll(context);
- for (Collection collection : collections) {
- indexContent(context, collection, force);
- }
- break;
- case Constants.COMMUNITY:
- List communities = communityService.findAll(context);
- for (Community community : communities) {
- indexContent(context, community, force);
- }
- break;
- default:
- throw new IllegalArgumentException("No type known: " + type);
+ }
}
-
- if (getSolr() != null) {
- getSolr().commit();
+ if (solrSearchCore.getSolr() != null) {
+ solrSearchCore.getSolr().commit();
}
} catch (Exception e) {
@@ -525,65 +347,58 @@ public class SolrServiceImpl implements SearchService, IndexingService {
*/
@Override
public void cleanIndex(boolean force) throws IOException, SQLException, SearchServiceException {
- if (force) {
- try {
- getSolr().deleteByQuery(
- "search.resourcetype:[" + Constants.ITEM + " TO " + Constants.COMMUNITY + "]" +
- " OR " +
- "search.resourcetype:[" + Constants.WORKSPACEITEM + " TO " + Constants.CLAIMEDTASK + "]");
- } catch (Exception e) {
- throw new SearchServiceException(e.getMessage(), e);
- }
- } else {
- cleanIndex(false, Constants.ITEM);
- cleanIndex(false, Constants.COLLECTION);
- cleanIndex(false, Constants.COMMUNITY);
- cleanIndex(false, Constants.WORKSPACEITEM);
- cleanIndex(false, Constants.POOLTASK);
- cleanIndex(false, Constants.CLAIMEDTASK);
- cleanIndex(false, Constants.WORKFLOWITEM);
- }
- }
-
- @Override
- public void cleanIndex(boolean force, int type) throws IOException, SQLException, SearchServiceException {
Context context = new Context();
context.turnOffAuthorisationSystem();
try {
- if (getSolr() == null) {
+ if (solrSearchCore.getSolr() == null) {
return;
}
if (force) {
- getSolr().deleteByQuery(RESOURCE_TYPE_FIELD + ":" + type);
+ final List indexableObjectServices = indexObjectServiceFactory.
+ getIndexFactories();
+ for (IndexFactory indexableObjectService : indexableObjectServices) {
+ indexableObjectService.deleteAll();
+ }
} else {
SolrQuery query = new SolrQuery();
// Query for all indexed Items, Collections and Communities,
// returning just their handle
- query.setFields(HANDLE_FIELD, RESOURCE_UNIQUE_ID, RESOURCE_ID_FIELD, RESOURCE_TYPE_FIELD);
- query.setQuery(RESOURCE_TYPE_FIELD + ":" + type);
- QueryResponse rsp = getSolr().query(query, SolrRequest.METHOD.POST);
- SolrDocumentList docs = rsp.getResults();
+ query.setFields(SearchUtils.RESOURCE_UNIQUE_ID);
+ query.addSort(SearchUtils.RESOURCE_UNIQUE_ID, SolrQuery.ORDER.asc);
+ query.setQuery("*:*");
- Iterator iter = docs.iterator();
- while (iter.hasNext()) {
+ // Get the total amount of results
+ QueryResponse totalResponse = solrSearchCore.getSolr().query(query, SolrRequest.METHOD.POST);
+ long total = totalResponse.getResults().getNumFound();
- SolrDocument doc = (SolrDocument) iter.next();
+ int start = 0;
+ int batch = 100;
- String uniqueID = (String) doc.getFieldValue(RESOURCE_UNIQUE_ID);
+ query.setRows(batch);
+ while (start < total) {
+ query.setStart(start);
+ QueryResponse rsp = solrSearchCore.getSolr().query(query, SolrRequest.METHOD.POST);
+ SolrDocumentList docs = rsp.getResults();
- IndexableObject o = findIndexableObject(context, doc);
+ for (SolrDocument doc : docs) {
+ String uniqueID = (String) doc.getFieldValue(SearchUtils.RESOURCE_UNIQUE_ID);
- if (o == null) {
- log.info("Deleting: " + uniqueID);
- /*
- * Use IndexWriter to delete, its easier to manage
- * write.lock
- */
- unIndexContent(context, uniqueID);
- } else {
- log.debug("Keeping: " + o.getUniqueIndexID());
+ IndexableObject o = findIndexableObject(context, doc);
+
+ if (o == null) {
+ log.info("Deleting: " + uniqueID);
+ /*
+ * Use IndexWriter to delete, its easier to manage
+ * write.lock
+ */
+ unIndexContent(context, uniqueID);
+ } else {
+ log.debug("Keeping: " + o.getUniqueIndexID());
+ }
}
+
+ start += batch;
}
}
} catch (Exception e) {
@@ -600,12 +415,12 @@ public class SolrServiceImpl implements SearchService, IndexingService {
@Override
public void optimize() {
try {
- if (getSolr() == null) {
+ if (solrSearchCore.getSolr() == null) {
return;
}
long start = System.currentTimeMillis();
System.out.println("SOLR Search Optimize -- Process Started:" + start);
- getSolr().optimize();
+ solrSearchCore.getSolr().optimize();
long finish = System.currentTimeMillis();
System.out.println("SOLR Search Optimize -- Process Finished:" + finish);
System.out.println("SOLR Search Optimize -- Total time taken:" + (finish - start) + " (ms).");
@@ -620,13 +435,13 @@ public class SolrServiceImpl implements SearchService, IndexingService {
public void buildSpellCheck()
throws SearchServiceException, IOException {
try {
- if (getSolr() == null) {
+ if (solrSearchCore.getSolr() == null) {
return;
}
SolrQuery solrQuery = new SolrQuery();
solrQuery.set("spellcheck", true);
solrQuery.set(SpellingParams.SPELLCHECK_BUILD, true);
- getSolr().query(solrQuery, SolrRequest.METHOD.POST);
+ solrSearchCore.getSolr().query(solrQuery, SolrRequest.METHOD.POST);
} catch (SolrServerException e) {
//Make sure to also log the exception since this command is usually run from a crontab.
log.error(e, e);
@@ -680,30 +495,35 @@ public class SolrServiceImpl implements SearchService, IndexingService {
* Is stale checks the lastModified time stamp in the database and the index
* to determine if the index is stale.
*
- * @param handle the handle of the dso
+ * @param uniqueId the unique identifier of the object that we want to index
* @param lastModified the last modified date of the DSpace object
* @return a boolean indicating if the dso should be re indexed again
* @throws SQLException sql exception
* @throws IOException io exception
* @throws SearchServiceException if something went wrong with querying the solr server
*/
- protected boolean requiresIndexing(String handle, Date lastModified)
+ protected boolean requiresIndexing(String uniqueId, Date lastModified)
throws SQLException, IOException, SearchServiceException {
+ // Check if we even have a last modified date
+ if (lastModified == null) {
+ return true;
+ }
+
boolean reindexItem = false;
boolean inIndex = false;
SolrQuery query = new SolrQuery();
- query.setQuery(RESOURCE_UNIQUE_ID + ":" + handle);
+ query.setQuery(SearchUtils.RESOURCE_UNIQUE_ID + ":" + uniqueId);
// Specify that we ONLY want the LAST_INDEXED_FIELD returned in the field list (fl)
- query.setFields(LAST_INDEXED_FIELD);
+ query.setFields(SearchUtils.LAST_INDEXED_FIELD);
QueryResponse rsp;
try {
- if (getSolr() == null) {
+ if (solrSearchCore.getSolr() == null) {
return false;
}
- rsp = getSolr().query(query, SolrRequest.METHOD.POST);
+ rsp = solrSearchCore.getSolr().query(query, SolrRequest.METHOD.POST);
} catch (SolrServerException e) {
throw new SearchServiceException(e.getMessage(), e);
}
@@ -712,7 +532,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
inIndex = true;
- Object value = doc.getFieldValue(LAST_INDEXED_FIELD);
+ Object value = doc.getFieldValue(SearchUtils.LAST_INDEXED_FIELD);
if (value instanceof Date) {
Date lastIndexed = (Date) value;
@@ -727,63 +547,6 @@ public class SolrServiceImpl implements SearchService, IndexingService {
return reindexItem || !inIndex;
}
-
- /**
- * @param context DSpace context
- * @param myitem the item for which our locations are to be retrieved
- * @return a list containing the identifiers of the communities and collections
- * @throws SQLException sql exception
- */
- protected List getItemLocations(Context context, Item myitem)
- throws SQLException {
- List locations = new Vector();
-
- // build list of community ids
- List communities = itemService.getCommunities(context, myitem);
-
- // build list of collection ids
- List collections = myitem.getCollections();
-
- // now put those into strings
- int i = 0;
-
- for (i = 0; i < communities.size(); i++) {
- locations.add("m" + communities.get(i).getID());
- }
-
- for (i = 0; i < collections.size(); i++) {
- locations.add("l" + collections.get(i).getID());
- }
-
- return locations;
- }
-
- protected List getCollectionLocations(Context context, Collection target) throws SQLException {
- List locations = new Vector();
- // build list of community ids
- List communities = communityService.getAllParents(context, target);
-
- // now put those into strings
- for (Community community : communities) {
- locations.add("m" + community.getID());
- }
-
- return locations;
- }
-
- protected List getCommunityLocations(Community target) throws SQLException {
- List locations = new Vector();
- // build list of community ids
- List communities = target.getParentCommunities();
-
- // now put those into strings
- for (Community community : communities) {
- locations.add("m" + community.getID());
- }
-
- return locations;
- }
-
@Override
public String createLocationQueryForAdministrableItems(Context context)
throws SQLException {
@@ -850,928 +613,6 @@ public class SolrServiceImpl implements SearchService, IndexingService {
return locationQuery.toString();
}
- /**
- * Write the document to the index under the appropriate handle.
- *
- * @param doc the solr document to be written to the server
- * @param streams list of bitstream content streams
- * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
- */
- protected void writeDocument(SolrInputDocument doc, FullTextContentStreams streams) throws IOException {
-
- try {
- if (getSolr() != null) {
- if (streams != null && !streams.isEmpty()) {
- ContentStreamUpdateRequest req = new ContentStreamUpdateRequest("/update/extract");
- req.addContentStream(streams);
-
- ModifiableSolrParams params = new ModifiableSolrParams();
-
- //req.setParam(ExtractingParams.EXTRACT_ONLY, "true");
- for (String name : doc.getFieldNames()) {
- for (Object val : doc.getFieldValues(name)) {
- params.add(ExtractingParams.LITERALS_PREFIX + name, val.toString());
- }
- }
-
- req.setParams(params);
- req.setParam(ExtractingParams.UNKNOWN_FIELD_PREFIX, "attr_");
- req.setParam(ExtractingParams.MAP_PREFIX + "content", "fulltext");
- req.setParam(ExtractingParams.EXTRACT_FORMAT, "text");
- req.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true);
- req.process(getSolr());
- } else {
- getSolr().add(doc);
- }
- }
- } catch (SolrServerException e) {
- log.error(e.getMessage(), e);
- }
- }
-
- /**
- * Build a solr document for a DSpace Community.
- *
- * @param context The relevant DSpace Context.
- * @param community Community to be indexed
- * @throws SQLException if database error
- * @throws IOException if IO error
- */
- protected void buildDocument(Context context, Community community)
- throws SQLException, IOException {
-
- List locations = getCommunityLocations(community);
-
- // Create Document
- SolrInputDocument doc = buildDocument(Constants.COMMUNITY, community.getID(),
- community.getHandle(), locations);
-
- DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(community);
- DiscoveryHitHighlightingConfiguration highlightingConfiguration = discoveryConfiguration
- .getHitHighlightingConfiguration();
- List highlightedMetadataFields = new ArrayList();
- if (highlightingConfiguration != null) {
- for (DiscoveryHitHighlightFieldConfiguration configuration : highlightingConfiguration
- .getMetadataFields()) {
- highlightedMetadataFields.add(configuration.getField());
- }
- }
-
- // and populate it
- String description = communityService.getMetadata(community, "introductory_text");
- String description_abstract = communityService.getMetadata(community, "short_description");
- String description_table = communityService.getMetadata(community, "side_bar_text");
- String rights = communityService.getMetadata(community, "copyright_text");
- String title = communityService.getMetadata(community, "name");
-
- List toIgnoreMetadataFields = SearchUtils.getIgnoredMetadataFields(community.getType());
- addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description",
- description);
- addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description.abstract",
- description_abstract);
- addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields,
- "dc.description.tableofcontents", description_table);
- addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.rights", rights);
- addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.title", title);
-
- //Do any additional indexing, depends on the plugins
- List solrServiceIndexPlugins = DSpaceServicesFactory.getInstance().getServiceManager()
- .getServicesByType(
- SolrServiceIndexPlugin.class);
- for (SolrServiceIndexPlugin solrServiceIndexPlugin : solrServiceIndexPlugins) {
- solrServiceIndexPlugin.additionalIndex(context, community, doc);
- }
-
- writeDocument(doc, null);
- }
-
- /**
- * Build a solr document for a DSpace Collection.
- *
- * @param context The relevant DSpace Context.
- * @param collection Collection to be indexed
- * @throws SQLException sql exception
- * @throws IOException IO exception
- */
- protected void buildDocument(Context context, Collection collection)
- throws SQLException, IOException {
- List locations = getCollectionLocations(context, collection);
-
- // Create Lucene Document
- SolrInputDocument doc = buildDocument(Constants.COLLECTION, collection.getID(),
- collection.getHandle(), locations);
-
- DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(collection);
- DiscoveryHitHighlightingConfiguration highlightingConfiguration = discoveryConfiguration
- .getHitHighlightingConfiguration();
- List highlightedMetadataFields = new ArrayList();
- if (highlightingConfiguration != null) {
- for (DiscoveryHitHighlightFieldConfiguration configuration : highlightingConfiguration
- .getMetadataFields()) {
- highlightedMetadataFields.add(configuration.getField());
- }
- }
-
-
- // and populate it
- String description = collectionService.getMetadata(collection, "introductory_text");
- String description_abstract = collectionService.getMetadata(collection, "short_description");
- String description_table = collectionService.getMetadata(collection, "side_bar_text");
- String provenance = collectionService.getMetadata(collection, "provenance_description");
- String rights = collectionService.getMetadata(collection, "copyright_text");
- String rights_license = collectionService.getMetadata(collection, "license");
- String title = collectionService.getMetadata(collection, "name");
-
- List toIgnoreMetadataFields = SearchUtils.getIgnoredMetadataFields(collection.getType());
- addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description",
- description);
- addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description.abstract",
- description_abstract);
- addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields,
- "dc.description.tableofcontents", description_table);
- addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.provenance", provenance);
- addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.rights", rights);
- addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.rights.license",
- rights_license);
- addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.title", title);
-
-
- //Do any additional indexing, depends on the plugins
- List solrServiceIndexPlugins = DSpaceServicesFactory.getInstance().getServiceManager()
- .getServicesByType(
- SolrServiceIndexPlugin.class);
- for (SolrServiceIndexPlugin solrServiceIndexPlugin : solrServiceIndexPlugins) {
- solrServiceIndexPlugin.additionalIndex(context, collection, doc);
- }
-
- writeDocument(doc, null);
- }
-
- /**
- * Add the metadata value of the community/collection to the solr document
- * IF needed highlighting is added !
- *
- * @param doc the solr document
- * @param highlightedMetadataFields the list of metadata fields that CAN be highlighted
- * @param toIgnoreMetadataFields the list of metadata fields to skip adding to Solr
- * @param metadataField the metadata field added
- * @param value the value (can be NULL !)
- */
- protected void addContainerMetadataField(SolrInputDocument doc, List highlightedMetadataFields,
- List toIgnoreMetadataFields, String metadataField, String value) {
- if (toIgnoreMetadataFields == null || !toIgnoreMetadataFields.contains(metadataField)) {
- if (StringUtils.isNotBlank(value)) {
- doc.addField(metadataField, value);
- if (highlightedMetadataFields.contains(metadataField)) {
- doc.addField(metadataField + "_hl", value);
- }
- }
- }
- }
-
- /**
- * Build a Lucene document for a DSpace Item and write the index
- *
- * @param context Users Context
- * @param item The DSpace Item to be indexed
- * @throws SQLException if database error
- * @throws IOException if IO error
- */
- protected void buildDocument(Context context, Item item)
- throws SQLException, IOException {
- String handle = item.getHandle();
-
- if (handle == null) {
- handle = handleService.findHandle(context, item);
- }
-
- // get the location string (for searching by collection & community)
- List locations = getItemLocations(context, item);
-
- SolrInputDocument doc = buildDocument(Constants.ITEM, item.getID(), handle,
- locations);
-
- log.debug("Building Item: " + handle);
-
- doc.addField("archived", item.isArchived());
- doc.addField("withdrawn", item.isWithdrawn());
- doc.addField("discoverable", item.isDiscoverable());
- doc.addField("lastModified", SolrUtils.getDateFormatter().format(item.getLastModified()));
-
- EPerson submitter = item.getSubmitter();
- if (submitter != null) {
- addFacetIndex(doc, "submitter", submitter.getID().toString(),
- submitter.getFullName());
- }
-
- List discoveryConfigurations = SearchUtils.getAllDiscoveryConfigurations(item);
- addDiscoveryFields(doc, context, item, discoveryConfigurations);
-
- //mandatory facet to show status on mydspace
- final String typeText = StringUtils.deleteWhitespace(item.getTypeText().toLowerCase());
- String acvalue = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty(
- "discovery.facet.namedtype." + typeText,
- typeText + SolrServiceImpl.AUTHORITY_SEPARATOR + typeText);
- if (StringUtils.isNotBlank(acvalue)) {
- addNamedResourceTypeIndex(doc, acvalue);
- }
-
- // write the index and close the inputstreamreaders
- try {
- writeDocument(doc, new FullTextContentStreams(context, item));
- log.info("Wrote Item: " + item.getUniqueIndexID() + " to Index");
- } catch (RuntimeException e) {
- log.error("Error while writing item to discovery index: " + item.getUniqueIndexID() + " message:"
- + e.getMessage(), e);
- }
- }
-
- protected void addDiscoveryFields(SolrInputDocument doc, Context context, Item item,
- List discoveryConfigurations)
- throws SQLException, IOException {
- //Keep a list of our sort values which we added, sort values can only be added once
- List sortFieldsAdded = new ArrayList();
- Map> searchFilters = null;
- Set hitHighlightingFields = new HashSet();
- try {
- //A map used to save each sidebarFacet config by the metadata fields
- searchFilters = new HashMap>();
- Map sortFields = new HashMap();
- Map recentSubmissionsConfigurationMap = new
- HashMap();
- Set moreLikeThisFields = new HashSet();
- // some configuration are returned multiple times, skip them to save CPU cycles
- Set appliedConf = new HashSet();
- // it is common to have search filter shared between multiple configurations
- Set appliedDiscoverySearchFilter = new HashSet();
-
- for (DiscoveryConfiguration discoveryConfiguration : discoveryConfigurations) {
- if (appliedConf.contains(discoveryConfiguration.getId())) {
- continue;
- } else {
- appliedConf.add(discoveryConfiguration.getId());
- }
- for (int i = 0; i < discoveryConfiguration.getSearchFilters().size(); i++) {
- if (appliedDiscoverySearchFilter
- .contains(discoveryConfiguration.getSearchFilters().get(i).getIndexFieldName())) {
- continue;
- } else {
- appliedDiscoverySearchFilter
- .add(discoveryConfiguration.getSearchFilters().get(i).getIndexFieldName());
- }
- List metadataValueList = new LinkedList<>();
- boolean shouldExposeMinMax = false;
- DiscoverySearchFilter discoverySearchFilter = discoveryConfiguration.getSearchFilters().get(i);
- if (StringUtils.equalsIgnoreCase(discoverySearchFilter.getFilterType(), "facet")) {
- if (((DiscoverySearchFilterFacet) discoverySearchFilter).exposeMinAndMaxValue()) {
- shouldExposeMinMax = true;
- }
- }
- for (int j = 0; j < discoverySearchFilter.getMetadataFields().size(); j++) {
- String metadataField = discoverySearchFilter.getMetadataFields().get(j);
- List resultingList;
- if (searchFilters.get(metadataField) != null) {
- resultingList = searchFilters.get(metadataField);
- } else {
- //New metadata field, create a new list for it
- resultingList = new ArrayList();
- }
-
-
- if (shouldExposeMinMax) {
- String[] splittedMetadataField = metadataField.split("\\.");
- String schema = splittedMetadataField[0];
- String element = splittedMetadataField.length > 1 ? splittedMetadataField[1] : null;
- String qualifier = splittedMetadataField.length > 2 ? splittedMetadataField[2] : null;
-
- metadataValueList.addAll(itemService.getMetadata(item, schema,
- element, qualifier, Item.ANY));
-
- }
-
- resultingList.add(discoverySearchFilter);
-
- searchFilters.put(metadataField, resultingList);
- }
-
- if (!metadataValueList.isEmpty() && shouldExposeMinMax) {
- metadataValueList.sort(new Comparator() {
- public int compare(MetadataValue mdv1,MetadataValue mdv2) {
- return mdv1.getValue().compareTo(mdv2.getValue()) ;
- }
- });
- MetadataValue firstMetadataValue = metadataValueList.get(0);
- MetadataValue lastMetadataValue = metadataValueList.get(metadataValueList.size() - 1);
-
- doc.addField(discoverySearchFilter.getIndexFieldName() + "_min", firstMetadataValue.getValue());
- doc.addField(discoverySearchFilter.getIndexFieldName()
- + "_min_sort", firstMetadataValue.getValue());
- doc.addField(discoverySearchFilter.getIndexFieldName() + "_max", lastMetadataValue.getValue());
- doc.addField(discoverySearchFilter.getIndexFieldName()
- + "_max_sort", lastMetadataValue.getValue());
-
- }
- }
-
- DiscoverySortConfiguration sortConfiguration = discoveryConfiguration.getSearchSortConfiguration();
- if (sortConfiguration != null) {
- for (DiscoverySortFieldConfiguration discoverySortConfiguration : sortConfiguration
- .getSortFields()) {
- sortFields.put(discoverySortConfiguration.getMetadataField(), discoverySortConfiguration);
- }
- }
-
- DiscoveryRecentSubmissionsConfiguration recentSubmissionConfiguration = discoveryConfiguration
- .getRecentSubmissionConfiguration();
- if (recentSubmissionConfiguration != null) {
- recentSubmissionsConfigurationMap
- .put(recentSubmissionConfiguration.getMetadataSortField(), recentSubmissionConfiguration);
- }
-
- DiscoveryHitHighlightingConfiguration hitHighlightingConfiguration = discoveryConfiguration
- .getHitHighlightingConfiguration();
- if (hitHighlightingConfiguration != null) {
- List fieldConfigurations = hitHighlightingConfiguration
- .getMetadataFields();
- for (DiscoveryHitHighlightFieldConfiguration fieldConfiguration : fieldConfigurations) {
- hitHighlightingFields.add(fieldConfiguration.getField());
- }
- }
- DiscoveryMoreLikeThisConfiguration moreLikeThisConfiguration = discoveryConfiguration
- .getMoreLikeThisConfiguration();
- if (moreLikeThisConfiguration != null) {
- for (String metadataField : moreLikeThisConfiguration.getSimilarityMetadataFields()) {
- moreLikeThisFields.add(metadataField);
- }
- }
- }
-
-
- List toProjectionFields = new ArrayList();
- String[] projectionFields = DSpaceServicesFactory.getInstance().getConfigurationService()
- .getArrayProperty("discovery.index.projection");
- if (projectionFields != null) {
- for (String field : projectionFields) {
- toProjectionFields.add(field.trim());
- }
- }
-
- List toIgnoreMetadataFields = SearchUtils.getIgnoredMetadataFields(item.getType());
- List mydc = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY);
- for (MetadataValue meta : mydc) {
- MetadataField metadataField = meta.getMetadataField();
- MetadataSchema metadataSchema = metadataField.getMetadataSchema();
- String field = metadataSchema.getName() + "." + metadataField.getElement();
- String unqualifiedField = field;
-
- String value = meta.getValue();
-
- if (value == null) {
- continue;
- }
-
- if (metadataField.getQualifier() != null && !metadataField.getQualifier().trim().equals("")) {
- field += "." + metadataField.getQualifier();
- }
-
- //We are not indexing provenance, this is useless
- if (toIgnoreMetadataFields != null && (toIgnoreMetadataFields.contains(field) || toIgnoreMetadataFields
- .contains(unqualifiedField + "." + Item.ANY))) {
- continue;
- }
-
- String authority = null;
- String preferedLabel = null;
- List variants = null;
- boolean isAuthorityControlled = metadataAuthorityService
- .isAuthorityControlled(metadataField);
-
- int minConfidence = isAuthorityControlled ? metadataAuthorityService
- .getMinConfidence(metadataField) : Choices.CF_ACCEPTED;
-
- if (isAuthorityControlled && meta.getAuthority() != null
- && meta.getConfidence() >= minConfidence) {
- boolean ignoreAuthority =
- DSpaceServicesFactory
- .getInstance()
- .getConfigurationService()
- .getPropertyAsType("discovery.index.authority.ignore." + field,
- DSpaceServicesFactory
- .getInstance()
- .getConfigurationService()
- .getPropertyAsType("discovery.index.authority.ignore",
- new Boolean(false)),
- true);
- if (!ignoreAuthority) {
- authority = meta.getAuthority();
-
- boolean ignorePrefered =
- DSpaceServicesFactory
- .getInstance()
- .getConfigurationService()
- .getPropertyAsType("discovery.index.authority.ignore-prefered." + field,
- DSpaceServicesFactory
- .getInstance()
- .getConfigurationService()
- .getPropertyAsType("discovery.index.authority.ignore-prefered",
- new Boolean(false)),
- true);
- if (!ignorePrefered) {
-
- preferedLabel = choiceAuthorityService
- .getLabel(meta, meta.getLanguage());
- }
-
- boolean ignoreVariants =
- DSpaceServicesFactory
- .getInstance()
- .getConfigurationService()
- .getPropertyAsType("discovery.index.authority.ignore-variants." + field,
- DSpaceServicesFactory
- .getInstance()
- .getConfigurationService()
- .getPropertyAsType("discovery.index.authority.ignore-variants",
- new Boolean(false)),
- true);
- if (!ignoreVariants) {
- variants = choiceAuthorityService
- .getVariants(meta);
- }
-
- }
- }
-
- if ((searchFilters.get(field) != null || searchFilters
- .get(unqualifiedField + "." + Item.ANY) != null)) {
- List searchFilterConfigs = searchFilters.get(field);
- if (searchFilterConfigs == null) {
- searchFilterConfigs = searchFilters.get(unqualifiedField + "." + Item.ANY);
- }
-
- for (DiscoverySearchFilter searchFilter : searchFilterConfigs) {
- Date date = null;
- String separator = DSpaceServicesFactory.getInstance().getConfigurationService()
- .getProperty("discovery.solr.facets.split.char");
- if (separator == null) {
- separator = FILTER_SEPARATOR;
- }
- if (searchFilter.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE)) {
- //For our search filters that are dates we format them properly
- date = MultiFormatDateParser.parse(value);
- if (date != null) {
- //TODO: make this date format configurable !
- value = DateFormatUtils.formatUTC(date, "yyyy-MM-dd");
- }
- }
- doc.addField(searchFilter.getIndexFieldName(), value);
- doc.addField(searchFilter.getIndexFieldName() + "_keyword", value);
-
- if (authority != null && preferedLabel == null) {
- doc.addField(searchFilter.getIndexFieldName()
- + "_keyword", value + AUTHORITY_SEPARATOR
- + authority);
- doc.addField(searchFilter.getIndexFieldName()
- + "_authority", authority);
- doc.addField(searchFilter.getIndexFieldName()
- + "_acid", value.toLowerCase()
- + separator + value
- + AUTHORITY_SEPARATOR + authority);
- }
-
- if (preferedLabel != null) {
- doc.addField(searchFilter.getIndexFieldName(),
- preferedLabel);
- doc.addField(searchFilter.getIndexFieldName()
- + "_keyword", preferedLabel);
- doc.addField(searchFilter.getIndexFieldName()
- + "_keyword", preferedLabel
- + AUTHORITY_SEPARATOR + authority);
- doc.addField(searchFilter.getIndexFieldName()
- + "_authority", authority);
- doc.addField(searchFilter.getIndexFieldName()
- + "_acid", preferedLabel.toLowerCase()
- + separator + preferedLabel
- + AUTHORITY_SEPARATOR + authority);
- }
- if (variants != null) {
- for (String var : variants) {
- doc.addField(searchFilter.getIndexFieldName() + "_keyword", var);
- doc.addField(searchFilter.getIndexFieldName()
- + "_acid", var.toLowerCase()
- + separator + var
- + AUTHORITY_SEPARATOR + authority);
- }
- }
-
- //Add a dynamic fields for auto complete in search
- doc.addField(searchFilter.getIndexFieldName() + "_ac",
- value.toLowerCase() + separator + value);
- if (preferedLabel != null) {
- doc.addField(searchFilter.getIndexFieldName()
- + "_ac", preferedLabel.toLowerCase()
- + separator + preferedLabel);
- }
- if (variants != null) {
- for (String var : variants) {
- doc.addField(searchFilter.getIndexFieldName()
- + "_ac", var.toLowerCase() + separator
- + var);
- }
- }
-
- if (searchFilter.getFilterType().equals(DiscoverySearchFilterFacet.FILTER_TYPE_FACET)) {
- if (searchFilter.getType().equals(DiscoveryConfigurationParameters.TYPE_TEXT)) {
- //Add a special filter
- //We use a separator to split up the lowercase and regular case, this is needed to
- // get our filters in regular case
- //Solr has issues with facet prefix and cases
- if (authority != null) {
- String facetValue = preferedLabel != null ? preferedLabel : value;
- doc.addField(searchFilter.getIndexFieldName() + "_filter", facetValue
- .toLowerCase() + separator + facetValue + AUTHORITY_SEPARATOR + authority);
- } else {
- doc.addField(searchFilter.getIndexFieldName() + "_filter",
- value.toLowerCase() + separator + value);
- }
- } else if (searchFilter.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE)) {
- if (date != null) {
- String indexField = searchFilter.getIndexFieldName() + ".year";
- String yearUTC = DateFormatUtils.formatUTC(date, "yyyy");
- doc.addField(searchFilter.getIndexFieldName() + "_keyword", yearUTC);
- // add the year to the autocomplete index
- doc.addField(searchFilter.getIndexFieldName() + "_ac", yearUTC);
- doc.addField(indexField, yearUTC);
-
- if (yearUTC.startsWith("0")) {
- doc.addField(
- searchFilter.getIndexFieldName()
- + "_keyword",
- yearUTC.replaceFirst("0*", ""));
- // add date without starting zeros for autocomplete e filtering
- doc.addField(
- searchFilter.getIndexFieldName()
- + "_ac",
- yearUTC.replaceFirst("0*", ""));
- doc.addField(
- searchFilter.getIndexFieldName()
- + "_ac",
- value.replaceFirst("0*", ""));
- doc.addField(
- searchFilter.getIndexFieldName()
- + "_keyword",
- value.replaceFirst("0*", ""));
- }
-
- //Also save a sort value of this year, this is required for determining the upper
- // & lower bound year of our facet
- if (doc.getField(indexField + "_sort") == null) {
- //We can only add one year so take the first one
- doc.addField(indexField + "_sort", yearUTC);
- }
- }
- } else if (searchFilter.getType()
- .equals(DiscoveryConfigurationParameters.TYPE_HIERARCHICAL)) {
- HierarchicalSidebarFacetConfiguration hierarchicalSidebarFacetConfiguration =
- (HierarchicalSidebarFacetConfiguration) searchFilter;
- String[] subValues = value.split(hierarchicalSidebarFacetConfiguration.getSplitter());
- if (hierarchicalSidebarFacetConfiguration
- .isSkipFirstNodeLevel() && 1 < subValues.length) {
- //Remove the first element of our array
- subValues = (String[]) ArrayUtils.subarray(subValues, 1, subValues.length);
- }
- for (int i = 0; i < subValues.length; i++) {
- StringBuilder valueBuilder = new StringBuilder();
- for (int j = 0; j <= i; j++) {
- valueBuilder.append(subValues[j]);
- if (j < i) {
- valueBuilder.append(hierarchicalSidebarFacetConfiguration.getSplitter());
- }
- }
-
- String indexValue = valueBuilder.toString().trim();
- doc.addField(searchFilter.getIndexFieldName() + "_tax_" + i + "_filter",
- indexValue.toLowerCase() + separator + indexValue);
- //We add the field x times that it has occurred
- for (int j = i; j < subValues.length; j++) {
- doc.addField(searchFilter.getIndexFieldName() + "_filter",
- indexValue.toLowerCase() + separator + indexValue);
- doc.addField(searchFilter.getIndexFieldName() + "_keyword", indexValue);
- }
- }
- }
- }
- }
- }
-
- if ((sortFields.get(field) != null || recentSubmissionsConfigurationMap
- .get(field) != null) && !sortFieldsAdded.contains(field)) {
- //Only add sort value once
- String type;
- if (sortFields.get(field) != null) {
- type = sortFields.get(field).getType();
- } else {
- type = recentSubmissionsConfigurationMap.get(field).getType();
- }
-
- if (type.equals(DiscoveryConfigurationParameters.TYPE_DATE)) {
- Date date = MultiFormatDateParser.parse(value);
- if (date != null) {
- String stringDate = SolrUtils.getDateFormatter().format(date);
- doc.addField(field + "_dt", stringDate);
- } else {
- log.warn("Error while indexing sort date field, item: " + item
- .getHandle() + " metadata field: " + field + " date value: " + date);
- }
- } else {
- doc.addField(field + "_sort", value);
- }
- sortFieldsAdded.add(field);
- }
-
- if (hitHighlightingFields.contains(field) || hitHighlightingFields
- .contains("*") || hitHighlightingFields.contains(unqualifiedField + "." + Item.ANY)) {
- if (authority != null) {
- doc.addField(field + "_hl", value + AUTHORITY_SEPARATOR + authority);
- } else {
- doc.addField(field + "_hl", value);
- }
- }
-
- if (moreLikeThisFields.contains(field) || moreLikeThisFields
- .contains(unqualifiedField + "." + Item.ANY)) {
- doc.addField(field + "_mlt", value);
- }
-
- doc.addField(field, value);
- if (authority != null) {
- doc.addField(field + "_authority", authority);
- }
- if (toProjectionFields.contains(field) || toProjectionFields
- .contains(unqualifiedField + "." + Item.ANY)) {
- StringBuffer variantsToStore = new StringBuffer();
- if (variants != null) {
- for (String var : variants) {
- variantsToStore.append(VARIANTS_STORE_SEPARATOR);
- variantsToStore.append(var);
- }
- }
- doc.addField(
- field + "_stored",
- value + STORE_SEPARATOR + preferedLabel
- + STORE_SEPARATOR
- + (variantsToStore.length() > VARIANTS_STORE_SEPARATOR
- .length() ? variantsToStore
- .substring(VARIANTS_STORE_SEPARATOR
- .length()) : "null")
- + STORE_SEPARATOR + authority
- + STORE_SEPARATOR + meta.getLanguage());
- }
-
- if (meta.getLanguage() != null && !meta.getLanguage().trim().equals("")) {
- String langField = field + "." + meta.getLanguage();
- doc.addField(langField, value);
- }
- }
-
- } catch (Exception e) {
- log.error(e.getMessage(), e);
- }
-
-
- log.debug(" Added Metadata");
-
- try {
-
- List values = itemService.getMetadataByMetadataString(item, "dc.relation.ispartof");
-
- if (values != null && values.size() > 0 && values.get(0) != null && values.get(0).getValue() != null) {
- // group on parent
- String handlePrefix = handleService.getCanonicalPrefix();
-
- doc.addField("publication_grp", values.get(0).getValue().replaceFirst(handlePrefix, ""));
-
- } else {
- // group on self
- doc.addField("publication_grp", item.getHandle());
- }
-
- } catch (Exception e) {
- log.error(e.getMessage(), e);
- }
-
-
- log.debug(" Added Grouping");
-
- //Do any additional indexing, depends on the plugins
- List solrServiceIndexPlugins = DSpaceServicesFactory.getInstance().getServiceManager()
- .getServicesByType(
- SolrServiceIndexPlugin.class);
- for (SolrServiceIndexPlugin solrServiceIndexPlugin : solrServiceIndexPlugins) {
- solrServiceIndexPlugin.additionalIndex(context, item, doc);
- }
- }
-
- private void deleteInProgressSubmissionByItemID(String uniqueID) throws SolrServerException, IOException {
- String query = "inprogress.item:\"" + uniqueID + "\"";
- log.debug("Try to delete all in progress submission [DELETEBYQUERY]:" + query);
- getSolr().deleteByQuery(query);
- }
-
- private void addFacetIndex(SolrInputDocument document, String field, String authority, String fvalue) {
- addFacetIndex(document, field, fvalue, authority, fvalue);
- }
-
- private void addFacetIndex(SolrInputDocument document, String field, String sortValue, String authority,
- String fvalue) {
- // the separator for the filter can be eventually configured
- String separator = DSpaceServicesFactory.getInstance().getConfigurationService()
- .getProperty("discovery.solr.facets.split.char");
- if (separator == null) {
- separator = FILTER_SEPARATOR;
- }
- String acvalue = sortValue + separator + fvalue + SolrServiceImpl.AUTHORITY_SEPARATOR + authority;
- document.addField(field + "_filter", acvalue);
- // build the solr field used for the keyword search
- document.addField(field + "_keyword", fvalue);
- // build the solr fields used for the autocomplete
- document.addField(field + "_ac", fvalue.toLowerCase() + separator + fvalue);
- if (StringUtils.isNotBlank(authority)) {
- document.addField(field + "_acid", fvalue.toLowerCase() + separator + fvalue
- + SolrServiceImpl.AUTHORITY_SEPARATOR + authority);
- document.addField(field + "_authority", authority);
- }
- }
-
- private void indexInProgressSubmissionItem(Context context, Item item)
- throws SQLException, IOException, SolrServerException, WorkflowConfigurationException {
- XmlWorkflowItem workflowItem = workflowItemService.findByItem(context, item);
- if (workflowItem == null) {
- WorkspaceItem workspaceItem = workspaceItemService.findByItem(context, item);
- if (workspaceItem == null) {
- // mmm... it could be a template item, skip it
- return;
- }
- // workspaceitem
- List locations = getCollectionLocations(context, workspaceItem.getCollection());
- SolrInputDocument doc = new SolrInputDocument();
-
- doc.addField("lastModified", item.getLastModified());
- EPerson submitter = workspaceItem.getSubmitter();
- if (submitter != null) {
- addFacetIndex(doc, "submitter", submitter.getID().toString(),
- submitter.getFullName());
- }
-
- List discoveryConfigurations = SearchUtils
- .getAllDiscoveryConfigurations(workspaceItem);
- addDiscoveryFields(doc, context, item, discoveryConfigurations);
- addBasicInfoToDocument(doc, Constants.WORKSPACEITEM, workspaceItem.getID(), null, locations);
-
- String acvalue = DSpaceServicesFactory.getInstance().getConfigurationService()
- .getProperty("discovery.facet.namedtype.workspace");
- if (StringUtils.isBlank(acvalue)) {
- acvalue = workspaceItem.getTypeText();
- }
- addNamedResourceTypeIndex(doc, acvalue);
- doc.addField("inprogress.item", item.getUniqueIndexID());
-
- getSolr().add(doc);
- } else {
- // so it is an item in the workflow
- // get the location string (for searching by collection & community)
- List locations = getCollectionLocations(context, workflowItem.getCollection());
- SolrInputDocument doc = new SolrInputDocument();
-
- doc.addField("inprogress.item", item.getUniqueIndexID());
- doc.addField("lastModified", item.getLastModified());
- EPerson submitter = workflowItem.getSubmitter();
- if (submitter != null) {
- addFacetIndex(doc, "submitter", submitter.getID().toString(),
- submitter.getFullName());
- }
-
- List discoveryConfigurations = SearchUtils
- .getAllDiscoveryConfigurations(workflowItem);
- addDiscoveryFields(doc, context, item, discoveryConfigurations);
-
- List claimedTasks = claimedTaskService.find(context, workflowItem);
- List pools = poolTaskService.find(context, workflowItem);
-
- List docs = new ArrayList();
-
- if (claimedTasks != null) {
- for (ClaimedTask claimedTask : claimedTasks) {
- SolrInputDocument claimDoc = doc.deepCopy();
- addBasicInfoToDocument(claimDoc, Constants.CLAIMEDTASK, claimedTask.getID(), null, locations);
- addFacetIndex(claimDoc, "action", claimedTask.getActionID(), claimedTask.getActionID());
- addFacetIndex(claimDoc, "step", claimedTask.getStepID(), claimedTask.getStepID());
-
- claimDoc.addField("taskfor", "e" + claimedTask.getOwner().getID().toString());
-
- String acvalue = DSpaceServicesFactory.getInstance().getConfigurationService()
- .getProperty("discovery.facet.namedtype.workflow.claimed");
- if (StringUtils.isBlank(acvalue)) {
- acvalue = claimedTask.getTypeText();
- }
- addNamedResourceTypeIndex(claimDoc, acvalue);
-
- docs.add(claimDoc);
- }
- }
-
- if (pools != null) {
- for (PoolTask poolTask : pools) {
- SolrInputDocument claimDoc = doc.deepCopy();
- addBasicInfoToDocument(claimDoc, Constants.POOLTASK, poolTask.getID(), null, locations);
- addFacetIndex(claimDoc, "action", poolTask.getActionID(), poolTask.getActionID());
- addFacetIndex(claimDoc, "step", poolTask.getStepID(), poolTask.getStepID());
-
- if (poolTask.getEperson() != null) {
- claimDoc.addField("taskfor", "e" + poolTask.getEperson().getID().toString());
- }
- if (poolTask.getGroup() != null) {
- claimDoc.addField("taskfor", "g" + poolTask.getGroup().getID().toString());
- }
-
- String acvalue = DSpaceServicesFactory.getInstance().getConfigurationService()
- .getProperty("discovery.facet.namedtype.workflow.pooled");
- if (StringUtils.isBlank(acvalue)) {
- acvalue = poolTask.getTypeText();
- }
- addNamedResourceTypeIndex(claimDoc, acvalue);
- docs.add(claimDoc);
- }
- }
-
- String acvalue = DSpaceServicesFactory.getInstance().getConfigurationService()
- .getProperty("discovery.facet.namedtype.workflow.item");
- if (StringUtils.isBlank(acvalue)) {
- acvalue = workflowItem.getTypeText();
- }
- addNamedResourceTypeIndex(doc, acvalue);
-
- addBasicInfoToDocument(doc, Constants.WORKFLOWITEM, workflowItem.getID(), null, locations);
- docs.add(doc);
-
- if (docs.size() > 0) {
- getSolr().add(docs);
- } else {
- // no tasks found?!?
- log.error("No tasks found for workflowitem " + workflowItem.getID());
- }
- }
- }
-
- /**
- * Create Lucene document with all the shared fields initialized.
- *
- * @param type Type of DSpace Object
- * @param id internal identifier
- * @param handle handle string
- * @param locations list of collection/community internal identifiers
- * @return initialized Lucene document
- */
- protected SolrInputDocument buildDocument(int type, UUID id, String handle,
- List locations) {
- SolrInputDocument doc = new SolrInputDocument();
- addBasicInfoToDocument(doc, type, id, handle, locations);
- return doc;
- }
-
- private void addBasicInfoToDocument(SolrInputDocument doc, int type, Serializable id, String handle,
- List locations) {
- // want to be able to check when last updated
- // (not tokenized, but it is indexed)
- doc.addField(LAST_INDEXED_FIELD,
- SolrUtils.getDateFormatter().format(new Date()));
-
- // New fields to weaken the dependence on handles, and allow for faster
- // list display
- doc.addField(RESOURCE_UNIQUE_ID, type + "-" + id);
- doc.addField(RESOURCE_TYPE_FIELD, Integer.toString(type));
- doc.addField(RESOURCE_ID_FIELD, id.toString());
-
- // want to be able to search for handle, so use keyword
- // (not tokenized, but it is indexed)
- if (handle != null) {
- // want to be able to search for handle, so use keyword
- // (not tokenized, but it is indexed)
- doc.addField(HANDLE_FIELD, handle);
- }
-
- if (locations != null) {
- for (String location : locations) {
- doc.addField("location", location);
- if (location.startsWith("m")) {
- doc.addField("location.comm", location.substring(1));
- } else {
- doc.addField("location.coll", location.substring(1));
- }
- }
- }
- }
-
/**
* Helper function to retrieve a date using a best guess of the potential
* date encodings on a field
@@ -1855,46 +696,36 @@ public class SolrServiceImpl implements SearchService, IndexingService {
}
//========== SearchService implementation
- @Override
- public DiscoverResult search(Context context, DiscoverQuery query) throws SearchServiceException {
- return search(context, query, false);
- }
@Override
- public DiscoverResult search(Context context, IndexableObject dso,
- DiscoverQuery query)
+ public DiscoverResult search(Context context, IndexableObject dso, DiscoverQuery discoveryQuery)
throws SearchServiceException {
- return search(context, dso, query, false);
- }
-
- @Override
- public DiscoverResult search(Context context, IndexableObject dso, DiscoverQuery discoveryQuery,
- boolean includeUnDiscoverable) throws SearchServiceException {
if (dso != null) {
- if (dso instanceof Community) {
+ if (dso instanceof IndexableCommunity) {
discoveryQuery.addFilterQueries("location:m" + dso.getID());
- } else if (dso instanceof Collection) {
+ } else if (dso instanceof IndexableCollection) {
discoveryQuery.addFilterQueries("location:l" + dso.getID());
- } else if (dso instanceof Item) {
- discoveryQuery.addFilterQueries(HANDLE_FIELD + ":" + ((Item) dso).getHandle());
+ } else if (dso instanceof IndexableItem) {
+ discoveryQuery.addFilterQueries(SearchUtils.RESOURCE_UNIQUE_ID + ":" + dso.
+ getUniqueIndexID());
}
}
- return search(context, discoveryQuery, includeUnDiscoverable);
+ return search(context, discoveryQuery);
}
@Override
- public DiscoverResult search(Context context, DiscoverQuery discoveryQuery, boolean includeUnDiscoverable)
+ public DiscoverResult search(Context context, DiscoverQuery discoveryQuery )
throws SearchServiceException {
try {
- if (getSolr() == null) {
+ if (solrSearchCore.getSolr() == null) {
return new DiscoverResult();
}
- SolrQuery solrQuery = resolveToSolrQuery(context, discoveryQuery, includeUnDiscoverable);
+ SolrQuery solrQuery = resolveToSolrQuery(context, discoveryQuery);
- QueryResponse queryResponse = getSolr().query(solrQuery, SolrRequest.METHOD.POST);
+ QueryResponse queryResponse = solrSearchCore.getSolr().query(solrQuery, SolrRequest.METHOD.POST);
return retrieveResult(context, discoveryQuery, queryResponse);
} catch (Exception e) {
@@ -1902,8 +733,8 @@ public class SolrServiceImpl implements SearchService, IndexingService {
}
}
- protected SolrQuery resolveToSolrQuery(Context context, DiscoverQuery discoveryQuery,
- boolean includeUnDiscoverable) throws SearchServiceException {
+ protected SolrQuery resolveToSolrQuery(Context context, DiscoverQuery discoveryQuery)
+ throws SearchServiceException {
SolrQuery solrQuery = new SolrQuery();
String query = "*:*";
@@ -1919,9 +750,8 @@ public class SolrServiceImpl implements SearchService, IndexingService {
solrQuery.addField(fieldName);
}
// Also ensure a few key obj identifier fields are returned with every query
- solrQuery.addField(HANDLE_FIELD);
- solrQuery.addField(RESOURCE_TYPE_FIELD);
- solrQuery.addField(RESOURCE_ID_FIELD);
+ solrQuery.addField(SearchUtils.RESOURCE_TYPE_FIELD);
+ solrQuery.addField(SearchUtils.RESOURCE_ID_FIELD);
if (discoveryQuery.isSpellCheck()) {
solrQuery.setParam(SpellingParams.SPELLCHECK_Q, query);
@@ -1929,17 +759,12 @@ public class SolrServiceImpl implements SearchService, IndexingService {
solrQuery.setParam("spellcheck", Boolean.TRUE);
}
- if (!includeUnDiscoverable) {
- solrQuery.addFilterQuery("NOT(withdrawn:true)");
- solrQuery.addFilterQuery("NOT(discoverable:false)");
- }
-
for (int i = 0; i < discoveryQuery.getFilterQueries().size(); i++) {
String filterQuery = discoveryQuery.getFilterQueries().get(i);
solrQuery.addFilterQuery(filterQuery);
}
- if (discoveryQuery.getDSpaceObjectFilter() != -1) {
- solrQuery.addFilterQuery(RESOURCE_TYPE_FIELD + ":" + discoveryQuery.getDSpaceObjectFilter());
+ if (discoveryQuery.getDSpaceObjectFilter() != null) {
+ solrQuery.addFilterQuery(SearchUtils.RESOURCE_TYPE_FIELD + ":" + discoveryQuery.getDSpaceObjectFilter());
}
for (int i = 0; i < discoveryQuery.getFieldPresentQueries().size(); i++) {
@@ -2082,13 +907,14 @@ public class SolrServiceImpl implements SearchService, IndexingService {
List searchFields = query.getSearchFields();
for (SolrDocument doc : solrQueryResponse.getResults()) {
- IndexableObject dso = findIndexableObject(context, doc);
+ IndexableObject indexableObject = findIndexableObject(context, doc);
- if (dso != null) {
- result.addIndexableObject(dso);
+ if (indexableObject != null) {
+ result.addIndexableObject(indexableObject);
} else {
- log.error(LogManager.getHeader(context, "Error while retrieving DSpace object from discovery index",
- "Handle: " + doc.getFirstValue(HANDLE_FIELD)));
+ log.error(LogManager.getHeader(context,
+ "Error while retrieving DSpace object from discovery index",
+ "Unique identifier: " + doc.getFirstValue(SearchUtils.RESOURCE_UNIQUE_ID)));
continue;
}
@@ -2101,11 +927,11 @@ public class SolrServiceImpl implements SearchService, IndexingService {
}
resultDoc.addSearchField(field, valuesAsString.toArray(new String[valuesAsString.size()]));
}
- result.addSearchDocument(dso, resultDoc);
+ result.addSearchDocument(indexableObject, resultDoc);
if (solrQueryResponse.getHighlighting() != null) {
Map> highlightedFields = solrQueryResponse.getHighlighting().get(
- dso.getType() + "-" + dso.getID());
+ indexableObject.getUniqueIndexID());
if (MapUtils.isNotEmpty(highlightedFields)) {
//We need to remove all the "_hl" appendix strings from our keys
Map> resultMap = new HashMap>();
@@ -2120,8 +946,8 @@ public class SolrServiceImpl implements SearchService, IndexingService {
resultMap.put(key.substring(0, key.lastIndexOf("_hl")), highlightedFields.get(key));
}
- result.addHighlightedResult(dso,
- new DiscoverResult.IndexableObjectHighlightResult(dso, resultMap));
+ result.addHighlightedResult(indexableObject,
+ new DiscoverResult.IndexableObjectHighlightResult(indexableObject, resultMap));
}
}
}
@@ -2220,35 +1046,16 @@ public class SolrServiceImpl implements SearchService, IndexingService {
* An exception that provides information on a database access error or other errors.
*/
protected IndexableObject findIndexableObject(Context context, SolrDocument doc) throws SQLException {
- Integer type = (Integer) doc.getFirstValue(RESOURCE_TYPE_FIELD);
- Object id = doc.getFirstValue(RESOURCE_ID_FIELD);
- String handle = (String) doc.getFirstValue(HANDLE_FIELD);
- IndexableObject o = null;
- Serializable uid = null;
- if (type != null && id != null) {
- switch (type) {
- case Constants.WORKSPACEITEM:
- case Constants.WORKFLOWITEM:
- case Constants.POOLTASK:
- case Constants.CLAIMEDTASK:
- uid = Integer.parseInt((String) id);
- break;
- default:
- uid = UUID.fromString((String) id);
- break;
- }
- }
+ String type = (String) doc.getFirstValue(SearchUtils.RESOURCE_TYPE_FIELD);
+ String id = (String) doc.getFirstValue(SearchUtils.RESOURCE_ID_FIELD);
+ final IndexFactory indexableObjectService = indexObjectServiceFactory.
+ getIndexFactoryByType(type);
+ Optional indexableObject = indexableObjectService.findIndexableObject(context, id);
- if (uid != null) {
- o = (IndexableObject) contentServiceFactory.getIndexableObjectService(type).findIndexableObject(context,
- uid);
+ if (!indexableObject.isPresent()) {
+ log.warn("Not able to retrieve object RESOURCE_ID:" + id + " - RESOURCE_TYPE_ID:" + type);
}
-
- if (o == null) {
- log.warn("Not able to retrieve object RESOURCE_ID:" + id + " - RESOURCE_TYPE_ID:" + type + " - HANDLE:" +
- handle);
- }
- return o;
+ return indexableObject.orElse(null);
}
public List search(Context context, String query, int offset, int max,
@@ -2261,14 +1068,14 @@ public class SolrServiceImpl implements SearchService, IndexingService {
int offset, int max, String... filterquery) {
try {
- if (getSolr() == null) {
+ if (solrSearchCore.getSolr() == null) {
return Collections.emptyList();
}
SolrQuery solrQuery = new SolrQuery();
solrQuery.setQuery(query);
//Only return obj identifier fields in result doc
- solrQuery.setFields(RESOURCE_ID_FIELD, RESOURCE_TYPE_FIELD);
+ solrQuery.setFields(SearchUtils.RESOURCE_ID_FIELD, SearchUtils.RESOURCE_TYPE_FIELD);
solrQuery.setStart(offset);
solrQuery.setRows(max);
if (orderfield != null) {
@@ -2277,18 +1084,14 @@ public class SolrServiceImpl implements SearchService, IndexingService {
if (filterquery != null) {
solrQuery.addFilterQuery(filterquery);
}
- QueryResponse rsp = getSolr().query(solrQuery, SolrRequest.METHOD.POST);
+ QueryResponse rsp = solrSearchCore.getSolr().query(solrQuery, SolrRequest.METHOD.POST);
SolrDocumentList docs = rsp.getResults();
Iterator iter = docs.iterator();
List result = new ArrayList();
while (iter.hasNext()) {
SolrDocument doc = (SolrDocument) iter.next();
-
- IndexableObject o = (IndexableObject)contentServiceFactory
- .getIndexableObjectService((Integer) doc.getFirstValue(RESOURCE_TYPE_FIELD))
- .findIndexableObject(context, UUID.fromString((String) doc.getFirstValue(RESOURCE_ID_FIELD)));
-
+ IndexableObject o = findIndexableObject(context, doc);
if (o != null) {
result.add(o);
}
@@ -2298,7 +1101,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
// Any acception that we get ignore it.
// We do NOT want any crashed to shown by the user
log.error(LogManager.getHeader(context, "Error while quering solr", "Query: " + query), e);
- return new ArrayList(0);
+ return new ArrayList<>(0);
}
}
@@ -2357,13 +1160,13 @@ public class SolrServiceImpl implements SearchService, IndexingService {
@Override
public List
- getRelatedItems(Context context, Item item, DiscoveryMoreLikeThisConfiguration mltConfig) {
- List
- results = new ArrayList
- ();
+ List
- results = new ArrayList<>();
try {
SolrQuery solrQuery = new SolrQuery();
//Set the query to handle since this is unique
- solrQuery.setQuery(HANDLE_FIELD + ": " + item.getHandle());
+ solrQuery.setQuery(SearchUtils.RESOURCE_UNIQUE_ID + ": " + new IndexableItem(item).getUniqueIndexID());
//Only return obj identifier fields in result doc
- solrQuery.setFields(HANDLE_FIELD, RESOURCE_TYPE_FIELD, RESOURCE_ID_FIELD);
+ solrQuery.setFields(SearchUtils.RESOURCE_TYPE_FIELD, SearchUtils.RESOURCE_ID_FIELD);
//Add the more like this parameters !
solrQuery.setParam(MoreLikeThisParams.MLT, true);
//Add a comma separated list of the similar fields
@@ -2382,35 +1185,33 @@ public class SolrServiceImpl implements SearchService, IndexingService {
solrQuery.setParam(MoreLikeThisParams.DOC_COUNT, String.valueOf(mltConfig.getMax()));
solrQuery.setParam(MoreLikeThisParams.MIN_WORD_LEN, String.valueOf(mltConfig.getMinWordLength()));
- if (getSolr() == null) {
+ if (solrSearchCore.getSolr() == null) {
return Collections.emptyList();
}
- QueryResponse rsp = getSolr().query(solrQuery, SolrRequest.METHOD.POST);
+ QueryResponse rsp = solrSearchCore.getSolr().query(solrQuery, SolrRequest.METHOD.POST);
NamedList mltResults = (NamedList) rsp.getResponse().get("moreLikeThis");
if (mltResults != null && mltResults.get(item.getType() + "-" + item.getID()) != null) {
SolrDocumentList relatedDocs = (SolrDocumentList) mltResults.get(item.getType() + "-" + item.getID());
for (Object relatedDoc : relatedDocs) {
SolrDocument relatedDocument = (SolrDocument) relatedDoc;
IndexableObject relatedItem = findIndexableObject(context, relatedDocument);
- if (relatedItem.getType() == Constants.ITEM) {
- results.add((Item) relatedItem);
+ if (relatedItem instanceof IndexableItem) {
+ results.add(((IndexableItem) relatedItem).getIndexedObject());
}
}
}
-
-
} catch (Exception e) {
log.error(
- LogManager.getHeader(context, "Error while retrieving related items", "Handle: " + item.getHandle()),
- e);
+ LogManager.getHeader(context, "Error while retrieving related items", "Handle: "
+ + item.getHandle()), e);
}
return results;
}
@Override
public String toSortFieldIndex(String metadataField, String type) {
- if (StringUtils.equalsIgnoreCase(SCORE, metadataField)) {
- return SCORE;
+ if (StringUtils.equalsIgnoreCase(DiscoverySortConfiguration.SCORE, metadataField)) {
+ return DiscoverySortConfiguration.SCORE;
} else if (StringUtils.equals(type, DiscoveryConfigurationParameters.TYPE_DATE)) {
return metadataField + "_dt";
} else {
@@ -2469,7 +1270,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
String separator = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("discovery.solr.facets.split.char");
if (separator == null) {
- separator = FILTER_SEPARATOR;
+ separator = SearchUtils.FILTER_SEPARATOR;
}
//Escape any regex chars
separator = java.util.regex.Pattern.quote(separator);
@@ -2477,7 +1278,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
StringBuffer valueBuffer = new StringBuffer();
int start = fqParts.length / 2;
for (int i = start; i < fqParts.length; i++) {
- String[] split = fqParts[i].split(AUTHORITY_SEPARATOR, 2);
+ String[] split = fqParts[i].split(SearchUtils.AUTHORITY_SEPARATOR, 2);
valueBuffer.append(split[0]);
}
value = valueBuffer.toString();
@@ -2501,7 +1302,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
String separator = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("discovery.solr.facets.split.char");
if (separator == null) {
- separator = FILTER_SEPARATOR;
+ separator = SearchUtils.FILTER_SEPARATOR;
}
//Escape any regex chars
separator = java.util.regex.Pattern.quote(separator);
@@ -2509,7 +1310,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
StringBuffer authorityBuffer = new StringBuffer();
int start = fqParts.length / 2;
for (int i = start; i < fqParts.length; i++) {
- String[] split = fqParts[i].split(AUTHORITY_SEPARATOR, 2);
+ String[] split = fqParts[i].split(SearchUtils.AUTHORITY_SEPARATOR, 2);
if (split.length == 2) {
authorityBuffer.append(split[1]);
}
@@ -2533,7 +1334,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
String separator = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("discovery.solr.facets.split.char");
if (separator == null) {
- separator = FILTER_SEPARATOR;
+ separator = SearchUtils.FILTER_SEPARATOR;
}
//Escape any regex chars
separator = java.util.regex.Pattern.quote(separator);
@@ -2563,8 +1364,8 @@ public class SolrServiceImpl implements SearchService, IndexingService {
@Override
public void commit() throws SearchServiceException {
try {
- if (getSolr() != null) {
- getSolr().commit();
+ if (solrSearchCore.getSolr() != null) {
+ solrSearchCore.getSolr().commit();
}
} catch (Exception e) {
throw new SearchServiceException(e.getMessage(), e);
@@ -2613,37 +1414,4 @@ public class SolrServiceImpl implements SearchService, IndexingService {
}
return null;
}
-
- /**
- * Add the necessary fields to the SOLR document to support a Discover Facet on resourcetypename (archived item,
- * workspace item, workflow item, etc)
- *
- * @param document
- * the solr document
- * @param filterValue
- * the filter value (i.e. \n|||\n###
- */
- private void addNamedResourceTypeIndex(SolrInputDocument document, String filterValue) {
-
- // the separator for the filter can be eventually configured
- String separator = DSpaceServicesFactory.getInstance().getConfigurationService()
- .getProperty("discovery.solr.facets.split.char");
- if (separator == null) {
- separator = FILTER_SEPARATOR;
- }
-
- // split the authority part from the sort/display
- String[] avalues = filterValue.split(SolrServiceImpl.AUTHORITY_SEPARATOR);
-
- String sortValue = avalues[0];
- String authorityValue = avalues.length == 2 ? avalues[1] : filterValue;
-
- // get the display value
- int idxSeparator = sortValue.indexOf(separator);
- String displayValue = idxSeparator != -1 ? sortValue.substring(idxSeparator + separator.length())
- : sortValue;
-
- addFacetIndex(document, NAMED_RESOURCE_TYPE, sortValue, authorityValue, displayValue);
- }
-
}
diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceMetadataBrowseIndexingPlugin.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceMetadataBrowseIndexingPlugin.java
index 6d1035c4a0..187c6b0600 100644
--- a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceMetadataBrowseIndexingPlugin.java
+++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceMetadataBrowseIndexingPlugin.java
@@ -23,6 +23,7 @@ import org.dspace.content.authority.service.ChoiceAuthorityService;
import org.dspace.content.authority.service.MetadataAuthorityService;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
+import org.dspace.discovery.indexobject.IndexableItem;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.sort.OrderFormat;
import org.dspace.sort.SortException;
@@ -56,12 +57,12 @@ public class SolrServiceMetadataBrowseIndexingPlugin implements SolrServiceIndex
protected ChoiceAuthorityService choiceAuthorityService;
@Override
- public void additionalIndex(Context context, IndexableObject dso, SolrInputDocument document) {
+ public void additionalIndex(Context context, IndexableObject indexableObject, SolrInputDocument document) {
// Only works for Items
- if (!(dso instanceof Item)) {
+ if (!(indexableObject instanceof IndexableItem)) {
return;
}
- Item item = (Item) dso;
+ Item item = ((IndexableItem) indexableObject).getIndexedObject();
// Get the currently configured browse indexes
BrowseIndex[] bis;
@@ -206,9 +207,9 @@ public class SolrServiceMetadataBrowseIndexingPlugin implements SolrServiceIndex
bi.getDataType());
distFValues
.add(nLabel
- + SolrServiceImpl.FILTER_SEPARATOR
+ + SearchUtils.FILTER_SEPARATOR
+ preferedLabel
- + SolrServiceImpl.AUTHORITY_SEPARATOR
+ + SearchUtils.AUTHORITY_SEPARATOR
+ values.get(x).getAuthority());
distValuesForAC.add(preferedLabel);
}
@@ -222,9 +223,9 @@ public class SolrServiceMetadataBrowseIndexingPlugin implements SolrServiceIndex
bi.getDataType());
distFValues
.add(nVal
- + SolrServiceImpl.FILTER_SEPARATOR
+ + SearchUtils.FILTER_SEPARATOR
+ var
- + SolrServiceImpl.AUTHORITY_SEPARATOR
+ + SearchUtils.AUTHORITY_SEPARATOR
+ values.get(x).getAuthority());
distValuesForAC.add(var);
}
@@ -241,7 +242,7 @@ public class SolrServiceMetadataBrowseIndexingPlugin implements SolrServiceIndex
bi.getDataType());
distFValues
.add(nVal
- + SolrServiceImpl.FILTER_SEPARATOR
+ + SearchUtils.FILTER_SEPARATOR
+ values.get(x).getValue());
distFVal.add(values.get(x).getValue());
distValuesForAC.add(values.get(x).getValue());
diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServicePrivateItemPlugin.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServicePrivateItemPlugin.java
new file mode 100644
index 0000000000..47dea08fc8
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServicePrivateItemPlugin.java
@@ -0,0 +1,49 @@
+/**
+ * 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 static org.apache.logging.log4j.LogManager.getLogger;
+
+import java.sql.SQLException;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.solr.client.solrj.SolrQuery;
+import org.dspace.authorize.service.AuthorizeService;
+import org.dspace.core.Context;
+import org.dspace.core.LogManager;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * This plugin prevents discovery of private items by non-administrators.
+ */
+public class SolrServicePrivateItemPlugin implements SolrServiceSearchPlugin {
+
+ private static final Logger log = getLogger(SolrServicePrivateItemPlugin.class.getSimpleName());
+
+ @Autowired(required = true)
+ protected AuthorizeService authorizeService;
+
+
+ @Autowired(required = true)
+ protected SearchService searchService;
+
+ @Override
+ public void additionalSearchParameters(Context context, DiscoverQuery discoveryQuery, SolrQuery solrQuery) {
+ try {
+ // Prevents access if user has no administrative rights on the community or collection.
+ // NOTE: the resource restriction plugin adds location filters for community and collection admins.
+ if ( !authorizeService.isAdmin(context) && !authorizeService.isCommunityAdmin(context)
+ && !authorizeService.isCollectionAdmin(context)) {
+ solrQuery.addFilterQuery("NOT(discoverable:false)");
+ }
+ } catch (SQLException ex) {
+ log.error(LogManager.getHeader(context, "Error looking up authorization rights of current user",
+ ""), ex);
+ }
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceResourceRestrictionPlugin.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceResourceRestrictionPlugin.java
index 853076fdc2..38e85dbf93 100644
--- a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceResourceRestrictionPlugin.java
+++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceResourceRestrictionPlugin.java
@@ -24,6 +24,7 @@ import org.dspace.content.service.CommunityService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
+import org.dspace.discovery.indexobject.IndexableDSpaceObject;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.eperson.service.GroupService;
@@ -56,8 +57,8 @@ public class SolrServiceResourceRestrictionPlugin implements SolrServiceIndexPlu
@Override
public void additionalIndex(Context context, IndexableObject idxObj, SolrInputDocument document) {
- if (idxObj instanceof DSpaceObject) {
- DSpaceObject dso = (DSpaceObject) idxObj;
+ if (idxObj instanceof IndexableDSpaceObject) {
+ DSpaceObject dso = ((IndexableDSpaceObject) idxObj).getIndexedObject();
try {
List policies = authorizeService.getPoliciesActionFilter(context, dso, Constants.READ);
for (ResourcePolicy resourcePolicy : policies) {
diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceSpellIndexingPlugin.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceSpellIndexingPlugin.java
index 99c3fcf6ef..47a96d0352 100644
--- a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceSpellIndexingPlugin.java
+++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceSpellIndexingPlugin.java
@@ -14,6 +14,7 @@ import org.dspace.content.Item;
import org.dspace.content.MetadataValue;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
+import org.dspace.discovery.indexobject.IndexableItem;
import org.springframework.beans.factory.annotation.Autowired;
/**
@@ -29,9 +30,9 @@ public class SolrServiceSpellIndexingPlugin implements SolrServiceIndexPlugin {
protected ItemService itemService;
@Override
- public void additionalIndex(Context context, IndexableObject dso, SolrInputDocument document) {
- if (dso instanceof Item) {
- Item item = (Item) dso;
+ public void additionalIndex(Context context, IndexableObject indexableObject, SolrInputDocument document) {
+ if (indexableObject instanceof IndexableItem) {
+ Item item = ((IndexableItem) indexableObject).getIndexedObject();
List dcValues = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY);
List toIgnoreMetadataFields = SearchUtils.getIgnoredMetadataFields(item.getType());
for (MetadataValue dcValue : dcValues) {
diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationService.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationService.java
index 53433f879f..2c12f923ae 100644
--- a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationService.java
+++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationService.java
@@ -13,8 +13,8 @@ import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
-import org.dspace.content.DSpaceObject;
import org.dspace.discovery.IndexableObject;
+import org.dspace.discovery.indexobject.IndexableDSpaceObject;
import org.dspace.services.factory.DSpaceServicesFactory;
/**
@@ -45,8 +45,8 @@ public class DiscoveryConfigurationService {
String name;
if (dso == null) {
name = "site";
- } else if (dso instanceof DSpaceObject) {
- name = ((DSpaceObject) dso).getHandle();
+ } else if (dso instanceof IndexableDSpaceObject) {
+ name = ((IndexableDSpaceObject) dso).getIndexedObject().getHandle();
} else {
name = dso.getUniqueIndexID();
}
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/ClaimedTaskIndexFactoryImpl.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/ClaimedTaskIndexFactoryImpl.java
new file mode 100644
index 0000000000..411aa6a0fb
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/ClaimedTaskIndexFactoryImpl.java
@@ -0,0 +1,99 @@
+/**
+ * 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.indexobject;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.solr.common.SolrInputDocument;
+import org.dspace.core.Context;
+import org.dspace.discovery.indexobject.factory.ClaimedTaskIndexFactory;
+import org.dspace.discovery.indexobject.factory.WorkflowItemIndexFactory;
+import org.dspace.services.factory.DSpaceServicesFactory;
+import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
+import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * Factory implementation for indexing/retrieving claimed tasks in the search core
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public class ClaimedTaskIndexFactoryImpl extends IndexFactoryImpl
+ implements ClaimedTaskIndexFactory {
+
+ @Autowired
+ protected ClaimedTaskService claimedTaskService;
+ @Autowired
+ WorkflowItemIndexFactory indexableWorkflowItemService;
+
+ @Override
+ public Iterator findAll(Context context) throws SQLException {
+ final Iterator claimedTasks = claimedTaskService.findAll(context).iterator();
+ return new Iterator() {
+ @Override
+ public boolean hasNext() {
+ return claimedTasks.hasNext();
+ }
+
+ @Override
+ public IndexableClaimedTask next() {
+ return new IndexableClaimedTask(claimedTasks.next());
+ }
+ };
+ }
+
+ @Override
+ public String getType() {
+ return IndexableClaimedTask.TYPE;
+ }
+
+ @Override
+ public SolrInputDocument buildDocument(Context context, IndexableClaimedTask indexableObject)
+ throws SQLException, IOException {
+ // Add the ID's, types and call the SolrServiceIndexPlugins
+ final SolrInputDocument doc = super.buildDocument(context, indexableObject);
+ final ClaimedTask claimedTask = indexableObject.getIndexedObject();
+ // Add submitter, locations and modification time
+ indexableWorkflowItemService.storeInprogressItemFields(context, doc, claimedTask.getWorkflowItem());
+
+ addFacetIndex(doc, "action", claimedTask.getActionID(), claimedTask.getActionID());
+ addFacetIndex(doc, "step", claimedTask.getStepID(), claimedTask.getStepID());
+
+ doc.addField("taskfor", "e" + claimedTask.getOwner().getID().toString());
+
+ String acvalue = DSpaceServicesFactory.getInstance().getConfigurationService()
+ .getProperty("discovery.facet.namedtype.workflow.claimed");
+ if (StringUtils.isBlank(acvalue)) {
+ acvalue = indexableObject.getTypeText();
+ }
+ addNamedResourceTypeIndex(doc, acvalue);
+
+ return doc;
+ }
+
+ @Override
+ public boolean supports(Object object) {
+ return object instanceof ClaimedTask;
+ }
+
+ @Override
+ public List getIndexableObjects(Context context, ClaimedTask object) {
+ return Arrays.asList(new IndexableClaimedTask(object));
+ }
+
+ @Override
+ public Optional findIndexableObject(Context context, String id) throws SQLException {
+ final ClaimedTask claimedTask = claimedTaskService.find(context, Integer.parseInt(id));
+ return claimedTask == null ? Optional.empty() : Optional.of(new IndexableClaimedTask(claimedTask));
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/CollectionIndexFactoryImpl.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/CollectionIndexFactoryImpl.java
new file mode 100644
index 0000000000..4a78dc8e82
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/CollectionIndexFactoryImpl.java
@@ -0,0 +1,158 @@
+/**
+ * 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.indexobject;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+import org.apache.solr.common.SolrInputDocument;
+import org.dspace.content.Collection;
+import org.dspace.content.Community;
+import org.dspace.content.factory.ContentServiceFactory;
+import org.dspace.content.service.CollectionService;
+import org.dspace.content.service.CommunityService;
+import org.dspace.core.Context;
+import org.dspace.discovery.SearchUtils;
+import org.dspace.discovery.configuration.DiscoveryConfiguration;
+import org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration;
+import org.dspace.discovery.configuration.DiscoveryHitHighlightingConfiguration;
+import org.dspace.discovery.indexobject.factory.CollectionIndexFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+
+/**
+ * Factory implementation for indexing/retrieving collections in the search core
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public class CollectionIndexFactoryImpl extends DSpaceObjectIndexFactoryImpl
+ implements CollectionIndexFactory {
+
+ @Autowired
+ protected CollectionService collectionService;
+
+ @Autowired
+ protected CommunityService communityService;
+
+ @Override
+ public Iterator findAll(Context context) throws SQLException {
+ Iterator collections = collectionService.findAll(context).iterator();
+
+ return new Iterator() {
+ @Override
+ public boolean hasNext() {
+ return collections.hasNext();
+ }
+
+ @Override
+ public IndexableCollection next() {
+ return new IndexableCollection(collections.next());
+ }
+ };
+ }
+
+ @Override
+ public String getType() {
+ return IndexableCollection.TYPE;
+ }
+
+ /**
+ * Build a solr document for a DSpace Collection.
+ *
+ * @param context The relevant DSpace Context.
+ * @param indexableCollection indexableCollection to be indexed
+ * @throws SQLException sql exception
+ * @throws IOException IO exception
+ */
+ @Override
+ public SolrInputDocument buildDocument(Context context, IndexableCollection indexableCollection)
+ throws IOException, SQLException {
+ // Create Lucene Document and add the ID's, types and call the SolrServiceIndexPlugins
+ SolrInputDocument doc = super.buildDocument(context, indexableCollection);
+
+ final Collection collection = indexableCollection.getIndexedObject();
+
+ // Retrieve configuration
+ DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(collection);
+ DiscoveryHitHighlightingConfiguration highlightingConfiguration = discoveryConfiguration
+ .getHitHighlightingConfiguration();
+ List highlightedMetadataFields = new ArrayList<>();
+ if (highlightingConfiguration != null) {
+ for (DiscoveryHitHighlightFieldConfiguration configuration : highlightingConfiguration
+ .getMetadataFields()) {
+ highlightedMetadataFields.add(configuration.getField());
+ }
+ }
+
+
+ // Add collection metadata
+ String description = collectionService.getMetadata(collection, "introductory_text");
+ String description_abstract = collectionService.getMetadata(collection, "short_description");
+ String description_table = collectionService.getMetadata(collection, "side_bar_text");
+ String provenance = collectionService.getMetadata(collection, "provenance_description");
+ String rights = collectionService.getMetadata(collection, "copyright_text");
+ String rights_license = collectionService.getMetadata(collection, "license");
+ String title = collectionService.getMetadata(collection, "name");
+
+ List toIgnoreMetadataFields = SearchUtils.getIgnoredMetadataFields(collection.getType());
+ addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description",
+ description);
+ addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description.abstract",
+ description_abstract);
+ addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields,
+ "dc.description.tableofcontents", description_table);
+ addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.provenance", provenance);
+ addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.rights", rights);
+ addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.rights.license",
+ rights_license);
+ addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.title", title);
+
+ return doc;
+ }
+
+ @Override
+ public boolean supports(Object object) {
+ return object instanceof Collection;
+ }
+
+ @Override
+ public List getIndexableObjects(Context context, Collection object) {
+ return Arrays.asList(new IndexableCollection(object));
+ }
+
+ @Override
+ public Optional findIndexableObject(Context context, String id) throws SQLException {
+ final Collection collection = (collectionService.find(context, UUID.fromString(id)));
+ return collection == null ? Optional.empty() : Optional.of(new IndexableCollection(collection));
+ }
+
+ @Override
+ public List getLocations(Context context, IndexableCollection indexableCollection) throws SQLException {
+ return getCollectionLocations(context, indexableCollection.getIndexedObject());
+ }
+
+ @Override
+ public List getCollectionLocations(Context context, Collection collection) throws SQLException {
+ List locations = new ArrayList<>();
+ // build list of community ids
+ List communities = ContentServiceFactory.getInstance().getCommunityService().
+ getAllParents(context, collection);
+
+ // now put those into strings
+ for (Community community : communities) {
+ locations.add("m" + community.getID());
+ }
+
+ return locations;
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/CommunityIndexFactoryImpl.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/CommunityIndexFactoryImpl.java
new file mode 100644
index 0000000000..ac33b4cf5a
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/CommunityIndexFactoryImpl.java
@@ -0,0 +1,131 @@
+/**
+ * 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.indexobject;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+import org.apache.solr.common.SolrInputDocument;
+import org.dspace.content.Community;
+import org.dspace.content.service.CommunityService;
+import org.dspace.core.Context;
+import org.dspace.discovery.SearchUtils;
+import org.dspace.discovery.configuration.DiscoveryConfiguration;
+import org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration;
+import org.dspace.discovery.configuration.DiscoveryHitHighlightingConfiguration;
+import org.dspace.discovery.indexobject.factory.CommunityIndexFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * Factory implementation for indexing/retrieving communities in the search core
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public class CommunityIndexFactoryImpl extends DSpaceObjectIndexFactoryImpl
+ implements CommunityIndexFactory {
+
+ @Autowired(required = true)
+ protected CommunityService communityService;
+
+ @Override
+ public Iterator findAll(Context context) throws SQLException {
+ Iterator communities = communityService.findAll(context).iterator();
+
+ return new Iterator() {
+ @Override
+ public boolean hasNext() {
+ return communities.hasNext();
+ }
+
+ @Override
+ public IndexableCommunity next() {
+ return new IndexableCommunity(communities.next());
+ }
+ };
+ }
+
+ @Override
+ public String getType() {
+ return IndexableCommunity.TYPE;
+ }
+
+
+ @Override
+ public SolrInputDocument buildDocument(Context context, IndexableCommunity indexableObject)
+ throws SQLException, IOException {
+ // Add the ID's, types and call the SolrServiceIndexPlugins
+ SolrInputDocument doc = super.buildDocument(context, indexableObject);
+ final Community community = indexableObject.getIndexedObject();
+
+ // Retrieve configuration
+ DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(community);
+ DiscoveryHitHighlightingConfiguration highlightingConfiguration = discoveryConfiguration
+ .getHitHighlightingConfiguration();
+ List highlightedMetadataFields = new ArrayList();
+ if (highlightingConfiguration != null) {
+ for (DiscoveryHitHighlightFieldConfiguration configuration : highlightingConfiguration
+ .getMetadataFields()) {
+ highlightedMetadataFields.add(configuration.getField());
+ }
+ }
+
+ // Add community metadata
+ String description = communityService.getMetadata(community, "introductory_text");
+ String description_abstract = communityService.getMetadata(community, "short_description");
+ String description_table = communityService.getMetadata(community, "side_bar_text");
+ String rights = communityService.getMetadata(community, "copyright_text");
+ String title = communityService.getMetadata(community, "name");
+
+ List toIgnoreMetadataFields = SearchUtils.getIgnoredMetadataFields(community.getType());
+ addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description",
+ description);
+ addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description.abstract",
+ description_abstract);
+ addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields,
+ "dc.description.tableofcontents", description_table);
+ addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.rights", rights);
+ addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.title", title);
+ return doc;
+ }
+
+ @Override
+ public boolean supports(Object object) {
+ return object instanceof Community;
+ }
+
+ @Override
+ public List getIndexableObjects(Context context, Community object) {
+ return Arrays.asList(new IndexableCommunity(object));
+ }
+
+ @Override
+ public Optional findIndexableObject(Context context, String id) throws SQLException {
+ final Community community = communityService.find(context, UUID.fromString(id));
+ return community == null ? Optional.empty() : Optional.of(new IndexableCommunity(community));
+ }
+
+ @Override
+ public List getLocations(Context context, IndexableCommunity indexableDSpaceObject) throws SQLException {
+ final Community target = indexableDSpaceObject.getIndexedObject();
+ List locations = new ArrayList<>();
+ // build list of community ids
+ List communities = target.getParentCommunities();
+
+ // now put those into strings
+ for (Community community : communities) {
+ locations.add("m" + community.getID());
+ }
+
+ return locations;
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/DSpaceObjectIndexFactoryImpl.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/DSpaceObjectIndexFactoryImpl.java
new file mode 100644
index 0000000000..08f9f31ea3
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/DSpaceObjectIndexFactoryImpl.java
@@ -0,0 +1,80 @@
+/**
+ * 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.indexobject;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.solr.common.SolrInputDocument;
+import org.dspace.content.DSpaceObject;
+import org.dspace.core.Context;
+import org.dspace.discovery.indexobject.factory.DSpaceObjectIndexFactory;
+
+/**
+ * Factory implementation for indexing/retrieving DSpaceObjects in the search core
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public abstract class DSpaceObjectIndexFactoryImpl
+ extends IndexFactoryImpl implements DSpaceObjectIndexFactory {
+
+ @Override
+ public SolrInputDocument buildDocument(Context context, T indexableObject) throws SQLException, IOException {
+ // Add the ID's, types and call the SolrServiceIndexPlugins
+ SolrInputDocument doc = super.buildDocument(context, indexableObject);
+ final DSpaceObject dso = indexableObject.getIndexedObject();
+
+ // want to be able to search for handle, so use keyword
+ // (not tokenized, but it is indexed)
+ if (dso.getHandle() != null) {
+ // want to be able to search for handle, so use keyword
+ // (not tokenized, but it is indexed)
+ doc.addField("handle", dso.getHandle());
+ }
+
+ final List locations = getLocations(context, indexableObject);
+ storeCommunityCollectionLocations(doc, locations);
+ return doc;
+ }
+
+ /**
+ * Add the metadata value of the community/collection to the solr document
+ * IF needed highlighting is added !
+ *
+ * @param doc the solr document
+ * @param highlightedMetadataFields the list of metadata fields that CAN be highlighted
+ * @param toIgnoreMetadataFields the list of metadata fields to skip adding to Solr
+ * @param metadataField the metadata field added
+ * @param value the value (can be NULL !)
+ */
+ protected void addContainerMetadataField(SolrInputDocument doc, List highlightedMetadataFields,
+ List toIgnoreMetadataFields, String metadataField, String value) {
+ if ((toIgnoreMetadataFields == null || !toIgnoreMetadataFields.contains(metadataField))
+ && StringUtils.isNotBlank(value)) {
+ doc.addField(metadataField, value);
+ if (highlightedMetadataFields.contains(metadataField)) {
+ doc.addField(metadataField + "_hl", value);
+ }
+ }
+ }
+
+ @Override
+ public void storeCommunityCollectionLocations(SolrInputDocument doc, List locations) {
+ if (locations != null) {
+ for (String location : locations) {
+ doc.addField("location", location);
+ if (location.startsWith("m")) {
+ doc.addField("location.comm", location.substring(1));
+ } else {
+ doc.addField("location.coll", location.substring(1));
+ }
+ }
+ }
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexFactoryImpl.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexFactoryImpl.java
new file mode 100644
index 0000000000..ca1423e593
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexFactoryImpl.java
@@ -0,0 +1,193 @@
+/**
+ * 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.indexobject;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
+import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.handler.extraction.ExtractingParams;
+import org.dspace.core.Context;
+import org.dspace.discovery.FullTextContentStreams;
+import org.dspace.discovery.IndexableObject;
+import org.dspace.discovery.SearchUtils;
+import org.dspace.discovery.SolrSearchCore;
+import org.dspace.discovery.SolrServiceIndexPlugin;
+import org.dspace.discovery.indexobject.factory.IndexFactory;
+import org.dspace.services.factory.DSpaceServicesFactory;
+import org.dspace.util.SolrUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * Basis factory interface implementation for indexing/retrieving any IndexableObject in the search core
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public abstract class IndexFactoryImpl implements IndexFactory {
+
+ @Autowired
+ protected List solrServiceIndexPlugins;
+ @Autowired
+ protected SolrSearchCore solrSearchCore;
+
+ @Override
+ public SolrInputDocument buildDocument(Context context, T indexableObject) throws SQLException, IOException {
+ SolrInputDocument doc = new SolrInputDocument();
+ // want to be able to check when last updated
+ // (not tokenized, but it is indexed)
+ doc.addField(SearchUtils.LAST_INDEXED_FIELD, SolrUtils.getDateFormatter().format(new Date()));
+
+ // New fields to weaken the dependence on handles, and allow for faster
+ // list display
+ doc.addField(SearchUtils.RESOURCE_UNIQUE_ID, indexableObject.getType() + "-" + indexableObject.getID());
+ doc.addField(SearchUtils.RESOURCE_TYPE_FIELD, indexableObject.getType());
+ doc.addField(SearchUtils.RESOURCE_ID_FIELD, indexableObject.getID().toString());
+
+ //Do any additional indexing, depends on the plugins
+ for (SolrServiceIndexPlugin solrServiceIndexPlugin : solrServiceIndexPlugins) {
+ solrServiceIndexPlugin.additionalIndex(context, indexableObject, doc);
+ }
+
+ return doc;
+ }
+
+ @Override
+ public void writeDocument(Context context, T indexableObject, SolrInputDocument solrInputDocument)
+ throws SQLException, IOException, SolrServerException {
+ writeDocument(solrInputDocument, null);
+ }
+
+ /**
+ * Write the document to the index under the appropriate unique identifier.
+ *
+ * @param doc the solr document to be written to the server
+ * @param streams list of bitstream content streams DiscoverQueryBuilderTest.java:285
+ * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
+ */
+ protected void writeDocument(SolrInputDocument doc, FullTextContentStreams streams)
+ throws IOException, SolrServerException {
+ final SolrClient solr = solrSearchCore.getSolr();
+ if (solr != null) {
+ if (streams != null && !streams.isEmpty()) {
+ ContentStreamUpdateRequest req = new ContentStreamUpdateRequest("/update/extract");
+ req.addContentStream(streams);
+
+ ModifiableSolrParams params = new ModifiableSolrParams();
+
+ //req.setParam(ExtractingParams.EXTRACT_ONLY, "true");
+ for (String name : doc.getFieldNames()) {
+ for (Object val : doc.getFieldValues(name)) {
+ params.add(ExtractingParams.LITERALS_PREFIX + name, val.toString());
+ }
+ }
+
+ req.setParams(params);
+ req.setParam(ExtractingParams.UNKNOWN_FIELD_PREFIX, "attr_");
+ req.setParam(ExtractingParams.MAP_PREFIX + "content", "fulltext");
+ req.setParam(ExtractingParams.EXTRACT_FORMAT, "text");
+ req.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true);
+ req.process(solr);
+ } else {
+ solr.add(doc);
+ }
+ }
+ }
+
+
+ /**
+ * Index the provided value as use for a sidebar facet
+ * @param document The solr document
+ * @param field The facet field name
+ * @param authority The authority linked to the field
+ * @param fvalue The display value for the facet
+ */
+ protected void addFacetIndex(SolrInputDocument document, String field, String authority, String fvalue) {
+ addFacetIndex(document, field, fvalue, authority, fvalue);
+ }
+
+ /**
+ * Index the provided value as use for a sidebar facet
+ * @param document The solr document
+ * @param field The facet field name
+ * @param sortValue The value on which we should sort our facet fields when retrieving
+ * @param authority The authority linked to the field
+ * @param fvalue The display value for the facet
+ */
+ protected void addFacetIndex(SolrInputDocument document, String field, String sortValue, String authority,
+ String fvalue) {
+ // the separator for the filter can be eventually configured
+ String separator = DSpaceServicesFactory.getInstance().getConfigurationService()
+ .getProperty("discovery.solr.facets.split.char");
+ if (separator == null) {
+ separator = SearchUtils.FILTER_SEPARATOR;
+ }
+ String acvalue = sortValue + separator + fvalue + SearchUtils.AUTHORITY_SEPARATOR + authority;
+ document.addField(field + "_filter", acvalue);
+ // build the solr field used for the keyword search
+ document.addField(field + "_keyword", fvalue);
+ // build the solr fields used for the autocomplete
+ document.addField(field + "_ac", fvalue.toLowerCase() + separator + fvalue);
+ if (StringUtils.isNotBlank(authority)) {
+ document.addField(field + "_acid", fvalue.toLowerCase() + separator + fvalue
+ + SearchUtils.AUTHORITY_SEPARATOR + authority);
+ document.addField(field + "_authority", authority);
+ }
+ }
+
+ /**
+ * Add the necessary fields to the SOLR document to support a Discover Facet on resourcetypename (archived item,
+ * workspace item, workflow item, etc)
+ *
+ * @param document the solr document
+ * @param filterValue the filter value (i.e. \n|||\n###
+ */
+ protected void addNamedResourceTypeIndex(SolrInputDocument document, String filterValue) {
+
+ // the separator for the filter can be eventually configured
+ String separator = DSpaceServicesFactory.getInstance().getConfigurationService()
+ .getProperty("discovery.solr.facets.split.char");
+ if (separator == null) {
+ separator = SearchUtils.FILTER_SEPARATOR;
+ }
+
+ // split the authority part from the sort/display
+ String[] avalues = filterValue.split(SearchUtils.AUTHORITY_SEPARATOR);
+
+ String sortValue = avalues[0];
+ String authorityValue = avalues.length == 2 ? avalues[1] : filterValue;
+
+ // get the display value
+ int idxSeparator = sortValue.indexOf(separator);
+ String displayValue = idxSeparator != -1 ? sortValue.substring(idxSeparator + separator.length())
+ : sortValue;
+
+ addFacetIndex(document, SearchUtils.NAMED_RESOURCE_TYPE, sortValue, authorityValue, displayValue);
+ }
+
+ @Override
+ public void delete(T indexableObject) throws IOException, SolrServerException {
+ solrSearchCore.getSolr().deleteById(indexableObject.getUniqueIndexID());
+ }
+
+ @Override
+ public void delete(String indexableObjectIdentifier) throws IOException, SolrServerException {
+ solrSearchCore.getSolr().deleteById(indexableObjectIdentifier);
+ }
+
+ @Override
+ public void deleteAll() throws IOException, SolrServerException {
+ solrSearchCore.getSolr().deleteByQuery(SearchUtils.RESOURCE_TYPE_FIELD + ":" + getType());
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableClaimedTask.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableClaimedTask.java
new file mode 100644
index 0000000000..3810b6803f
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableClaimedTask.java
@@ -0,0 +1,51 @@
+/**
+ * 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.indexobject;
+
+import org.dspace.discovery.IndexableObject;
+import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
+
+/**
+ * ClaimedTask implementation for the IndexableObject
+ *
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public class IndexableClaimedTask implements IndexableObject {
+
+ private ClaimedTask claimedTask;
+ public static final String TYPE = ClaimedTask.class.getSimpleName();
+
+ public IndexableClaimedTask(ClaimedTask claimedTask) {
+ this.claimedTask = claimedTask;
+ }
+
+ @Override
+ public ClaimedTask getIndexedObject() {
+ return claimedTask;
+ }
+
+ @Override
+ public void setIndexedObject(ClaimedTask claimedTask) {
+ this.claimedTask = claimedTask;
+ }
+
+ @Override
+ public String getType() {
+ return TYPE;
+ }
+
+ @Override
+ public Integer getID() {
+ return claimedTask.getID();
+ }
+
+ @Override
+ public String getTypeText() {
+ return "CLAIMEDTASK";
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableCollection.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableCollection.java
new file mode 100644
index 0000000000..d7a618c3f5
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableCollection.java
@@ -0,0 +1,35 @@
+/**
+ * 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.indexobject;
+
+import org.dspace.content.Collection;
+import org.dspace.core.Constants;
+
+/**
+ * Collection implementation for the IndexableObject
+ *
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public class IndexableCollection extends IndexableDSpaceObject {
+
+ public static final String TYPE = Collection.class.getSimpleName();
+
+ public IndexableCollection(Collection dso) {
+ super(dso);
+ }
+
+ @Override
+ public String getType() {
+ return TYPE;
+ }
+
+ @Override
+ public String getTypeText() {
+ return Constants.typeText[Constants.COLLECTION];
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableCommunity.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableCommunity.java
new file mode 100644
index 0000000000..46b927f00f
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableCommunity.java
@@ -0,0 +1,34 @@
+/**
+ * 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.indexobject;
+
+import org.dspace.content.Community;
+import org.dspace.core.Constants;
+
+/**
+ * Community implementation for the IndexableObject
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public class IndexableCommunity extends IndexableDSpaceObject {
+
+ public static final String TYPE = Community.class.getSimpleName();
+
+ public IndexableCommunity(Community dso) {
+ super(dso);
+ }
+
+ @Override
+ public String getType() {
+ return TYPE;
+ }
+
+ @Override
+ public String getTypeText() {
+ return Constants.typeText[Constants.COMMUNITY];
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableDSpaceObject.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableDSpaceObject.java
new file mode 100644
index 0000000000..7ad82b1a95
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableDSpaceObject.java
@@ -0,0 +1,43 @@
+/**
+ * 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.indexobject;
+
+import java.util.UUID;
+
+import org.dspace.content.DSpaceObject;
+import org.dspace.discovery.IndexableObject;
+
+/**
+ * DSpaceObject implementation for the IndexableObject, contains methods used by all DSpaceObject methods
+ * All DSpaceObjects that will be indexed in discovery should inherit from this class & have their own implementation
+ *
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public abstract class IndexableDSpaceObject implements IndexableObject {
+
+ private T dso;
+
+ public IndexableDSpaceObject(T dso) {
+ this.dso = dso;
+ }
+
+ @Override
+ public T getIndexedObject() {
+ return dso;
+ }
+
+ @Override
+ public void setIndexedObject(T dso) {
+ this.dso = dso;
+ }
+
+ @Override
+ public UUID getID() {
+ return dso.getID();
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableInProgressSubmission.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableInProgressSubmission.java
new file mode 100644
index 0000000000..cfa27ff814
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableInProgressSubmission.java
@@ -0,0 +1,35 @@
+/**
+ * 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.indexobject;
+
+import org.dspace.content.InProgressSubmission;
+import org.dspace.discovery.IndexableObject;
+
+/**
+ * InProgressSubmission implementation for the IndexableObject
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public abstract class IndexableInProgressSubmission
+ implements IndexableObject {
+
+ protected T inProgressSubmission;
+
+ public IndexableInProgressSubmission(T inProgressSubmission) {
+ this.inProgressSubmission = inProgressSubmission;
+ }
+
+ @Override
+ public T getIndexedObject() {
+ return inProgressSubmission;
+ }
+
+ @Override
+ public void setIndexedObject(T inProgressSubmission) {
+ this.inProgressSubmission = inProgressSubmission;
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableItem.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableItem.java
new file mode 100644
index 0000000000..ec67406e8f
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableItem.java
@@ -0,0 +1,41 @@
+/**
+ * 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.indexobject;
+
+import java.util.Date;
+
+import org.dspace.content.Item;
+import org.dspace.core.Constants;
+
+/**
+ * Item implementation for the IndexableObject
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public class IndexableItem extends IndexableDSpaceObject
- {
+
+ public static final String TYPE = Item.class.getSimpleName();
+
+ public IndexableItem(Item dso) {
+ super(dso);
+ }
+
+ @Override
+ public Date getLastModified() {
+ return getIndexedObject().getLastModified();
+ }
+
+ @Override
+ public String getType() {
+ return TYPE;
+ }
+
+ @Override
+ public String getTypeText() {
+ return Constants.typeText[Constants.ITEM];
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexablePoolTask.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexablePoolTask.java
new file mode 100644
index 0000000000..6eea1f0ebb
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexablePoolTask.java
@@ -0,0 +1,51 @@
+/**
+ * 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.indexobject;
+
+import org.dspace.discovery.IndexableObject;
+import org.dspace.xmlworkflow.storedcomponents.PoolTask;
+
+/**
+ * PoolTask implementation for the IndexableObject
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public class IndexablePoolTask implements IndexableObject {
+
+ public static final String TYPE = PoolTask.class.getSimpleName();
+
+ private PoolTask poolTask;
+
+ public IndexablePoolTask(PoolTask poolTask) {
+ this.poolTask = poolTask;
+ }
+
+ @Override
+ public PoolTask getIndexedObject() {
+ return poolTask;
+ }
+
+ @Override
+ public void setIndexedObject(PoolTask poolTask) {
+ this.poolTask = poolTask;
+ }
+
+ @Override
+ public String getType() {
+ return TYPE;
+ }
+
+ @Override
+ public String getTypeText() {
+ return "POOLTASK";
+ }
+
+ @Override
+ public Integer getID() {
+ return poolTask.getID();
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableWorkflowItem.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableWorkflowItem.java
new file mode 100644
index 0000000000..016fec1bbb
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableWorkflowItem.java
@@ -0,0 +1,38 @@
+/**
+ * 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.indexobject;
+
+import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
+
+/**
+ * Workflow item implementation for the IndexableObject
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public class IndexableWorkflowItem extends IndexableInProgressSubmission {
+
+ public static final String TYPE = XmlWorkflowItem.class.getSimpleName();
+
+ public IndexableWorkflowItem(XmlWorkflowItem inProgressSubmission) {
+ super(inProgressSubmission);
+ }
+
+ @Override
+ public String getType() {
+ return TYPE;
+ }
+
+ @Override
+ public String getTypeText() {
+ return "WORKFLOWITEM";
+ }
+
+ @Override
+ public Integer getID() {
+ return getIndexedObject().getID();
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableWorkspaceItem.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableWorkspaceItem.java
new file mode 100644
index 0000000000..65b05b0d49
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexableWorkspaceItem.java
@@ -0,0 +1,38 @@
+/**
+ * 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.indexobject;
+
+import org.dspace.content.WorkspaceItem;
+
+/**
+ * Workspace item implementation for the IndexableObject
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public class IndexableWorkspaceItem extends IndexableInProgressSubmission {
+
+ public static final String TYPE = WorkspaceItem.class.getSimpleName();
+
+ public IndexableWorkspaceItem(WorkspaceItem inProgressSubmission) {
+ super(inProgressSubmission);
+ }
+
+ @Override
+ public String getType() {
+ return TYPE;
+ }
+
+ @Override
+ public Integer getID() {
+ return getIndexedObject().getID();
+ }
+
+ @Override
+ public String getTypeText() {
+ return "WORKSPACEITEM";
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/InprogressSubmissionIndexFactoryImpl.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/InprogressSubmissionIndexFactoryImpl.java
new file mode 100644
index 0000000000..4109d11021
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/InprogressSubmissionIndexFactoryImpl.java
@@ -0,0 +1,66 @@
+/**
+ * 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.indexobject;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.solr.common.SolrInputDocument;
+import org.dspace.content.InProgressSubmission;
+import org.dspace.content.Item;
+import org.dspace.core.Context;
+import org.dspace.discovery.indexobject.factory.CollectionIndexFactory;
+import org.dspace.discovery.indexobject.factory.InprogressSubmissionIndexFactory;
+import org.dspace.discovery.indexobject.factory.ItemIndexFactory;
+import org.dspace.eperson.EPerson;
+import org.dspace.util.SolrUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * Factory implementation for indexing/retrieving InProgressSubmissions in the search core
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public abstract class InprogressSubmissionIndexFactoryImpl
+ extends IndexFactoryImpl
+ implements InprogressSubmissionIndexFactory {
+
+ @Autowired
+ protected CollectionIndexFactory indexableCollectionService;
+ @Autowired
+ protected ItemIndexFactory indexableItemService;
+
+
+ @Override
+ public SolrInputDocument buildDocument(Context context, T indexableObject) throws SQLException, IOException {
+ // Add the ID's, types and call the SolrServiceIndexPlugins
+ SolrInputDocument doc = super.buildDocument(context, indexableObject);
+ // Add submitter, locations and modification time
+ storeInprogressItemFields(context, doc, indexableObject.getIndexedObject());
+ return doc;
+ }
+
+ @Override
+ public void storeInprogressItemFields(Context context, SolrInputDocument doc,
+ InProgressSubmission inProgressSubmission) throws SQLException {
+ final Item item = inProgressSubmission.getItem();
+ doc.addField("lastModified", SolrUtils.getDateFormatter().format(item.getLastModified()));
+ EPerson submitter = inProgressSubmission.getSubmitter();
+ if (submitter != null) {
+ addFacetIndex(doc, "submitter", submitter.getID().toString(),
+ submitter.getFullName());
+ }
+
+ doc.addField("inprogress.item", new IndexableItem(inProgressSubmission.getItem()).getUniqueIndexID());
+
+ // get the location string (for searching by collection & community)
+ List locations = indexableCollectionService.
+ getCollectionLocations(context, inProgressSubmission.getCollection());
+ indexableCollectionService.storeCommunityCollectionLocations(doc, locations);
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/ItemIndexFactoryImpl.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/ItemIndexFactoryImpl.java
new file mode 100644
index 0000000000..7f98131566
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/ItemIndexFactoryImpl.java
@@ -0,0 +1,733 @@
+/**
+ * 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.indexobject;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.UUID;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.time.DateFormatUtils;
+import org.apache.logging.log4j.Logger;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.common.SolrInputDocument;
+import org.dspace.content.Collection;
+import org.dspace.content.Community;
+import org.dspace.content.Item;
+import org.dspace.content.MetadataField;
+import org.dspace.content.MetadataSchema;
+import org.dspace.content.MetadataValue;
+import org.dspace.content.WorkspaceItem;
+import org.dspace.content.authority.Choices;
+import org.dspace.content.authority.service.ChoiceAuthorityService;
+import org.dspace.content.authority.service.MetadataAuthorityService;
+import org.dspace.content.service.ItemService;
+import org.dspace.content.service.WorkspaceItemService;
+import org.dspace.core.Context;
+import org.dspace.core.LogManager;
+import org.dspace.discovery.FullTextContentStreams;
+import org.dspace.discovery.IndexableObject;
+import org.dspace.discovery.SearchUtils;
+import org.dspace.discovery.configuration.DiscoveryConfiguration;
+import org.dspace.discovery.configuration.DiscoveryConfigurationParameters;
+import org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration;
+import org.dspace.discovery.configuration.DiscoveryHitHighlightingConfiguration;
+import org.dspace.discovery.configuration.DiscoveryMoreLikeThisConfiguration;
+import org.dspace.discovery.configuration.DiscoveryRecentSubmissionsConfiguration;
+import org.dspace.discovery.configuration.DiscoverySearchFilter;
+import org.dspace.discovery.configuration.DiscoverySearchFilterFacet;
+import org.dspace.discovery.configuration.DiscoverySortConfiguration;
+import org.dspace.discovery.configuration.DiscoverySortFieldConfiguration;
+import org.dspace.discovery.configuration.HierarchicalSidebarFacetConfiguration;
+import org.dspace.discovery.indexobject.factory.ItemIndexFactory;
+import org.dspace.discovery.indexobject.factory.WorkflowItemIndexFactory;
+import org.dspace.discovery.indexobject.factory.WorkspaceItemIndexFactory;
+import org.dspace.eperson.EPerson;
+import org.dspace.handle.service.HandleService;
+import org.dspace.services.factory.DSpaceServicesFactory;
+import org.dspace.util.MultiFormatDateParser;
+import org.dspace.util.SolrUtils;
+import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
+import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * Factory implementation for indexing/retrieving items in the search core
+ * @author Kevin Van de Velde (kevin at atmire dot com)
+ */
+public class ItemIndexFactoryImpl extends DSpaceObjectIndexFactoryImpl
+ implements ItemIndexFactory {
+
+ private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(ItemIndexFactoryImpl.class);
+ public static final String VARIANTS_STORE_SEPARATOR = "###";
+ public static final String STORE_SEPARATOR = "\n|||\n";
+
+
+ @Autowired
+ protected HandleService handleService;
+ @Autowired
+ protected ItemService itemService;
+ @Autowired(required = true)
+ protected ChoiceAuthorityService choiceAuthorityService;
+ @Autowired
+ protected MetadataAuthorityService metadataAuthorityService;
+ @Autowired
+ protected WorkspaceItemService workspaceItemService;
+ @Autowired
+ protected XmlWorkflowItemService xmlWorkflowItemService;
+ @Autowired
+ protected WorkflowItemIndexFactory workflowItemIndexFactory;
+ @Autowired
+ protected WorkspaceItemIndexFactory workspaceItemIndexFactory;
+
+
+ @Override
+ public Iterator findAll(Context context) throws SQLException {
+ Iterator
- items = itemService.findAllUnfiltered(context);
+ return new Iterator() {
+ @Override
+ public boolean hasNext() {
+ return items.hasNext();
+ }
+
+ @Override
+ public IndexableItem next() {
+ return new IndexableItem(items.next());
+ }
+ };
+ }
+
+ @Override
+ public String getType() {
+ return IndexableItem.TYPE;
+ }
+
+ /**
+ * Build a Solr document for a DSpace Item and write the index
+ *
+ * @param context Users Context
+ * @param indexableItem The IndexableItem Item to be indexed
+ * @throws SQLException if database error
+ * @throws IOException if IO error
+ */
+ @Override
+ public SolrInputDocument buildDocument(Context context, IndexableItem indexableItem)
+ throws SQLException, IOException {
+ // Add the ID's, types and call the SolrServiceIndexPlugins
+ SolrInputDocument doc = super.buildDocument(context, indexableItem);
+
+ final Item item = indexableItem.getIndexedObject();
+
+ doc.addField("archived", item.isArchived());
+ doc.addField("withdrawn", item.isWithdrawn());
+ doc.addField("discoverable", item.isDiscoverable());
+ doc.addField("lastModified", SolrUtils.getDateFormatter().format(item.getLastModified()));
+
+ EPerson submitter = item.getSubmitter();
+ if (submitter != null) {
+ addFacetIndex(doc, "submitter", submitter.getID().toString(),
+ submitter.getFullName());
+ }
+
+ // Add the item metadata
+ List discoveryConfigurations = SearchUtils.getAllDiscoveryConfigurations(item);
+ addDiscoveryFields(doc, context, indexableItem.getIndexedObject(), discoveryConfigurations);
+
+ //mandatory facet to show status on mydspace
+ final String typeText = StringUtils.deleteWhitespace(indexableItem.getTypeText().toLowerCase());
+ String acvalue = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty(
+ "discovery.facet.namedtype." + typeText,
+ typeText + SearchUtils.AUTHORITY_SEPARATOR + typeText);
+ if (StringUtils.isNotBlank(acvalue)) {
+ addNamedResourceTypeIndex(doc, acvalue);
+ }
+
+ // write the index and close the inputstreamreaders
+ try {
+ log.info("Wrote Item: " + item.getID() + " to Index");
+ } catch (RuntimeException e) {
+ log.error("Error while writing item to discovery index: " + item.getID() + " message:"
+ + e.getMessage(), e);
+ }
+ return doc;
+ }
+
+ @Override
+ public void addDiscoveryFields(SolrInputDocument doc, Context context, Item item,
+ List discoveryConfigurations)
+ throws SQLException, IOException {
+ //Keep a list of our sort values which we added, sort values can only be added once
+ List sortFieldsAdded = new ArrayList<>();
+ Map> searchFilters = null;
+ Set hitHighlightingFields = new HashSet<>();
+ try {
+ //A map used to save each sidebarFacet config by the metadata fields
+ searchFilters = new HashMap<>();
+ Map sortFields = new HashMap<>();
+ Map recentSubmissionsConfigurationMap = new
+ HashMap<>();
+ Set moreLikeThisFields = new HashSet<>();
+ // some configuration are returned multiple times, skip them to save CPU cycles
+ Set appliedConf = new HashSet<>();
+ // it is common to have search filter shared between multiple configurations
+ Set appliedDiscoverySearchFilter = new HashSet<>();
+
+ for (DiscoveryConfiguration discoveryConfiguration : discoveryConfigurations) {
+ if (appliedConf.contains(discoveryConfiguration.getId())) {
+ continue;
+ } else {
+ appliedConf.add(discoveryConfiguration.getId());
+ }
+ for (int i = 0; i < discoveryConfiguration.getSearchFilters().size(); i++) {
+ if (appliedDiscoverySearchFilter
+ .contains(discoveryConfiguration.getSearchFilters().get(i).getIndexFieldName())) {
+ continue;
+ } else {
+ appliedDiscoverySearchFilter
+ .add(discoveryConfiguration.getSearchFilters().get(i).getIndexFieldName());
+ }
+ List metadataValueList = new LinkedList<>();
+ boolean shouldExposeMinMax = false;
+ DiscoverySearchFilter discoverySearchFilter = discoveryConfiguration.getSearchFilters().get(i);
+ if (StringUtils.equalsIgnoreCase(discoverySearchFilter.getFilterType(), "facet")) {
+ if (((DiscoverySearchFilterFacet) discoverySearchFilter).exposeMinAndMaxValue()) {
+ shouldExposeMinMax = true;
+ }
+ }
+ for (int j = 0; j < discoverySearchFilter.getMetadataFields().size(); j++) {
+ String metadataField = discoverySearchFilter.getMetadataFields().get(j);
+ List resultingList;
+ if (searchFilters.get(metadataField) != null) {
+ resultingList = searchFilters.get(metadataField);
+ } else {
+ //New metadata field, create a new list for it
+ resultingList = new ArrayList<>();
+ }
+
+
+ if (shouldExposeMinMax) {
+ String[] splittedMetadataField = metadataField.split("\\.");
+ String schema = splittedMetadataField[0];
+ String element = splittedMetadataField.length > 1 ? splittedMetadataField[1] : null;
+ String qualifier = splittedMetadataField.length > 2 ? splittedMetadataField[2] : null;
+
+ metadataValueList.addAll(itemService.getMetadata(item, schema,
+ element, qualifier, Item.ANY));
+
+ }
+
+ resultingList.add(discoverySearchFilter);
+
+ searchFilters.put(metadataField, resultingList);
+ }
+
+ if (!metadataValueList.isEmpty() && shouldExposeMinMax) {
+ metadataValueList.sort((mdv1, mdv2) -> mdv1.getValue().compareTo(mdv2.getValue()));
+ MetadataValue firstMetadataValue = metadataValueList.get(0);
+ MetadataValue lastMetadataValue = metadataValueList.get(metadataValueList.size() - 1);
+
+ doc.addField(discoverySearchFilter.getIndexFieldName() + "_min", firstMetadataValue.getValue());
+ doc.addField(discoverySearchFilter.getIndexFieldName()
+ + "_min_sort", firstMetadataValue.getValue());
+ doc.addField(discoverySearchFilter.getIndexFieldName() + "_max", lastMetadataValue.getValue());
+ doc.addField(discoverySearchFilter.getIndexFieldName()
+ + "_max_sort", lastMetadataValue.getValue());
+
+ }
+ }
+
+ DiscoverySortConfiguration sortConfiguration = discoveryConfiguration.getSearchSortConfiguration();
+ if (sortConfiguration != null) {
+ for (DiscoverySortFieldConfiguration discoverySortConfiguration : sortConfiguration
+ .getSortFields()) {
+ sortFields.put(discoverySortConfiguration.getMetadataField(), discoverySortConfiguration);
+ }
+ }
+
+ DiscoveryRecentSubmissionsConfiguration recentSubmissionConfiguration = discoveryConfiguration
+ .getRecentSubmissionConfiguration();
+ if (recentSubmissionConfiguration != null) {
+ recentSubmissionsConfigurationMap
+ .put(recentSubmissionConfiguration.getMetadataSortField(), recentSubmissionConfiguration);
+ }
+
+ DiscoveryHitHighlightingConfiguration hitHighlightingConfiguration = discoveryConfiguration
+ .getHitHighlightingConfiguration();
+ if (hitHighlightingConfiguration != null) {
+ List fieldConfigurations = hitHighlightingConfiguration
+ .getMetadataFields();
+ for (DiscoveryHitHighlightFieldConfiguration fieldConfiguration : fieldConfigurations) {
+ hitHighlightingFields.add(fieldConfiguration.getField());
+ }
+ }
+ DiscoveryMoreLikeThisConfiguration moreLikeThisConfiguration = discoveryConfiguration
+ .getMoreLikeThisConfiguration();
+ if (moreLikeThisConfiguration != null) {
+ for (String metadataField : moreLikeThisConfiguration.getSimilarityMetadataFields()) {
+ moreLikeThisFields.add(metadataField);
+ }
+ }
+ }
+
+
+ List toProjectionFields = new ArrayList<>();
+ String[] projectionFields = DSpaceServicesFactory.getInstance().getConfigurationService()
+ .getArrayProperty("discovery.index.projection");
+ if (projectionFields != null) {
+ for (String field : projectionFields) {
+ toProjectionFields.add(field.trim());
+ }
+ }
+
+ List toIgnoreMetadataFields = SearchUtils.getIgnoredMetadataFields(item.getType());
+ List mydc = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY);
+ for (MetadataValue meta : mydc) {
+ MetadataField metadataField = meta.getMetadataField();
+ MetadataSchema metadataSchema = metadataField.getMetadataSchema();
+ String field = metadataSchema.getName() + "." + metadataField.getElement();
+ String unqualifiedField = field;
+
+ String value = meta.getValue();
+
+ if (value == null) {
+ continue;
+ }
+
+ if (metadataField.getQualifier() != null && !metadataField.getQualifier().trim().equals("")) {
+ field += "." + metadataField.getQualifier();
+ }
+
+ //We are not indexing provenance, this is useless
+ if (toIgnoreMetadataFields != null && (toIgnoreMetadataFields.contains(field) || toIgnoreMetadataFields
+ .contains(unqualifiedField + "." + Item.ANY))) {
+ continue;
+ }
+
+ String authority = null;
+ String preferedLabel = null;
+ List variants = null;
+ boolean isAuthorityControlled = metadataAuthorityService
+ .isAuthorityControlled(metadataField);
+
+ int minConfidence = isAuthorityControlled ? metadataAuthorityService
+ .getMinConfidence(metadataField) : Choices.CF_ACCEPTED;
+
+ if (isAuthorityControlled && meta.getAuthority() != null
+ && meta.getConfidence() >= minConfidence) {
+ boolean ignoreAuthority =
+ DSpaceServicesFactory
+ .getInstance()
+ .getConfigurationService()
+ .getPropertyAsType("discovery.index.authority.ignore." + field,
+ DSpaceServicesFactory
+ .getInstance()
+ .getConfigurationService()
+ .getPropertyAsType("discovery.index.authority.ignore",
+ new Boolean(false)),
+ true);
+ if (!ignoreAuthority) {
+ authority = meta.getAuthority();
+
+ boolean ignorePrefered =
+ DSpaceServicesFactory
+ .getInstance()
+ .getConfigurationService()
+ .getPropertyAsType("discovery.index.authority.ignore-prefered." + field,
+ DSpaceServicesFactory
+ .getInstance()
+ .getConfigurationService()
+ .getPropertyAsType("discovery.index.authority.ignore-prefered",
+ new Boolean(false)),
+ true);
+ if (!ignorePrefered) {
+
+ preferedLabel = choiceAuthorityService
+ .getLabel(meta, meta.getLanguage());
+ }
+
+ boolean ignoreVariants =
+ DSpaceServicesFactory
+ .getInstance()
+ .getConfigurationService()
+ .getPropertyAsType("discovery.index.authority.ignore-variants." + field,
+ DSpaceServicesFactory
+ .getInstance()
+ .getConfigurationService()
+ .getPropertyAsType("discovery.index.authority.ignore-variants",
+ new Boolean(false)),
+ true);
+ if (!ignoreVariants) {
+ variants = choiceAuthorityService
+ .getVariants(meta);
+ }
+
+ }
+ }
+
+ if ((searchFilters.get(field) != null || searchFilters
+ .get(unqualifiedField + "." + Item.ANY) != null)) {
+ List searchFilterConfigs = searchFilters.get(field);
+ if (searchFilterConfigs == null) {
+ searchFilterConfigs = searchFilters.get(unqualifiedField + "." + Item.ANY);
+ }
+
+ for (DiscoverySearchFilter searchFilter : searchFilterConfigs) {
+ Date date = null;
+ String separator = DSpaceServicesFactory.getInstance().getConfigurationService()
+ .getProperty("discovery.solr.facets.split.char");
+ if (separator == null) {
+ separator = SearchUtils.FILTER_SEPARATOR;
+ }
+ if (searchFilter.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE)) {
+ //For our search filters that are dates we format them properly
+ date = MultiFormatDateParser.parse(value);
+ if (date != null) {
+ //TODO: make this date format configurable !
+ value = DateFormatUtils.formatUTC(date, "yyyy-MM-dd");
+ }
+ }
+ doc.addField(searchFilter.getIndexFieldName(), value);
+ doc.addField(searchFilter.getIndexFieldName() + "_keyword", value);
+
+ if (authority != null && preferedLabel == null) {
+ doc.addField(searchFilter.getIndexFieldName()
+ + "_keyword", value + SearchUtils.AUTHORITY_SEPARATOR
+ + authority);
+ doc.addField(searchFilter.getIndexFieldName()
+ + "_authority", authority);
+ doc.addField(searchFilter.getIndexFieldName()
+ + "_acid", value.toLowerCase()
+ + separator + value
+ + SearchUtils.AUTHORITY_SEPARATOR + authority);
+ }
+
+ if (preferedLabel != null) {
+ doc.addField(searchFilter.getIndexFieldName(),
+ preferedLabel);
+ doc.addField(searchFilter.getIndexFieldName()
+ + "_keyword", preferedLabel);
+ doc.addField(searchFilter.getIndexFieldName()
+ + "_keyword", preferedLabel
+ + SearchUtils.AUTHORITY_SEPARATOR + authority);
+ doc.addField(searchFilter.getIndexFieldName()
+ + "_authority", authority);
+ doc.addField(searchFilter.getIndexFieldName()
+ + "_acid", preferedLabel.toLowerCase()
+ + separator + preferedLabel
+ + SearchUtils.AUTHORITY_SEPARATOR + authority);
+ }
+ if (variants != null) {
+ for (String var : variants) {
+ doc.addField(searchFilter.getIndexFieldName() + "_keyword", var);
+ doc.addField(searchFilter.getIndexFieldName()
+ + "_acid", var.toLowerCase()
+ + separator + var
+ + SearchUtils.AUTHORITY_SEPARATOR + authority);
+ }
+ }
+
+ //Add a dynamic fields for auto complete in search
+ doc.addField(searchFilter.getIndexFieldName() + "_ac",
+ value.toLowerCase() + separator + value);
+ if (preferedLabel != null) {
+ doc.addField(searchFilter.getIndexFieldName()
+ + "_ac", preferedLabel.toLowerCase()
+ + separator + preferedLabel);
+ }
+ if (variants != null) {
+ for (String var : variants) {
+ doc.addField(searchFilter.getIndexFieldName()
+ + "_ac", var.toLowerCase() + separator
+ + var);
+ }
+ }
+
+ if (searchFilter.getFilterType().equals(DiscoverySearchFilterFacet.FILTER_TYPE_FACET)) {
+ if (searchFilter.getType().equals(DiscoveryConfigurationParameters.TYPE_TEXT)) {
+ //Add a special filter
+ //We use a separator to split up the lowercase and regular case, this is needed to
+ // get our filters in regular case
+ //Solr has issues with facet prefix and cases
+ if (authority != null) {
+ String facetValue = preferedLabel != null ? preferedLabel : value;
+ doc.addField(searchFilter.getIndexFieldName() + "_filter", facetValue
+ .toLowerCase() + separator + facetValue + SearchUtils.AUTHORITY_SEPARATOR
+ + authority);
+ } else {
+ doc.addField(searchFilter.getIndexFieldName() + "_filter",
+ value.toLowerCase() + separator + value);
+ }
+ } else if (searchFilter.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE)) {
+ if (date != null) {
+ String indexField = searchFilter.getIndexFieldName() + ".year";
+ String yearUTC = DateFormatUtils.formatUTC(date, "yyyy");
+ doc.addField(searchFilter.getIndexFieldName() + "_keyword", yearUTC);
+ // add the year to the autocomplete index
+ doc.addField(searchFilter.getIndexFieldName() + "_ac", yearUTC);
+ doc.addField(indexField, yearUTC);
+
+ if (yearUTC.startsWith("0")) {
+ doc.addField(
+ searchFilter.getIndexFieldName()
+ + "_keyword",
+ yearUTC.replaceFirst("0*", ""));
+ // add date without starting zeros for autocomplete e filtering
+ doc.addField(
+ searchFilter.getIndexFieldName()
+ + "_ac",
+ yearUTC.replaceFirst("0*", ""));
+ doc.addField(
+ searchFilter.getIndexFieldName()
+ + "_ac",
+ value.replaceFirst("0*", ""));
+ doc.addField(
+ searchFilter.getIndexFieldName()
+ + "_keyword",
+ value.replaceFirst("0*", ""));
+ }
+
+ //Also save a sort value of this year, this is required for determining the upper
+ // & lower bound year of our facet
+ if (doc.getField(indexField + "_sort") == null) {
+ //We can only add one year so take the first one
+ doc.addField(indexField + "_sort", yearUTC);
+ }
+ }
+ } else if (searchFilter.getType()
+ .equals(DiscoveryConfigurationParameters.TYPE_HIERARCHICAL)) {
+ HierarchicalSidebarFacetConfiguration hierarchicalSidebarFacetConfiguration =
+ (HierarchicalSidebarFacetConfiguration) searchFilter;
+ String[] subValues = value.split(hierarchicalSidebarFacetConfiguration.getSplitter());
+ if (hierarchicalSidebarFacetConfiguration
+ .isSkipFirstNodeLevel() && 1 < subValues.length) {
+ //Remove the first element of our array
+ subValues = (String[]) ArrayUtils.subarray(subValues, 1, subValues.length);
+ }
+ for (int i = 0; i < subValues.length; i++) {
+ StringBuilder valueBuilder = new StringBuilder();
+ for (int j = 0; j <= i; j++) {
+ valueBuilder.append(subValues[j]);
+ if (j < i) {
+ valueBuilder.append(hierarchicalSidebarFacetConfiguration.getSplitter());
+ }
+ }
+
+ String indexValue = valueBuilder.toString().trim();
+ doc.addField(searchFilter.getIndexFieldName() + "_tax_" + i + "_filter",
+ indexValue.toLowerCase() + separator + indexValue);
+ //We add the field x times that it has occurred
+ for (int j = i; j < subValues.length; j++) {
+ doc.addField(searchFilter.getIndexFieldName() + "_filter",
+ indexValue.toLowerCase() + separator + indexValue);
+ doc.addField(searchFilter.getIndexFieldName() + "_keyword", indexValue);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ((sortFields.get(field) != null || recentSubmissionsConfigurationMap
+ .get(field) != null) && !sortFieldsAdded.contains(field)) {
+ //Only add sort value once
+ String type;
+ if (sortFields.get(field) != null) {
+ type = sortFields.get(field).getType();
+ } else {
+ type = recentSubmissionsConfigurationMap.get(field).getType();
+ }
+
+ if (type.equals(DiscoveryConfigurationParameters.TYPE_DATE)) {
+ Date date = MultiFormatDateParser.parse(value);
+ if (date != null) {
+ String stringDate = SolrUtils.getDateFormatter().format(date);
+ doc.addField(field + "_dt", stringDate);
+ } else {
+ log.warn("Error while indexing sort date field, item: " + item
+ .getHandle() + " metadata field: " + field + " date value: " + date);
+ }
+ } else {
+ doc.addField(field + "_sort", value);
+ }
+ sortFieldsAdded.add(field);
+ }
+
+ if (hitHighlightingFields.contains(field) || hitHighlightingFields
+ .contains("*") || hitHighlightingFields.contains(unqualifiedField + "." + Item.ANY)) {
+ if (authority != null) {
+ doc.addField(field + "_hl", value + SearchUtils.AUTHORITY_SEPARATOR + authority);
+ } else {
+ doc.addField(field + "_hl", value);
+ }
+ }
+
+ if (moreLikeThisFields.contains(field) || moreLikeThisFields
+ .contains(unqualifiedField + "." + Item.ANY)) {
+ doc.addField(field + "_mlt", value);
+ }
+
+ doc.addField(field, value);
+ if (authority != null) {
+ doc.addField(field + "_authority", authority);
+ }
+ if (toProjectionFields.contains(field) || toProjectionFields
+ .contains(unqualifiedField + "." + Item.ANY)) {
+ StringBuffer variantsToStore = new StringBuffer();
+ if (variants != null) {
+ for (String var : variants) {
+ variantsToStore.append(VARIANTS_STORE_SEPARATOR);
+ variantsToStore.append(var);
+ }
+ }
+ doc.addField(
+ field + "_stored",
+ value + STORE_SEPARATOR + preferedLabel
+ + STORE_SEPARATOR
+ + (variantsToStore.length() > VARIANTS_STORE_SEPARATOR
+ .length() ? variantsToStore
+ .substring(VARIANTS_STORE_SEPARATOR
+ .length()) : "null")
+ + STORE_SEPARATOR + authority
+ + STORE_SEPARATOR + meta.getLanguage());
+ }
+
+ if (meta.getLanguage() != null && !meta.getLanguage().trim().equals("")) {
+ String langField = field + "." + meta.getLanguage();
+ doc.addField(langField, value);
+ }
+ }
+
+ } catch (Exception e) {
+ log.error(LogManager.getHeader(context, "item_metadata_discovery_error",
+ "Item identifier: " + item.getID()), e);
+ }
+
+
+ log.debug(" Added Metadata");
+
+ try {
+
+ List values = itemService.getMetadataByMetadataString(item, "dc.relation.ispartof");
+
+ if (values != null && values.size() > 0 && values.get(0) != null && values.get(0).getValue() != null) {
+ // group on parent
+ String handlePrefix = handleService.getCanonicalPrefix();
+
+ doc.addField("publication_grp", values.get(0).getValue().replaceFirst(handlePrefix, ""));
+
+ } else {
+ // group on self
+ doc.addField("publication_grp", item.getHandle());
+ }
+
+ } catch (Exception e) {
+ log.error(LogManager.getHeader(context, "item_publication_group_discovery_error",
+ "Item identifier: " + item.getID()), e);
+ }
+
+
+ log.debug(" Added Grouping");
+ }
+
+ @Override
+ public void writeDocument(Context context, IndexableItem indexableObject, SolrInputDocument solrInputDocument)
+ throws SQLException, IOException, SolrServerException {
+ writeDocument(solrInputDocument, new FullTextContentStreams(context, indexableObject.getIndexedObject()));
+ }
+
+ @Override
+ public List getLocations(Context context, IndexableItem indexableDSpaceObject)
+ throws SQLException {
+ final Item item = indexableDSpaceObject.getIndexedObject();
+ List locations = new ArrayList<>();
+
+ // build list of community ids
+ List