Skip to content

Commit 353ca92

Browse files
authored
Merge pull request #11558 from vera/feat/search-api-collections
feat: return list of collections of datasets in search API
2 parents 684e0ba + a111fa5 commit 353ca92

File tree

14 files changed

+158
-33
lines changed

14 files changed

+158
-33
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
The Search API now supports a `show_collections` parameter for dataset results.
2+
When the parameter is set, each result includes a `collections` array showing the dataset’s parent and linked collections. Each entry includes `id`, `name`, and `alias`, for example:
3+
4+
```json
5+
"collections": [
6+
{
7+
"id": 11,
8+
"name": "My cool collection",
9+
"alias": "dvcb50a190"
10+
}
11+
]
12+
```

doc/sphinx-guides/source/api/search.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ type string Can be either "dataverse", "dataset", or "file". Multi
2929
subtree string The identifier of the Dataverse collection to which the search should be narrowed. The subtree of this Dataverse collection and all its children will be searched. Multiple "subtree" parameters can be used to include multiple Dataverse collections. For example, https://demo.dataverse.org/api/search?q=data&subtree=birds&subtree=cats .
3030
sort string The sort field. Supported values include "name" and "date". See example under "order".
3131
order string The order in which to sort. Can either be "asc" or "desc". For example, https://demo.dataverse.org/api/search?q=data&sort=name&order=asc
32-
per_page int The number of results to return per request. The default is 10. The max is 1000. See :ref:`iteration example <iteration-example>`.
32+
per_page int The number of results to return per request. The default is 10. The max is 1000. See :ref:`iteration example <iteration-example>`.
3333
start int A cursor for paging through search results. See :ref:`iteration example <iteration-example>`.
3434
show_relevance boolean Whether or not to show details of which fields were matched by the query. False by default. See :ref:`advanced search example <advancedsearch-example>`.
3535
show_facets boolean Whether or not to show facets that can be operated on by the "fq" parameter. False by default. See :ref:`advanced search example <advancedsearch-example>`.
@@ -41,6 +41,7 @@ metadata_fields string Includes the requested fields for each dataset in the
4141
geo_point string Latitude and longitude in the form ``geo_point=42.3,-71.1``. You must supply ``geo_radius`` as well. See also :ref:`geospatial-search`.
4242
geo_radius string Radial distance in kilometers from ``geo_point`` (which must be supplied as well) such as ``geo_radius=1.5``.
4343
show_type_counts boolean Whether or not to include total_count_per_object_type for types: Dataverse, Dataset, and Files.
44+
show_collections boolean Whether or not to include a list of Dataverse collections for each dataset search result.
4445
search_service string The name of the search service to use for this query. If omitted, the default search service will be used. For available search services, see :ref:`discovering-available-search-services`.
4546
================ ======= ===========
4647

@@ -794,7 +795,7 @@ Note: Configurable Search Services are an optional, experimental feature than ma
794795

795796
Example API endpoint: https://demo.dataverse.org/api/search/services
796797

797-
This endpoint returns a list of available search services, including their names, and display names. It also indicates the default search service.
798+
This endpoint returns a list of available search services, including their names, and display names. It also indicates the default search service.
798799

799800
Example response:
800801

