Skip to content

Commit

Permalink
feat(cn-browse): support aliases for callNumberTypeId filters
Browse files Browse the repository at this point in the history
Closes: MSEARCH-942
  • Loading branch information
psmagin committed Jan 15, 2025
1 parent e4df3f8 commit 610ba63
Show file tree
Hide file tree
Showing 29 changed files with 114 additions and 45 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* Call Numbers Browse: Implement Call Number Browse Config ([MSEARCH-863](https://folio-org.atlassian.net/browse/MSEARCH-863))
* Call Numbers Browse: Implement Indexing and Re-indexing Mechanisms for Call-Numbers ([MSEARCH-864](https://folio-org.atlassian.net/browse/MSEARCH-864))
* Call Numbers Browse: Implement Browsing Endpoint for Call-Numbers ([MSEARCH-865](https://folio-org.atlassian.net/browse/MSEARCH-865))
* Call Numbers Browse: Support aliases for callNumberTypeId filters ([MSEARCH-942](https://folio-org.atlassian.net/browse/MSEARCH-942))

### Bug fixes
* Remove shelving order calculation for local call-number types
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,12 @@ does not produce any values, so the following search options will return an empt
|:------------------------|:----:|:------------------------------------|:------------------------------------------------|
| `contributorNameTypeId` | term | `contributorNameTypeId == "123456"` | Matches contributors with `123456` name type id |

##### Call-numbers search options

| Option | Type | Example | Description |
|:-------------------|:----:|:-------------------------------|:--------------------------------------------------------------------------------------------------------------------------------|
| `callNumberTypeId` | term | `callNumberTypeId == "123456"` | Matches call-numbers with `123456` call-number type id. Support aliases by call-number browse options: `callNumberTypeId == lc` |

#### Search Facets

Facets can be retrieved by using following API `GET /{recordType}/facets`. It consumes following request parameters:
Expand Down Expand Up @@ -876,6 +882,14 @@ GET /instances/facets?query=title all book&facet=source:5,discoverySuppress:2
| `instances.tenantId` | term | Requests a tenantId facet |
| `instances.shared` | term | Requests a shared/local facet |

##### Classifications facets

| Option | Type | Description |
|:-----------------------|:----:|:------------------------------|
| `instances.locationId` | term | Requests a location facet |
| `instances.tenantId` | term | Requests a tenantId facet |
| `instances.shared` | term | Requests a shared/local facet |

#### Sorting results

The default sorting is by relevancy. The `sortBy` clause is used to define sorting, for example:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.folio.search.cql.builders.TermQueryBuilder;
import org.folio.search.cql.searchterm.SearchTermProcessor;
import org.folio.search.exception.RequestValidationException;
import org.folio.search.exception.ValidationException;
import org.folio.search.model.metadata.PlainFieldDescription;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static org.opensearch.index.query.QueryBuilders.multiMatchQuery;
import static org.opensearch.index.query.QueryBuilders.scriptQuery;
import static org.opensearch.index.query.QueryBuilders.termQuery;
import static org.opensearch.index.query.QueryBuilders.termsQuery;

import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -46,6 +47,9 @@ public QueryBuilder getFulltextQuery(Object term, String fieldName, ResourceType

@Override
public QueryBuilder getTermLevelQuery(Object term, String fieldName, ResourceType resource, String fieldIndex) {
if (term instanceof String[] termArray) {
return termArray.length > 1 ? termsQuery(fieldName, termArray) : termQuery(fieldName, termArray[0]);
}
return EMPTY_ARRAY.equals(term) && KEYWORD_FIELD_INDEX.equals(fieldIndex)
? getEmptyArrayScriptQuery(fieldName)
: termQuery(fieldName, term);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.folio.search.cql;
package org.folio.search.cql.searchterm;

import static org.folio.search.utils.CallNumberUtils.normalizeCallNumberComponents;
import static org.folio.search.utils.SearchUtils.ASTERISKS_SIGN;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.folio.search.cql.searchterm;

import lombok.RequiredArgsConstructor;
import org.folio.search.domain.dto.BrowseOptionType;
import org.folio.search.domain.dto.BrowseType;
import org.folio.search.service.consortium.BrowseConfigServiceDecorator;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class CallNumberTypeIdSearchTermProcessor implements SearchTermProcessor {

private final BrowseConfigServiceDecorator configService;

@Override
public Object getSearchTerm(String inputTerm) {
try {
var browseOptionType = BrowseOptionType.fromValue(inputTerm);
var browseConfig = configService.getConfig(BrowseType.CALL_NUMBER, browseOptionType);
return browseConfig.getTypeIds().stream().map(Object::toString).toArray(String[]::new);
} catch (IllegalArgumentException e) {
return inputTerm;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.folio.search.cql;
package org.folio.search.cql.searchterm;

import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.apache.commons.lang3.StringUtils.isBlank;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.folio.search.cql;
package org.folio.search.cql.searchterm;

import static org.folio.search.utils.CallNumberUtils.getShelfKeyFromCallNumber;
import static org.folio.search.utils.CallNumberUtils.normalizeEffectiveShelvingOrder;
Expand All @@ -8,6 +8,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import org.folio.search.cql.SuDocCallNumber;
import org.folio.search.domain.dto.CallNumberType;
import org.marc4j.callnum.CallNumber;
import org.marc4j.callnum.DeweyCallNumber;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.folio.search.cql;
package org.folio.search.cql.searchterm;

import lombok.RequiredArgsConstructor;
import org.folio.search.service.setter.instance.IsbnProcessor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.folio.search.cql;
package org.folio.search.cql.searchterm;

import lombok.RequiredArgsConstructor;
import org.folio.search.service.lccn.LccnNormalizer;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.folio.search.cql;
package org.folio.search.cql.searchterm;

import lombok.RequiredArgsConstructor;
import org.folio.search.service.setter.instance.OclcProcessor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.folio.search.cql;
package org.folio.search.cql.searchterm;

public interface SearchTermProcessor {

Expand Down
4 changes: 3 additions & 1 deletion src/main/java/org/folio/search/utils/SearchQueryUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.opensearch.index.query.QueryBuilder;
import org.opensearch.index.query.RangeQueryBuilder;
import org.opensearch.index.query.TermQueryBuilder;
import org.opensearch.index.query.TermsQueryBuilder;
import org.opensearch.search.aggregations.AggregationBuilders;
import org.opensearch.search.aggregations.bucket.terms.IncludeExclude;
import org.opensearch.search.builder.SearchSourceBuilder;
Expand Down Expand Up @@ -75,7 +76,8 @@ public static boolean isDisjunctionFilterQuery(QueryBuilder query, Predicate<Str
* @return true if query is type of filter, false - otherwise
*/
public static boolean isFilterQuery(QueryBuilder query, Predicate<String> check) {
return query instanceof TermQueryBuilder && check.test(((TermQueryBuilder) query).fieldName())
return query instanceof TermsQueryBuilder && check.test(((TermsQueryBuilder) query).fieldName())
|| query instanceof TermQueryBuilder && check.test(((TermQueryBuilder) query).fieldName())
|| query instanceof RangeQueryBuilder && check.test(((RangeQueryBuilder) query).fieldName());
}

Expand Down
5 changes: 3 additions & 2 deletions src/main/resources/model/instance_call_number.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
},
"callNumberTypeId": {
"index": "keyword",
"searchTypes": [ "facet" ],
"showInResponse": [ "browse" ]
"searchTypes": [ "filter", "facet" ],
"showInResponse": [ "browse" ],
"searchTermProcessor": "callNumberTypeIdSearchTermProcessor"
},
"volume": {
"index": "source",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,16 @@
value:
items:
- fullCallNumber: "Bilingualism: a bibliography of 1000 references with special reference to Wales."
shelfKey: "Bilingualism: a bibliography of 1000 references with special reference to Wales."
- fullCallNumber: "NS 1 .B5"
callNumber: "NS 1 .B4"
callNumberTypeId: "2b94c631-fca9-4892-a730-03ee529ff6c3"
prefix: "pref1"
isAnchor: true
totalRecords: 1
instance:
id: "d20569a7-9bba-44dd-9ad5-6f8f1d24ee1f"
title: "Bilingualism: a bibliography of 1000 references with special reference to Wales."
contributors:
- name: "Eichhorst, Georg."
publication:
- publisher: "Duncker und Humblot"
dateOfPublication: "1976"
electronicAccess:
- uri: "http://www.example.com"
notes:
- note: "Staff note"
items:
- barcode: "12345"
notes:
- note: "Staff note"
electronicAccess:
- uri: "http://www.example.com"
holdings:
- callNumber: "FS 124.44"
notes:
- note: "Staff note"
electronicAccess:
- uri: "http://www.example.com"
prev: "string"
next: "string"
totalRecords: 1
- fullCallNumber: "NS 1 .B5 suf-1801"
callNumber: "NS 1 .B5"
suffix: "suf-1801"
isAnchor: true
totalRecords: 1
prev: "NS 1 .B4"
next: "NS 1 .B5 suf-1801"
totalRecords: 2
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: query
in: query
required: true
description: |
A CQL query string with filter conditions must include anchor query with range conditions. Anchor field is `number`.
A CQL query string with filter conditions must include anchor query with range conditions. Anchor field is `fullCallNumber`.
Filters support logic operators `AND` and `OR`. All filters should be combined in parentheses.
Anchor will be included only if `<=` or `>=` are used in the query. Otherwise, the empty row will be added if `highlightMatch` is equal to `true`.
<table>
Expand Down Expand Up @@ -30,6 +30,18 @@ description: |
<td>==</td>
<td>Filter by shared/non-shared in consortium</td>
</tr>
<tr>
<td>instances.locationId</td>
<td>string</td>
<td>==</td>
<td>Filter by location ID</td>
</tr>
<tr>
<td>callNumberTypeId</td>
<td>string</td>
<td>==</td>
<td>Filter by call-number type ID</td>
</tr>
</tbody>
</table>
schema:
Expand All @@ -45,5 +57,5 @@ examples:
value: number >= "DT571.F84"
summary: Search for all classification numbers before "DT571.F84"
browseAroundWithFilters:
value: (number >= "DT571.F84" or number < "DT571.F84") and instances.shared==false
value: (number >= "DT571.F84" or number < "DT571.F84") and instances.shared==false and instances.locationId=="2b94c631-fca9-4892-a730-03ee529ff6c3"
summary: Search for local classification numbers before and after "DT571.F84"
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ get:
application/json:
examples:
browseResult:
$ref: '../../examples/result/browseClassificationNumberResult.yaml'
$ref: '../../examples/result/browseCallNumberResult.yaml'
schema:
$ref: '../../schemas/response/callNumberBrowseResult.yaml'
'400':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ private static Stream<Arguments> facetQueriesProvider() {
arguments("cql.allRecords=1", array("instances.locationId"), mapOf("instances.locationId",
facet(facetItem(locations.get(1), 42), facetItem(locations.get(2), 34), facetItem(locations.get(3), 24)))),
arguments("callNumberTypeId=\"" + LC.getId() + "\"", array("instances.locationId"), mapOf("instances.locationId",
facet(facetItem(locations.get(1), 8), facetItem(locations.get(2), 8), facetItem(locations.get(3), 4)))),
arguments("callNumberTypeId==lc", array("instances.locationId"), mapOf("instances.locationId",
facet(facetItem(locations.get(1), 8), facetItem(locations.get(2), 8), facetItem(locations.get(3), 4))))
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static org.assertj.core.api.Assertions.assertThat;

import org.folio.search.cql.searchterm.CallNumberSearchTermProcessor;
import org.folio.spring.testing.type.UnitTest;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.stream.Stream;
import org.folio.search.cql.searchterm.ClassificationNumberSearchTermProcessor;
import org.folio.spring.testing.type.UnitTest;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.util.Optional;
import java.util.stream.Stream;
import org.folio.search.cql.CqlSearchQueryConverterTest.ConverterTestConfiguration;
import org.folio.search.cql.searchterm.SearchTermProcessor;
import org.folio.search.exception.RequestValidationException;
import org.folio.search.exception.SearchServiceException;
import org.folio.search.model.metadata.PlainFieldDescription;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.Optional;
import java.util.Set;
import org.folio.search.cql.builders.TermQueryBuilder;
import org.folio.search.cql.searchterm.SearchTermProcessor;
import org.folio.search.exception.RequestValidationException;
import org.folio.search.exception.ValidationException;
import org.folio.search.service.metadata.LocalSearchFieldProvider;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import java.util.List;
import java.util.stream.Collectors;
import org.folio.search.cql.searchterm.EffectiveShelvingOrderTermProcessor;
import org.folio.spring.testing.type.UnitTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static org.mockito.Mockito.when;

import java.util.List;
import org.folio.search.cql.searchterm.IsbnSearchTermProcessor;
import org.folio.search.service.setter.instance.IsbnProcessor;
import org.folio.spring.testing.type.UnitTest;
import org.junit.jupiter.api.Test;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static org.mockito.Mockito.when;

import java.util.Optional;
import org.folio.search.cql.searchterm.LccnSearchTermProcessor;
import org.folio.search.service.lccn.LccnNormalizer;
import org.folio.spring.testing.type.UnitTest;
import org.junit.jupiter.api.Test;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;

import org.folio.search.cql.searchterm.OclcSearchTermProcessor;
import org.folio.search.service.setter.instance.OclcProcessor;
import org.folio.spring.testing.type.UnitTest;
import org.junit.jupiter.api.Test;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import static org.opensearch.index.query.QueryBuilders.multiMatchQuery;
import static org.opensearch.index.query.QueryBuilders.scriptQuery;
import static org.opensearch.index.query.QueryBuilders.termQuery;
import static org.opensearch.index.query.QueryBuilders.termsQuery;

import java.util.List;
import java.util.Optional;
Expand Down Expand Up @@ -95,6 +96,19 @@ void getTermLevelQuery_positive_emptyArrayValueNonKeywordField() {
assertThat(actual).isEqualTo(termQuery("field", "[]"));
}

@Test
void getTermLevelQuery_positive_arrayOfTermsWithSizeLessThen1() {
var actual = queryBuilder.getTermLevelQuery(new String[]{"val1"}, "field", UNKNOWN, null);
assertThat(actual).isEqualTo(termQuery("field", "val1"));
}


@Test
void getTermLevelQuery_positive_arrayOfTermsWithSizeGreaterThen1() {
var actual = queryBuilder.getTermLevelQuery(new String[]{"val1", "val2"}, "field", UNKNOWN, null);
assertThat(actual).isEqualTo(termsQuery("field", "val1", "val2"));
}

@Test
void getSupportedComparators_positive() {
var actual = queryBuilder.getSupportedComparators();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import org.apache.lucene.search.TotalHits;
import org.folio.search.configuration.properties.SearchConfigurationProperties;
import org.folio.search.cql.CqlSearchQueryConverter;
import org.folio.search.cql.EffectiveShelvingOrderTermProcessor;
import org.folio.search.cql.searchterm.EffectiveShelvingOrderTermProcessor;
import org.folio.search.domain.dto.Instance;
import org.folio.search.domain.dto.Item;
import org.folio.search.domain.dto.ItemEffectiveCallNumberComponents;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ private static Stream<Arguments> isFilterQueryDataProvider() {
arguments(rangeQuery("f").gt(10), false),
arguments(matchQuery(FIELD, "value"), false),
arguments(termQuery(FIELD, "value"), true),
arguments(termQuery("f", "v"), false)
);
arguments(termQuery("f", "v"), false),
arguments(termsQuery(FIELD, "value"), true)
);
}
}

0 comments on commit 610ba63

Please sign in to comment.