mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
Merge pull request #8613 from atmire/issue-1712_w2p-97080_facet-search-all-words-main
Facet search should search all words, not just the first one
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
*/
|
||||
package org.dspace.discovery;
|
||||
|
||||
import static org.dspace.discovery.SolrServiceImpl.SOLR_FIELD_SUFFIX_FACET_PREFIXES;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@@ -109,6 +111,9 @@ public class DiscoverResult {
|
||||
if (facetValues.size() == 0 && field.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE)) {
|
||||
facetValues = getFacetResult(field.getIndexFieldName() + ".year");
|
||||
}
|
||||
if (facetValues.isEmpty()) {
|
||||
facetValues = getFacetResult(field.getIndexFieldName() + SOLR_FIELD_SUFFIX_FACET_PREFIXES);
|
||||
}
|
||||
return ListUtils.emptyIfNull(facetValues);
|
||||
}
|
||||
|
||||
|
@@ -105,6 +105,10 @@ public class SolrServiceImpl implements SearchService, IndexingService {
|
||||
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(SolrServiceImpl.class);
|
||||
|
||||
// Suffix of the solr field used to index the facet/filter so that the facet search can search all word in a
|
||||
// facet by indexing "each word to end of value' partial value
|
||||
public static final String SOLR_FIELD_SUFFIX_FACET_PREFIXES = "_prefix";
|
||||
|
||||
@Autowired
|
||||
protected ContentServiceFactory contentServiceFactory;
|
||||
@Autowired
|
||||
@@ -905,6 +909,9 @@ public class SolrServiceImpl implements SearchService, IndexingService {
|
||||
//Only add facet information if there are any facets
|
||||
for (DiscoverFacetField facetFieldConfig : facetFields) {
|
||||
String field = transformFacetField(facetFieldConfig, facetFieldConfig.getField(), false);
|
||||
if (facetFieldConfig.getPrefix() != null) {
|
||||
field = transformPrefixFacetField(facetFieldConfig, facetFieldConfig.getField(), false);
|
||||
}
|
||||
solrQuery.addFacetField(field);
|
||||
|
||||
// Setting the facet limit in this fashion ensures that each facet can have its own max
|
||||
@@ -1344,7 +1351,31 @@ public class SolrServiceImpl implements SearchService, IndexingService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the solr field that contains the facet value split on each word break to the end, so can be searched
|
||||
* on each word in the value, see {@link org.dspace.discovery.indexobject.ItemIndexFactoryImpl
|
||||
* #saveFacetPrefixParts(SolrInputDocument, DiscoverySearchFilter, String, String)}
|
||||
* Ony applicable to facets of type {@link DiscoveryConfigurationParameters.TYPE_TEXT}, otherwise uses the regular
|
||||
* facet filter field
|
||||
*/
|
||||
protected String transformPrefixFacetField(DiscoverFacetField facetFieldConfig, String field,
|
||||
boolean removePostfix) {
|
||||
if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_TEXT) ||
|
||||
facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_HIERARCHICAL)) {
|
||||
if (removePostfix) {
|
||||
return field.substring(0, field.lastIndexOf(SOLR_FIELD_SUFFIX_FACET_PREFIXES));
|
||||
} else {
|
||||
return field + SOLR_FIELD_SUFFIX_FACET_PREFIXES;
|
||||
}
|
||||
} else {
|
||||
return this.transformFacetField(facetFieldConfig, field, removePostfix);
|
||||
}
|
||||
}
|
||||
|
||||
protected String transformFacetField(DiscoverFacetField facetFieldConfig, String field, boolean removePostfix) {
|
||||
if (field.contains(SOLR_FIELD_SUFFIX_FACET_PREFIXES)) {
|
||||
return this.transformPrefixFacetField(facetFieldConfig, field, removePostfix);
|
||||
}
|
||||
if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_TEXT)) {
|
||||
if (removePostfix) {
|
||||
return field.substring(0, field.lastIndexOf("_filter"));
|
||||
@@ -1390,7 +1421,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
|
||||
if (field.equals("location.comm") || field.equals("location.coll")) {
|
||||
value = locationToName(context, field, value);
|
||||
} else if (field.endsWith("_filter") || field.endsWith("_ac")
|
||||
|| field.endsWith("_acid")) {
|
||||
|| field.endsWith("_acid") || field.endsWith(SOLR_FIELD_SUFFIX_FACET_PREFIXES)) {
|
||||
//We have a filter make sure we split !
|
||||
String separator = DSpaceServicesFactory.getInstance().getConfigurationService()
|
||||
.getProperty("discovery.solr.facets.split.char");
|
||||
@@ -1422,7 +1453,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
|
||||
return value;
|
||||
}
|
||||
if (field.endsWith("_filter") || field.endsWith("_ac")
|
||||
|| field.endsWith("_acid")) {
|
||||
|| field.endsWith("_acid") || field.endsWith(SOLR_FIELD_SUFFIX_FACET_PREFIXES)) {
|
||||
//We have a filter make sure we split !
|
||||
String separator = DSpaceServicesFactory.getInstance().getConfigurationService()
|
||||
.getProperty("discovery.solr.facets.split.char");
|
||||
|
@@ -7,6 +7,8 @@
|
||||
*/
|
||||
package org.dspace.discovery;
|
||||
|
||||
import static org.dspace.discovery.SolrServiceImpl.SOLR_FIELD_SUFFIX_FACET_PREFIXES;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -261,9 +263,9 @@ public class SolrServiceMetadataBrowseIndexingPlugin implements SolrServiceIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (String facet : distFValues) {
|
||||
document.addField(bi.getDistinctTableName() + "_filter", facet);
|
||||
document.addField(bi.getDistinctTableName() + SOLR_FIELD_SUFFIX_FACET_PREFIXES, facet);
|
||||
}
|
||||
for (String facet : distFAuths) {
|
||||
document.addField(bi.getDistinctTableName()
|
||||
|
@@ -7,6 +7,8 @@
|
||||
*/
|
||||
package org.dspace.discovery.indexobject;
|
||||
|
||||
import static org.dspace.discovery.SolrServiceImpl.SOLR_FIELD_SUFFIX_FACET_PREFIXES;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
@@ -20,6 +22,8 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -519,88 +523,10 @@ public class ItemIndexFactoryImpl extends DSpaceObjectIndexFactoryImpl<Indexable
|
||||
+ var);
|
||||
}
|
||||
}
|
||||
|
||||
// if searchFilter is of type "facet", delegate to indexIfFilterTypeFacet method
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
indexIfFilterTypeFacet(doc, searchFilter, value, date,
|
||||
authority, preferedLabel, separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -796,4 +722,140 @@ public class ItemIndexFactoryImpl extends DSpaceObjectIndexFactoryImpl<Indexable
|
||||
final Item item = itemService.find(context, UUID.fromString(id));
|
||||
return item == null ? Optional.empty() : Optional.of(new IndexableItem(item));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles indexing when discoverySearchFilter is of type facet.
|
||||
*
|
||||
* @param doc the solr document
|
||||
* @param searchFilter the discoverySearchFilter
|
||||
* @param value the metadata value
|
||||
* @param date Date object
|
||||
* @param authority the authority key
|
||||
* @param preferedLabel the preferred label for metadata field
|
||||
* @param separator the separator being used to separate lowercase and regular case
|
||||
*/
|
||||
private void indexIfFilterTypeFacet(SolrInputDocument doc, DiscoverySearchFilter searchFilter, String value,
|
||||
Date date, String authority, String preferedLabel, String separator) {
|
||||
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);
|
||||
}
|
||||
//Also add prefix field with all parts of value
|
||||
saveFacetPrefixParts(doc, searchFilter, value, separator, authority, preferedLabel);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
//Also add prefix field with all parts of value
|
||||
saveFacetPrefixParts(doc, searchFilter, value, separator, authority, preferedLabel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores every "value part" in lowercase, together with the original value in regular case,
|
||||
* separated by the separator, in the {fieldName}{@link SolrServiceImpl.SOLR_FIELD_SUFFIX_FACET_PREFIXES} field.
|
||||
* <br>
|
||||
* E.g. Author "With Multiple Words" gets stored as:
|
||||
* <br>
|
||||
* <code>
|
||||
* with multiple words ||| With Multiple Words, <br>
|
||||
* multiple words ||| With Multiple Words, <br>
|
||||
* words ||| With Multiple Words, <br>
|
||||
* </code>
|
||||
* in the author_prefix field.
|
||||
* @param doc the solr document
|
||||
* @param searchFilter the current discoverySearchFilter
|
||||
* @param value the metadata value
|
||||
* @param separator the separator being used to separate value part and original value
|
||||
*/
|
||||
private void saveFacetPrefixParts(SolrInputDocument doc, DiscoverySearchFilter searchFilter, String value,
|
||||
String separator, String authority, String preferedLabel) {
|
||||
value = StringUtils.normalizeSpace(value);
|
||||
Pattern pattern = Pattern.compile("\\b\\w+\\b", Pattern.CASE_INSENSITIVE);
|
||||
Matcher matcher = pattern.matcher(value);
|
||||
while (matcher.find()) {
|
||||
int index = matcher.start();
|
||||
String currentPart = StringUtils.substring(value, index);
|
||||
if (authority != null) {
|
||||
String facetValue = preferedLabel != null ? preferedLabel : currentPart;
|
||||
doc.addField(searchFilter.getIndexFieldName() + SOLR_FIELD_SUFFIX_FACET_PREFIXES,
|
||||
facetValue.toLowerCase() + separator + value
|
||||
+ SearchUtils.AUTHORITY_SEPARATOR + authority);
|
||||
} else {
|
||||
doc.addField(searchFilter.getIndexFieldName() + SOLR_FIELD_SUFFIX_FACET_PREFIXES,
|
||||
currentPart.toLowerCase() + separator + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -428,8 +428,9 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest
|
||||
getClient().perform(get("/api/discover/facets/author")
|
||||
.param("prefix", "Smith"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values",
|
||||
containsInAnyOrder(FacetValueMatcher.entryFacetWithoutSelfLink("Smith, John"))));
|
||||
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
|
||||
FacetValueMatcher.entryFacetWithoutSelfLink("Smith, John"),
|
||||
FacetValueMatcher.entryFacetWithoutSelfLink("stIjn, SmITH"))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/author")
|
||||
.param("prefix", "S"))
|
||||
@@ -438,6 +439,9 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest
|
||||
.entryFacetWithoutSelfLink("Smith, John"),
|
||||
FacetValueMatcher
|
||||
.entryFacetWithoutSelfLink("S’Idan, Mo"),
|
||||
// gets returned once for smith, once for stijn
|
||||
FacetValueMatcher
|
||||
.entryFacetWithoutSelfLink("stIjn, SmITH"),
|
||||
FacetValueMatcher
|
||||
.entryFacetWithoutSelfLink("stIjn, SmITH"))));
|
||||
|
||||
@@ -494,12 +498,99 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest
|
||||
containsInAnyOrder(FacetValueMatcher.entryFacetWithoutSelfLink("I.T."))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "?U"))
|
||||
.param("prefix", "U"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values",
|
||||
containsInAnyOrder(FacetValueMatcher.entryFacetWithoutSelfLink("?Unknown"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoverFacetsAuthorTestWithPrefixFirstName() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||
.withName("Parent Community").build();
|
||||
|
||||
Collection collection = CollectionBuilder.createCollection(context, parentCommunity)
|
||||
.withName("Parent Collection").build();
|
||||
|
||||
Item item1 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 1")
|
||||
.withAuthor("Smith, John")
|
||||
.build();
|
||||
|
||||
Item item2 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 2")
|
||||
.withAuthor("Smith, Jane")
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
getClient().perform(get("/api/discover/facets/author")
|
||||
.param("prefix", "john"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values",
|
||||
containsInAnyOrder(
|
||||
FacetValueMatcher.entryAuthor("Smith, John"))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/author")
|
||||
.param("prefix", "jane"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values",
|
||||
containsInAnyOrder(
|
||||
FacetValueMatcher.entryAuthor("Smith, Jane"))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/author")
|
||||
.param("prefix", "j"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values",
|
||||
containsInAnyOrder(
|
||||
FacetValueMatcher.entryAuthor("Smith, John"),
|
||||
FacetValueMatcher.entryAuthor("Smith, Jane"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoverFacetsAuthorWithAuthorityTestWithPrefixFirstName() throws Exception {
|
||||
configurationService.setProperty("choices.plugin.dc.contributor.author", "SolrAuthorAuthority");
|
||||
configurationService.setProperty("authority.controlled.dc.contributor.author", "true");
|
||||
|
||||
metadataAuthorityService.clearCache();
|
||||
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||
.withName("Parent Community").build();
|
||||
|
||||
Collection collection = CollectionBuilder.createCollection(context, parentCommunity)
|
||||
.withName("Parent Collection").build();
|
||||
|
||||
Item item1 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 1")
|
||||
.withAuthor("Smith, John", "test_authority_1", Choices.CF_ACCEPTED)
|
||||
.build();
|
||||
|
||||
Item item2 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 2")
|
||||
.withAuthor("Smith, Jane", "test_authority_2", Choices.CF_ACCEPTED)
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
getClient().perform(get("/api/discover/facets/author")
|
||||
.param("prefix", "j"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values",
|
||||
containsInAnyOrder(
|
||||
FacetValueMatcher.entryAuthorWithAuthority(
|
||||
"Smith, John", "test_authority_1", 1),
|
||||
FacetValueMatcher.entryAuthorWithAuthority(
|
||||
"Smith, Jane", "test_authority_2", 1))));
|
||||
|
||||
DSpaceServicesFactory.getInstance().getConfigurationService().reloadConfig();
|
||||
|
||||
metadataAuthorityService.clearCache();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoverFacetsAuthorTestForHasMoreFalse() throws Exception {
|
||||
//Turn of the authorization system so that we can create the structure specified below
|
||||
@@ -5987,4 +6078,240 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest
|
||||
.andExpect(jsonPath("$._embedded.values").value(Matchers.hasSize(1)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoverFacetsSubjectTestWithCapitalAndSpecialChars() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||
.withName("Parent Community").build();
|
||||
|
||||
Collection collection = CollectionBuilder.createCollection(context, parentCommunity)
|
||||
.withName("Parent Collection").build();
|
||||
|
||||
Item item1 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 1")
|
||||
.withSubject("Value with: Multiple Words ")
|
||||
.build();
|
||||
|
||||
Item item2 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 2")
|
||||
.withSubject("Multiple worded subject ")
|
||||
.build();
|
||||
|
||||
Item item3 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 3")
|
||||
.withSubject("Subject with a lot of Word values")
|
||||
.build();
|
||||
|
||||
Item item4 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 4")
|
||||
.withSubject("With, Values")
|
||||
.build();
|
||||
|
||||
Item item5 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 5")
|
||||
.withSubject("Test:of:the:colon")
|
||||
.build();
|
||||
|
||||
Item item6 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 6")
|
||||
.withSubject("Test,of,comma")
|
||||
.build();
|
||||
|
||||
Item item7 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 7")
|
||||
.withSubject("N’guyen")
|
||||
.build();
|
||||
|
||||
Item item8 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 8")
|
||||
.withSubject("test;Semicolon")
|
||||
.build();
|
||||
|
||||
Item item9 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 9")
|
||||
.withSubject("test||of|Pipe")
|
||||
.build();
|
||||
|
||||
Item item10 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 10")
|
||||
.withSubject("Test-Subject")
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "with a lot of word"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
|
||||
FacetValueMatcher.entrySubject("Subject with a lot of Word values", 1))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "multiple words"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
|
||||
FacetValueMatcher.entrySubject("Value with: Multiple Words", 1))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "mUltiPle wor"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
|
||||
FacetValueMatcher.entrySubject("Multiple worded subject", 1),
|
||||
FacetValueMatcher.entrySubject("Value with: Multiple Words", 1))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "with"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
|
||||
FacetValueMatcher.entrySubject("With, Values", 1),
|
||||
FacetValueMatcher.entrySubject("Subject with a lot of Word values", 1),
|
||||
FacetValueMatcher.entrySubject("Value with: Multiple Words", 1))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "of"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
|
||||
FacetValueMatcher.entrySubject("Subject with a lot of Word values", 1),
|
||||
FacetValueMatcher.entrySubject("Test,of,comma", 1),
|
||||
FacetValueMatcher.entrySubject("Test:of:the:colon", 1),
|
||||
FacetValueMatcher.entrySubject("test||of|Pipe", 1))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "tEsT"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
|
||||
FacetValueMatcher.entrySubject("Test,of,comma", 1),
|
||||
FacetValueMatcher.entrySubject("Test-Subject", 1),
|
||||
FacetValueMatcher.entrySubject("Test:of:the:colon", 1),
|
||||
FacetValueMatcher.entrySubject("test;Semicolon", 1),
|
||||
FacetValueMatcher.entrySubject("test||of|Pipe", 1))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "colon"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
|
||||
FacetValueMatcher.entrySubject("Test:of:the:colon", 1))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "coMma"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
|
||||
FacetValueMatcher.entrySubject("Test,of,comma", 1))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "guyen"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
|
||||
FacetValueMatcher.entrySubject("N’guyen", 1))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "semiColon"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
|
||||
FacetValueMatcher.entrySubject("test;Semicolon", 1))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "pipe"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
|
||||
FacetValueMatcher.entrySubject("test||of|Pipe", 1))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "Subject"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
|
||||
FacetValueMatcher.entrySubject("Multiple worded subject", 1),
|
||||
FacetValueMatcher.entrySubject("Test-Subject", 1),
|
||||
FacetValueMatcher.entrySubject("Subject with a lot of Word values", 1))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "Subject of word"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values").isEmpty())
|
||||
.andExpect(jsonPath("$.page.number", is(0)));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "Value with words"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values").isEmpty())
|
||||
.andExpect(jsonPath("$.page.number", is(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoverFacetsSubjectWithAuthorityTest() throws Exception {
|
||||
configurationService.setProperty("choices.plugin.dc.subject", "SolrSubjectAuthority");
|
||||
configurationService.setProperty("authority.controlled.dc.subject", "true");
|
||||
|
||||
metadataAuthorityService.clearCache();
|
||||
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
parentCommunity = CommunityBuilder.createCommunity(context)
|
||||
.withName("Parent Community").build();
|
||||
|
||||
Collection collection = CollectionBuilder.createCollection(context, parentCommunity)
|
||||
.withName("Parent Collection").build();
|
||||
|
||||
Item item1 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 1")
|
||||
.withSubject("Value with: Multiple Words",
|
||||
"test_authority_1", Choices.CF_ACCEPTED)
|
||||
.build();
|
||||
|
||||
Item item2 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 2")
|
||||
.withSubject("Multiple worded subject ",
|
||||
"test_authority_2", Choices.CF_ACCEPTED)
|
||||
.build();
|
||||
|
||||
Item item3 = ItemBuilder.createItem(context, collection)
|
||||
.withTitle("Item 3")
|
||||
.withSubject("Subject with a lot of Word values",
|
||||
"test_authority_3", Choices.CF_ACCEPTED)
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "with a lot of word"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
|
||||
FacetValueMatcher.entrySubjectWithAuthority("Subject with a lot of Word values",
|
||||
"test_authority_3", 1))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "mUltiPle wor"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
|
||||
FacetValueMatcher.entrySubjectWithAuthority("Multiple worded subject",
|
||||
"test_authority_2", 1),
|
||||
FacetValueMatcher.entrySubjectWithAuthority("Value with: Multiple Words",
|
||||
"test_authority_1", 1))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "Subject"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values", containsInAnyOrder(
|
||||
FacetValueMatcher.entrySubjectWithAuthority("Multiple worded subject",
|
||||
"test_authority_2", 1),
|
||||
FacetValueMatcher.entrySubjectWithAuthority("Subject with a lot of Word values",
|
||||
"test_authority_3", 1))));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "Subject of word"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values").isEmpty())
|
||||
.andExpect(jsonPath("$.page.number", is(0)));
|
||||
|
||||
getClient().perform(get("/api/discover/facets/subject")
|
||||
.param("prefix", "Value with words"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.values").isEmpty())
|
||||
.andExpect(jsonPath("$.page.number", is(0)));
|
||||
|
||||
DSpaceServicesFactory.getInstance().getConfigurationService().reloadConfig();
|
||||
|
||||
metadataAuthorityService.clearCache();
|
||||
}
|
||||
}
|
||||
|
@@ -55,15 +55,20 @@ public class FacetValueMatcher {
|
||||
hasJsonPath("$.type", is("discover")),
|
||||
hasJsonPath("$.count", is(count)),
|
||||
hasJsonPath("$._links.search.href", containsString("api/discover/search/objects")),
|
||||
hasJsonPath("$._links.search.href", containsString("f.subject=" + label + ",equals"))
|
||||
hasJsonPath("$._links.search.href", containsString(
|
||||
"f.subject=" + urlPathSegmentEscaper().escape(label) + ",equals"))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static Matcher<? super Object> entrySubject(String label, String authority, int count) {
|
||||
public static Matcher<? super Object> entrySubjectWithAuthority(String label, String authority, int count) {
|
||||
return allOf(
|
||||
hasJsonPath("$.authorityKey", is(authority)),
|
||||
entrySubject(label, count)
|
||||
hasJsonPath("$.count", is(count)),
|
||||
hasJsonPath("$.label", is(label)),
|
||||
hasJsonPath("$.type", is("discover")),
|
||||
hasJsonPath("$._links.search.href", containsString("api/discover/search/objects")),
|
||||
hasJsonPath("$._links.search.href", containsString("f.subject=" + authority + ",authority"))
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -299,6 +299,9 @@
|
||||
|
||||
<!--Dynamic field used for sidebar filters & SOLR browse by value -->
|
||||
<dynamicField name="*_filter" type="keywordFilter" indexed="true" stored="true" multiValued="true" omitNorms="true" />
|
||||
<!--Dynamic field used to index the facet/filter value, split on each word to end,
|
||||
so that the facet search can search all words in a facet-->
|
||||
<dynamicField name="*_prefix" type="keywordFilter" indexed="true" stored="true" multiValued="true" omitNorms="true" />
|
||||
<dynamicField name="*_authority" type="keywordFilter" indexed="true" stored="true" multiValued="true" omitNorms="true" />
|
||||
<dynamicField name="*_keyword" type="keywordFilter" indexed="true" stored="true" multiValued="true" omitNorms="true" />
|
||||
|
||||
|
Reference in New Issue
Block a user