diff --git a/api/src/main/kotlin/edu/wgu/osmt/HasAllPaginated.kt b/api/src/main/kotlin/edu/wgu/osmt/HasAllPaginated.kt index 530095f08..81eafc3f5 100644 --- a/api/src/main/kotlin/edu/wgu/osmt/HasAllPaginated.kt +++ b/api/src/main/kotlin/edu/wgu/osmt/HasAllPaginated.kt @@ -6,6 +6,7 @@ import edu.wgu.osmt.db.PublishStatus import edu.wgu.osmt.elasticsearch.FindsAllByPublishStatus import edu.wgu.osmt.elasticsearch.OffsetPageable import edu.wgu.osmt.elasticsearch.PaginatedLinks +import org.springframework.data.elasticsearch.core.SearchHits import org.springframework.http.HttpEntity import org.springframework.http.HttpHeaders import org.springframework.http.ResponseEntity @@ -48,10 +49,11 @@ interface HasAllPaginated { val sortEnum: SortOrder = sortOrderCompanion.forValueOrDefault(sort) val pageable = OffsetPageable(from, size, sortEnum.sort) - val searchHits = elasticRepository.findAllFilteredByPublishStatus(publishStatuses, pageable) + val searchHits: SearchHits = elasticRepository.findAllFilteredByPublishStatus(publishStatuses, pageable) val responseHeaders = HttpHeaders() - responseHeaders.add("X-Total-Count", searchHits.totalHits.toString()) + val countAllFilteredByPublishStatus: Long = elasticRepository.countAllFilteredByPublishStatus(publishStatuses, pageable) + responseHeaders.add("X-Total-Count", countAllFilteredByPublishStatus.toString()) // build up current uri with path and params uriComponentsBuilder diff --git a/api/src/main/kotlin/edu/wgu/osmt/elasticsearch/FindsAllByPublishStatus.kt b/api/src/main/kotlin/edu/wgu/osmt/elasticsearch/FindsAllByPublishStatus.kt index 927e84f60..2bd6d2891 100644 --- a/api/src/main/kotlin/edu/wgu/osmt/elasticsearch/FindsAllByPublishStatus.kt +++ b/api/src/main/kotlin/edu/wgu/osmt/elasticsearch/FindsAllByPublishStatus.kt @@ -14,6 +14,19 @@ interface FindsAllByPublishStatus { val javaClass: Class fun findAllFilteredByPublishStatus(publishStatus: Set, pageable: Pageable): SearchHits { + val nsq: NativeSearchQueryBuilder = buildQuery(pageable, publishStatus) + return elasticSearchTemplate.search(nsq.build(), javaClass) + } + + fun countAllFilteredByPublishStatus(publishStatus: Set, pageable: Pageable): Long { + val nsq: NativeSearchQueryBuilder = buildQuery(pageable, publishStatus) + return elasticSearchTemplate.count(nsq.build(), javaClass) + } + + fun buildQuery( + pageable: Pageable, + publishStatus: Set + ): NativeSearchQueryBuilder { val nsq: NativeSearchQueryBuilder = NativeSearchQueryBuilder().withPageable(pageable) nsq.withQuery(QueryBuilders.matchAllQuery()) nsq.withFilter( @@ -22,8 +35,9 @@ interface FindsAllByPublishStatus { "publishStatus", publishStatus.map { ps -> ps.toString() } ) - ) ) - return elasticSearchTemplate.search(nsq.build(), javaClass) + ) + ) + return nsq } } diff --git a/api/src/main/kotlin/edu/wgu/osmt/elasticsearch/SearchController.kt b/api/src/main/kotlin/edu/wgu/osmt/elasticsearch/SearchController.kt index dc3e54d87..d7cc9287b 100644 --- a/api/src/main/kotlin/edu/wgu/osmt/elasticsearch/SearchController.kt +++ b/api/src/main/kotlin/edu/wgu/osmt/elasticsearch/SearchController.kt @@ -123,8 +123,14 @@ class SearchController @Autowired constructor( sort?.let { uriComponentsBuilder.queryParam(RoutePaths.QueryParams.SORT, it) } collectionId?.let { uriComponentsBuilder.queryParam(RoutePaths.QueryParams.COLLECTION_ID, it) } + val countByApiSearch = richSkillEsRepo.countByApiSearch( + apiSearch, + publishStatuses, + pageable, + collectionId + ) val responseHeaders = HttpHeaders() - responseHeaders.add("X-Total-Count", searchHits.totalHits.toString()) + responseHeaders.add("X-Total-Count", countByApiSearch.toString()) PaginatedLinks( pageable, diff --git a/api/src/main/kotlin/edu/wgu/osmt/richskill/RichSkillEsRepo.kt b/api/src/main/kotlin/edu/wgu/osmt/richskill/RichSkillEsRepo.kt index ec861abf6..e644c0543 100644 --- a/api/src/main/kotlin/edu/wgu/osmt/richskill/RichSkillEsRepo.kt +++ b/api/src/main/kotlin/edu/wgu/osmt/richskill/RichSkillEsRepo.kt @@ -35,6 +35,12 @@ interface CustomRichSkillQueries : FindsAllByPublishStatus { pageable: Pageable = Pageable.unpaged(), collectionId: String? = null ): SearchHits + fun countByApiSearch( + apiSearch: ApiSearch, + publishStatus: Set = PublishStatus.publishStatusSet, + pageable: Pageable = Pageable.unpaged(), + collectionId: String? = null + ): Long fun findSimilar(apiSimilaritySearch: ApiSimilaritySearch): SearchHits @@ -207,6 +213,28 @@ class CustomRichSkillQueriesImpl @Autowired constructor(override val elasticSear pageable: Pageable, collectionId: String? ): SearchHits { + val nsq: NativeSearchQueryBuilder = buildQuery(pageable, publishStatus, apiSearch, collectionId) + + return elasticSearchTemplate.search(nsq.build(), RichSkillDoc::class.java) + } + + override fun countByApiSearch( + apiSearch: ApiSearch, + publishStatus: Set, + pageable: Pageable, + collectionId: String? + ): Long { + val nsq: NativeSearchQueryBuilder = buildQuery(pageable, publishStatus, apiSearch, collectionId) + + return elasticSearchTemplate.count(nsq.build(), RichSkillDoc::class.java) + } + + fun buildQuery( + pageable: Pageable, + publishStatus: Set, + apiSearch: ApiSearch, + collectionId: String? + ): NativeSearchQueryBuilder { val nsq: NativeSearchQueryBuilder = NativeSearchQueryBuilder().withPageable(pageable) val bq = boolQuery() @@ -236,7 +264,7 @@ class CustomRichSkillQueriesImpl @Autowired constructor(override val elasticSear bq.must( nestedQuery( RichSkillDoc::collections.name, - QueryBuilders.boolQuery().must(QueryBuilders.matchQuery(collectionsUuid, collectionId)), + boolQuery().must(matchQuery(collectionsUuid, collectionId)), ScoreMode.Avg ) ) @@ -246,9 +274,9 @@ class CustomRichSkillQueriesImpl @Autowired constructor(override val elasticSear generateBoolQueriesFromApiSearch(bq, apiSearch.advanced) if (collectionId.isNullOrBlank()) { - apiSearch.advanced.collectionName?.let { + apiSearch?.advanced.collectionName?.let { bq.must( - QueryBuilders.nestedQuery( + nestedQuery( RichSkillDoc::collections.name, simpleQueryStringQuery(it).field("collections.name.raw").defaultOperator(Operator.AND), ScoreMode.Avg @@ -257,9 +285,9 @@ class CustomRichSkillQueriesImpl @Autowired constructor(override val elasticSear } } else { bq.must( - QueryBuilders.nestedQuery( + nestedQuery( RichSkillDoc::collections.name, - QueryBuilders.boolQuery().must(QueryBuilders.matchQuery(collectionsUuid, collectionId)), + boolQuery().must(matchQuery(collectionsUuid, collectionId)), ScoreMode.Avg ) ) @@ -279,18 +307,17 @@ class CustomRichSkillQueriesImpl @Autowired constructor(override val elasticSear } if (!collectionId.isNullOrBlank()) { bq.must( - QueryBuilders.nestedQuery( + nestedQuery( RichSkillDoc::collections.name, - QueryBuilders.boolQuery() - .must(QueryBuilders.matchQuery(collectionsUuid, collectionId)), + boolQuery() + .must(matchQuery(collectionsUuid, collectionId)), ScoreMode.Avg ) ) } } - - return elasticSearchTemplate.search(nsq.build(), RichSkillDoc::class.java) + return nsq } override fun findSimilar(apiSimilaritySearch: ApiSimilaritySearch): SearchHits { diff --git a/ui/src/app/richskill/list/skills-list.component.ts b/ui/src/app/richskill/list/skills-list.component.ts index 6030a239e..e5b8e45eb 100644 --- a/ui/src/app/richskill/list/skills-list.component.ts +++ b/ui/src/app/richskill/list/skills-list.component.ts @@ -21,11 +21,6 @@ import {ButtonAction} from "../../auth/auth-roles"; templateUrl: "./skills-list.component.html" }) export class SkillsListComponent extends QuickLinksHelper { - /* - * In default configuration, ElasticSearch has an upper limit of returning 10000 elements. For a short-term - * usability fix, we're simply going to add a "+" character when displaying 10000 (or more) total hits. - */ - readonly upperLimit = 10000 from = 0 size = 50 @@ -72,7 +67,7 @@ export class SkillsListComponent extends QuickLinksHelper { get skillCountLabel(): string { if (this.totalCount > 0) { - return `${this.totalCount}${this.totalCount >= this.upperLimit ? "+" : ""} RSD${this.totalCount > 1 ? "s" : ""}` + return `${this.totalCount} RSD${this.totalCount > 1 ? "s" : ""}` } return `0 RSDs` }