src/main/java/edu/harvard/iq/dataverse/api/Search.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ public Response search(
7575
@QueryParam("geo_point") String geoPointRequested,
7676
@QueryParam("geo_radius") String geoRadiusRequested,
7777
@QueryParam("show_type_counts") boolean showTypeCounts,
78+
@QueryParam("show_collections") boolean showCollections,
7879
@QueryParam("search_service") String searchServiceName,
7980
@Context HttpServletResponse response
8081
) {
@@ -134,11 +135,11 @@ public Response search(
134135
List<String> totalFilterQueries = new ArrayList<>();
135136
totalFilterQueries.addAll(filterQueries);
136137
totalFilterQueries.add(SearchFields.TYPE + allTypes);
137-
138+
138139
try {
139-
140+
140141
SolrQueryResponse resp = searchService.search(requestUser, dataverseSubtrees, query, totalFilterQueries, null, null, 0,
141-
dataRelatedToMe, 1, false, null, null, false, false);
142+
dataRelatedToMe, 1, false, null, null, false, false, false);
142143
if (resp != null) {
143144
for (FacetCategory facetCategory : resp.getTypeFacetCategories()) {
144145
for (FacetLabel facetLabel : facetCategory.getFacetLabel()) {
@@ -193,11 +194,12 @@ public Response search(
193194
paginationStart,
194195
dataRelatedToMe,
195196
numResultsPerPage,
196-
queryEntities,
197+
queryEntities,
197198
geoPoint,
198199
geoRadius,
199200
showFacets, // facets are expensive, no need to ask for them if not requested
200-
showRelevance // no need for highlights unless requested either
201+
showRelevance, // no need for highlights unless requested either
202+
showCollections // same for collections
201203
);
202204
} catch (SearchException ex) {
203205
Throwable cause = ex;
@@ -284,15 +286,15 @@ public Response search(
284286
}
285287
}
286288

287-
289+
288290
@GET
289291
@Path("/services")
290292
public Response getSearchEngines() {
291293
Map<String, SearchService> availableEngines = searchServiceFactory.getAvailableServices();
292294
String defaultServiceName = JvmSettings.DEFAULT_SEARCH_SERVICE.lookupOptional().orElse(SearchServiceFactory.INTERNAL_SOLR_SERVICE_NAME);
293-
295+
294296
JsonArrayBuilder enginesArray = Json.createArrayBuilder();
295-
297+
296298
for (String engine : availableEngines.keySet()) {
297299
JsonObjectBuilder engineObject = Json.createObjectBuilder()
298300
.add("name", engine)
@@ -302,10 +304,10 @@ public Response getSearchEngines() {
302304
JsonObjectBuilder response = Json.createObjectBuilder()
303305
.add("services", enginesArray)
304306
.add("defaultService", defaultServiceName);
305-
307+
306308
return ok(response);
307309
}
308-
310+
309311
private User getUser(ContainerRequestContext crc) throws WrappedResponse {
310312
User userToExecuteSearchAs = GuestUser.get();
311313
try {

src/main/java/edu/harvard/iq/dataverse/mydata/DataRetrieverAPI.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,8 @@ private SolrQueryResponse getTotalCountsFromSolr(DataverseRequest dataverseReque
233233
null,
234234
null,
235235
false, // no need to request facets here ...
236-
false // ... same for highlights
236+
false, // ... same for highlights
237+
false // ... same for collections
237238
);
238239
} catch (SearchException ex) {
239240
logger.severe("Search for total counts failed with filter query");

src/main/java/edu/harvard/iq/dataverse/search/AbstractExternalSearchServiceBean.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public void setSettingsService(SettingsServiceBean settingsService) {
5050
* @throws Exception
5151
*/
5252
protected SolrQueryResponse postProcessResponse(String responseString, DataverseRequest dataverseRequest,
53-
boolean retrieveEntities, boolean addFacets, boolean addHighlights) throws Exception {
53+
boolean retrieveEntities, boolean addFacets, boolean addHighlights, boolean addCollections) throws Exception {
5454

5555
JsonObject responseObject = JsonUtil.getJsonObject(responseString);
5656
JsonArray resultsArray = responseObject.getJsonArray("results");
@@ -82,7 +82,7 @@ protected SolrQueryResponse postProcessResponse(String responseString, Dataverse
8282
// Execute Solr query
8383
SolrQueryResponse solrResponse = solrSearchService.search(dataverseRequest, null, solrQuery,
8484
Collections.emptyList(), null, null, 0, false, pids.size(), retrieveEntities, null, null, addFacets,
85-
addHighlights);
85+
addHighlights, addCollections);
8686

8787
// Reorder results based on distance, lowest values first
8888
List<SolrSearchResult> reorderedResults = solrResponse.getSolrSearchResults().stream()

src/main/java/edu/harvard/iq/dataverse/search/GetExternalSearchServiceBean.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public void setSolrSearchService(SearchService solrSearchService) {
4444
public SolrQueryResponse search(DataverseRequest dataverseRequest, List<Dataverse> dataverses, String query,
4545
List<String> filterQueries, String sortField, String sortOrder, int paginationStart,
4646
boolean onlyDataRelatedToMe, int numResultsPerPage, boolean retrieveEntities, String geoPoint,
47-
String geoRadius, boolean addFacets, boolean addHighlights) throws SearchException {
47+
String geoRadius, boolean addFacets, boolean addHighlights, boolean addCollections) throws SearchException {
4848

4949
String externalSearchUrl = settingsService.getValueForKey(SettingsServiceBean.Key.GetExternalSearchUrl);
5050
if (externalSearchUrl == null || externalSearchUrl.isEmpty()) {
@@ -53,7 +53,7 @@ public SolrQueryResponse search(DataverseRequest dataverseRequest, List<Datavers
5353

5454
// Prepare query parameters
5555
String queryParams = prepareQuery(query, paginationStart, numResultsPerPage, sortField, sortOrder,
56-
filterQueries, addHighlights, addFacets, onlyDataRelatedToMe, retrieveEntities, geoPoint, geoRadius);
56+
filterQueries, addHighlights, addCollections, addFacets, onlyDataRelatedToMe, retrieveEntities, geoPoint, geoRadius);
5757

5858
// Send GET request to external service
5959
try (Client client = ClientBuilder.newClient()) {
@@ -67,14 +67,14 @@ public SolrQueryResponse search(DataverseRequest dataverseRequest, List<Datavers
6767
// Parse response and process results
6868
String responseString = response.readEntity(String.class);
6969
logger.finest("External search returned: " + responseString);
70-
return postProcessResponse(responseString, dataverseRequest, retrieveEntities, addFacets, addHighlights);
70+
return postProcessResponse(responseString, dataverseRequest, retrieveEntities, addFacets, addHighlights, addCollections);
7171
} catch (Exception e) {
7272
throw new SearchException("Error parsing external search service response", e);
7373
}
7474
}
7575

7676
private String prepareQuery(String query, int paginationStart, int numResultsPerPage, String sortField,
77-
String sortOrder, List<String> filterQueries, boolean addHighlights, boolean addFacets,
77+
String sortOrder, List<String> filterQueries, boolean addHighlights, boolean addCollections, boolean addFacets,
7878
boolean onlyDataRelatedToMe, boolean retrieveEntities, String geoPoint, String geoRadius) {
7979
StringBuilder queryParams = new StringBuilder();
8080
queryParams.append("q=").append(URLEncoder.encode(query, StandardCharsets.UTF_8));
@@ -94,6 +94,7 @@ private String prepareQuery(String query, int paginationStart, int numResultsPer
9494
}
9595

9696
queryParams.append("&show_relevance=").append(addHighlights);
97+
queryParams.append("&show_collections=").append(addCollections);
9798
queryParams.append("&show_facets=").append(addFacets);
9899
queryParams.append("&show_entity_ids=true");
99100
queryParams.append("&show_api_urls=true");

src/main/java/edu/harvard/iq/dataverse/search/GoldenOldiesSearchServiceBean.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public String getDisplayName() {
4949
* @param geoRadius e.g. "5"
5050
* @param addFacets boolean
5151
* @param addHighlights boolean
52+
* @param addCollections boolean
5253
* @return
5354
* @throws SearchException
5455
*/
@@ -67,7 +68,8 @@ public SolrQueryResponse search(
6768
String geoPoint,
6869
String geoRadius,
6970
boolean addFacets,
70-
boolean addHighlights
71+
boolean addHighlights,
72+
boolean addCollections
7173
) throws SearchException {
7274

7375
// Execute the query using SolrSearchService

src/main/java/edu/harvard/iq/dataverse/search/OddlyEnoughSearchServiceBean.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public String getDisplayName() {
4949
* @param geoRadius e.g. "5"
5050
* @param addFacets boolean
5151
* @param addHighlights boolean
52+
* @param addCollections boolean
5253
* @return
5354
* @throws SearchException
5455
*/
@@ -67,12 +68,13 @@ public SolrQueryResponse search(
6768
String geoPoint,
6869
String geoRadius,
6970
boolean addFacets,
70-
boolean addHighlights
71+
boolean addHighlights,
72+
boolean addCollections
7173
) throws SearchException {
7274

7375
logger.info("Search query: " + query + "handled by OddlyEnough search service");
7476
// Execute the query using SolrSearchService
75-
SolrQueryResponse queryResponse = solrSearchService.search(dataverseRequest, dataverses, query, filterQueries, sortField, sortOrder, 0, onlyDatatRelatedToMe, 1000, retrieveEntities, geoPoint, geoRadius, addFacets, addHighlights);
77+
SolrQueryResponse queryResponse = solrSearchService.search(dataverseRequest, dataverses, query, filterQueries, sortField, sortOrder, 0, onlyDatatRelatedToMe, 1000, retrieveEntities, geoPoint, geoRadius, addFacets, addHighlights, addCollections);
7678

7779
// Process the results
7880
List<SolrSearchResult> solrSearchResults = queryResponse.getSolrSearchResults();

src/main/java/edu/harvard/iq/dataverse/search/PostExternalSearchServiceBean.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ private JsonObject prepareQuery(String query, int paginationStart, int numResult
4545
public SolrQueryResponse search(DataverseRequest dataverseRequest, List<Dataverse> dataverses, String query,
4646
List<String> filterQueries, String sortField, String sortOrder, int paginationStart,
4747
boolean onlyDataRelatedToMe, int numResultsPerPage, boolean retrieveEntities, String geoPoint,
48-
String geoRadius, boolean addFacets, boolean addHighlights) throws SearchException {
48+
String geoRadius, boolean addFacets, boolean addHighlights, boolean addCollections) throws SearchException {
4949

5050
String externalSearchUrl = settingsService.getValueForKey(SettingsServiceBean.Key.PostExternalSearchUrl);
5151
if (externalSearchUrl == null || externalSearchUrl.isEmpty()) {
@@ -68,7 +68,7 @@ public SolrQueryResponse search(DataverseRequest dataverseRequest, List<Datavers
6868
// Parse response and process results
6969
String responseString = response.readEntity(String.class);
7070
logger.fine("External search returned: " + responseString);
71-
return postProcessResponse(responseString, dataverseRequest, retrieveEntities, addFacets, addHighlights);
71+
return postProcessResponse(responseString, dataverseRequest, retrieveEntities, addFacets, addHighlights, addCollections);
7272
} catch (Exception e) {
7373
throw new SearchException("Error parsing external search service response", e);
7474
}

src/main/java/edu/harvard/iq/dataverse/search/SearchIncludeFragment.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ The real issue here (https://github.com/IQSS/dataverse/issues/7304) is caused
361361
DataverseRequest dataverseRequest = getDataverseRequest();
362362
List<Dataverse> dataverses = new ArrayList<>();
363363
dataverses.add(dataverse);
364-
solrQueryResponse = searchServiceFactory.getDefaultSearchService().search(dataverseRequest, dataverses, queryToPassToSolr, filterQueriesFinal, sortField, sortOrder.toString(), paginationStart, onlyDataRelatedToMe, numRows, false, null, null, !isFacetsDisabled(), true);
364+
solrQueryResponse = searchServiceFactory.getDefaultSearchService().search(dataverseRequest, dataverses, queryToPassToSolr, filterQueriesFinal, sortField, sortOrder.toString(), paginationStart, onlyDataRelatedToMe, numRows, false, null, null, !isFacetsDisabled(), true, false);
365365
if (solrQueryResponse.hasError()){
366366
logger.info(solrQueryResponse.getError());
367367
setSolrErrorEncountered(true);
@@ -416,7 +416,7 @@ The real issue here (https://github.com/IQSS/dataverse/issues/7304) is caused
416416
logger.fine("second pass query: " + queryToPassToSolr);
417417
logger.fine("second pass filter query: "+filterQueriesFinalSecondPass.toString());
418418

419-
solrQueryResponseSecondPass = searchServiceFactory.getDefaultSearchService().search(dataverseRequest, dataverses, queryToPassToSolr, filterQueriesFinalSecondPass, null, sortOrder.toString(), 0, onlyDataRelatedToMe, 1, false, null, null, false, false);
419+
solrQueryResponseSecondPass = searchServiceFactory.getDefaultSearchService().search(dataverseRequest, dataverses, queryToPassToSolr, filterQueriesFinalSecondPass, null, sortOrder.toString(), 0, onlyDataRelatedToMe, 1, false, null, null, false, false, false);
420420

421421
if (solrQueryResponseSecondPass != null) {
422422

@@ -1561,7 +1561,7 @@ public boolean canSeeCurationStatus(Long datasetId) {
15611561
return canPublishDataset(datasetId);
15621562
}
15631563
}
1564-
1564+
15651565
public enum SortOrder {
15661566

15671567
asc, desc

0 commit comments

Comments
 (0)