use of org.snomed.snowstorm.core.data.services.pojo.PageWithBucketAggregations in project snowstorm by IHTSDO.
the class DescriptionController method findBrowserDescriptions.
@ApiOperation(value = "Search for concept descriptions.", notes = "The Accept-Language header is used to specify the user's preferred language, 'en' is always added as a fallback if not already included in the list. " + "Each language is used as an optional clause for matching and will include the correct character folding behaviour for that language. " + "The Accept-Language header list is also used to chose the best translated FSN and PT values in the response.")
@RequestMapping(value = "browser/{branch}/descriptions", method = RequestMethod.GET)
@JsonView(value = View.Component.class)
public Page<BrowserDescriptionSearchResult> findBrowserDescriptions(@PathVariable String branch, @RequestParam(required = false) String term, @RequestParam(required = false) Boolean active, @RequestParam(required = false) Set<String> module, @ApiParam(value = "Set of two character language codes to match. " + "The English language code 'en' will not be added automatically, in contrast to the Accept-Language header which always includes it. " + "Accept-Language header still controls result FSN and PT language selection.") @RequestParam(required = false) Set<String> language, @ApiParam(value = "Set of description type ids to use include. Defaults to any. " + "Pick descendants of '900000000000446008 | Description type (core metadata concept) |'. " + "Examples: 900000000000003001 (FSN), 900000000000013009 (Synonym), 900000000000550004 (Definition)") @RequestParam(required = false) Set<Long> type, @Deprecated @RequestParam(required = false) String semanticTag, @ApiParam(value = "Set of semantic tags.") @RequestParam(required = false) Set<String> semanticTags, @ApiParam(value = "Set of description language reference sets. The description must be preferred in at least one of these to match.") @RequestParam(required = false) Set<Long> preferredIn, @ApiParam(value = "Set of description language reference sets. The description must be acceptable in at least one of these to match.") @RequestParam(required = false) Set<Long> acceptableIn, @ApiParam(value = "Set of description language reference sets. The description must be preferred OR acceptable in at least one of these to match.") @RequestParam(required = false) Set<Long> preferredOrAcceptableIn, @RequestParam(required = false) Boolean conceptActive, @RequestParam(required = false) String conceptRefset, @RequestParam(defaultValue = "false") boolean groupByConcept, @RequestParam(defaultValue = "STANDARD") DescriptionService.SearchMode searchMode, @RequestParam(defaultValue = "0") int offset, @RequestParam(defaultValue = "50") int limit, @RequestHeader(value = "Accept-Language", defaultValue = Config.DEFAULT_ACCEPT_LANG_HEADER) String acceptLanguageHeader) throws TooCostlyException {
branch = BranchPathUriUtil.decodePath(branch);
PageRequest pageRequest = ControllerHelper.getPageRequest(offset, limit);
List<LanguageDialect> languageDialects = ControllerHelper.parseAcceptLanguageHeaderWithDefaultFallback(acceptLanguageHeader);
PageWithBucketAggregations<Description> page = descriptionService.findDescriptionsWithAggregations(branch, new DescriptionCriteria().term(term).active(active).modules(module).searchLanguageCodes(language).type(type).semanticTag(semanticTag).semanticTags(semanticTags).preferredIn(preferredIn).acceptableIn(acceptableIn).preferredOrAcceptableIn(preferredOrAcceptableIn).conceptActive(conceptActive).conceptRefset(conceptRefset).groupByConcept(groupByConcept).searchMode(searchMode), // Page
pageRequest);
Set<String> conceptIds = page.getContent().stream().map(Description::getConceptId).collect(Collectors.toSet());
Map<String, ConceptMini> conceptMinis = conceptService.findConceptMinis(branch, conceptIds, languageDialects).getResultsMap();
List<BrowserDescriptionSearchResult> results = new ArrayList<>();
page.getContent().forEach(d -> results.add(new BrowserDescriptionSearchResult(d.getTerm(), d.isActive(), d.getLanguageCode(), d.getModuleId(), conceptMinis.get(d.getConceptId()))));
PageWithBucketAggregations<BrowserDescriptionSearchResult> pageWithBucketAggregations = new PageWithBucketAggregations<>(results, page.getPageable(), page.getTotalElements(), page.getBuckets());
addBucketConcepts(branch, languageDialects, pageWithBucketAggregations);
addLanguageNames(pageWithBucketAggregations);
return pageWithBucketAggregations;
}
use of org.snomed.snowstorm.core.data.services.pojo.PageWithBucketAggregations in project snowstorm by IHTSDO.
the class MultiSearchController method findDescriptionsReferenceSets.
@ApiOperation("Search descriptions across multiple Code Systems returning reference set membership bucket.")
@RequestMapping(value = "multisearch/descriptions/referencesets", method = RequestMethod.GET)
@JsonView(value = View.Component.class)
public Page<BrowserDescriptionSearchResult> findDescriptionsReferenceSets(// Required!
@RequestParam String term, @RequestParam(required = false) Boolean active, @RequestParam(required = false) Collection<String> module, @ApiParam(value = "Set of two character language codes to match. " + "The English language code 'en' will not be added automatically, in contrast to the Accept-Language header which always includes it. " + "Accept-Language header still controls result FSN and PT language selection.") @RequestParam(required = false) Set<String> language, @ApiParam(value = "Set of description types to include. Pick descendants of '900000000000446008 | Description type (core metadata concept) |'.") @RequestParam(required = false) Set<Long> type, @RequestParam(required = false) Boolean conceptActive, @RequestParam(defaultValue = "ALL_PUBLISHED_CONTENT") ContentScope contentScope, @RequestParam(defaultValue = "0") int offset, @RequestParam(defaultValue = "50") int limit, @RequestHeader(value = "Accept-Language", defaultValue = Config.DEFAULT_ACCEPT_LANG_HEADER) String acceptLanguageHeader) throws TooCostlyException {
TimerUtil timer = new TimerUtil("MultiSearch - Descriptions with Reference Set buckets");
DescriptionCriteria descriptionCriteria = new DescriptionCriteria().term(term).active(active).modules(module).searchLanguageCodes(language).type(type).conceptActive(conceptActive);
PageRequest pageRequest = ControllerHelper.getPageRequest(offset, limit);
PageWithBucketAggregations<Description> page = multiSearchService.findDescriptionsReferenceSets(descriptionCriteria, pageRequest);
timer.checkpoint("description search with reference sets");
Map<String, List<Description>> branchDescriptions = new HashMap<>();
Map<String, List<String>> branchConceptIds = new HashMap<>();
for (Description description : page) {
branchDescriptions.computeIfAbsent(description.getPath(), s -> new ArrayList<>()).add(description);
branchConceptIds.computeIfAbsent(description.getPath(), s -> new ArrayList<>()).add(description.getConceptId());
}
List<LanguageDialect> languageDialects = ControllerHelper.parseAcceptLanguageHeaderWithDefaultFallback(acceptLanguageHeader);
Map<String, ConceptMini> conceptMiniMap = new HashMap<>();
for (String branchPath : branchConceptIds.keySet()) {
conceptMiniMap.putAll(conceptService.findConceptMinis(branchPath, branchConceptIds.get(branchPath), languageDialects).getResultsMap());
timer.checkpoint("Join concepts from " + branchPath);
}
timer.finish();
List<BrowserDescriptionSearchResult> results = new ArrayList<>();
page.getContent().forEach(d -> results.add(new BrowserDescriptionSearchResult(d.getTerm(), d.isActive(), d.getLanguageCode(), d.getModuleId(), conceptMiniMap.get(d.getConceptId()))));
PageWithBucketAggregations<BrowserDescriptionSearchResult> pageWithBucketAggregations = new PageWithBucketAggregations<>(results, page.getPageable(), page.getTotalElements(), page.getBuckets());
return pageWithBucketAggregations;
}
use of org.snomed.snowstorm.core.data.services.pojo.PageWithBucketAggregations in project snowstorm by IHTSDO.
the class DescriptionService method findDescriptionsWithAggregations.
public PageWithBucketAggregations<Description> findDescriptionsWithAggregations(String path, DescriptionCriteria criteria, PageRequest pageRequest) throws TooCostlyException {
TimerUtil timer = new TimerUtil("Search", Level.INFO, 5, new TimerUtil("Search DEBUG", Level.DEBUG));
final BranchCriteria branchCriteria = versionControlHelper.getBranchCriteria(path);
timer.checkpoint("Build branch criteria");
// Fetch all matching description and concept ids
// ids of concepts where all descriptions and concept criteria are met
DescriptionMatches descriptionMatches = findDescriptionAndConceptIds(criteria, Collections.EMPTY_SET, branchCriteria, timer);
BoolQueryBuilder descriptionQuery = descriptionMatches.getDescriptionQuery();
// Apply concept and acceptability filtering for final search
BoolQueryBuilder descriptionFilter = boolQuery();
descriptionFilter.must(termsQuery(Description.Fields.DESCRIPTION_ID, descriptionMatches.getMatchedDescriptionIds()));
// Start fetching aggregations..
List<Aggregation> allAggregations = new ArrayList<>();
Set<Long> conceptIds = descriptionMatches.getMatchedConceptIds();
// Fetch FSN semantic tag aggregation
BoolQueryBuilder fsnClauses = boolQuery();
String semanticTag = criteria.getSemanticTag();
Set<String> semanticTags = criteria.getSemanticTags();
boolean semanticTagFiltering = !Strings.isNullOrEmpty(semanticTag) || !CollectionUtils.isEmpty(semanticTags);
Set<String> allSemanticTags = new HashSet<>();
if (semanticTagFiltering) {
if (!Strings.isNullOrEmpty(semanticTag)) {
allSemanticTags.add(semanticTag);
}
if (!CollectionUtils.isEmpty(semanticTags)) {
allSemanticTags.addAll(semanticTags);
}
fsnClauses.must(termsQuery(Description.Fields.TAG, allSemanticTags));
}
NativeSearchQueryBuilder fsnQueryBuilder = new NativeSearchQueryBuilder().withQuery(fsnClauses.must(branchCriteria.getEntityBranchCriteria(Description.class)).must(termsQuery(Description.Fields.ACTIVE, true)).must(termsQuery(Description.Fields.TYPE_ID, Concepts.FSN)).must(termsQuery(Description.Fields.CONCEPT_ID, conceptIds))).addAggregation(AggregationBuilders.terms("semanticTags").field(Description.Fields.TAG).size(AGGREGATION_SEARCH_SIZE));
if (!semanticTagFiltering) {
fsnQueryBuilder.withPageable(PAGE_OF_ONE);
SearchHits<Description> semanticTagResults = elasticsearchTemplate.search(fsnQueryBuilder.build(), Description.class);
allAggregations.add(semanticTagResults.getAggregations().get("semanticTags"));
timer.checkpoint("Semantic tag aggregation");
} else {
// Apply semantic tag filter
fsnQueryBuilder.withPageable(LARGE_PAGE).withFields(Description.Fields.CONCEPT_ID);
Set<Long> conceptSemanticTagMatches = new LongOpenHashSet();
if (allSemanticTags.size() == 1) {
try (SearchHitsIterator<Description> descriptionStream = elasticsearchTemplate.searchForStream(fsnQueryBuilder.build(), Description.class)) {
descriptionStream.forEachRemaining(hit -> conceptSemanticTagMatches.add(parseLong(hit.getContent().getConceptId())));
}
allAggregations.add(new SimpleAggregation("semanticTags", allSemanticTags.iterator().next(), conceptSemanticTagMatches.size()));
} else {
SearchHits<Description> semanticTagResults = elasticsearchTemplate.search(fsnQueryBuilder.build(), Description.class);
semanticTagResults.stream().forEach((hit -> conceptSemanticTagMatches.add(parseLong(hit.getContent().getConceptId()))));
allAggregations.add(semanticTagResults.getAggregations().get("semanticTags"));
}
conceptIds = conceptSemanticTagMatches;
}
// Fetch concept refset membership aggregation
SearchHits<ReferenceSetMember> membershipResults = elasticsearchTemplate.search(new NativeSearchQueryBuilder().withQuery(boolQuery().must(branchCriteria.getEntityBranchCriteria(ReferenceSetMember.class)).must(termsQuery(ReferenceSetMember.Fields.ACTIVE, true)).filter(termsQuery(ReferenceSetMember.Fields.REFERENCED_COMPONENT_ID, conceptIds))).withPageable(PAGE_OF_ONE).addAggregation(AggregationBuilders.terms("membership").field(ReferenceSetMember.Fields.REFSET_ID)).build(), ReferenceSetMember.class);
allAggregations.add(membershipResults.getAggregations().get("membership"));
timer.checkpoint("Concept refset membership aggregation");
// Perform final paged description search with description property aggregations
descriptionFilter.must(termsQuery(Description.Fields.CONCEPT_ID, conceptIds));
final NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder().withQuery(descriptionQuery.filter(descriptionFilter)).addAggregation(AggregationBuilders.terms("module").field(Description.Fields.MODULE_ID)).addAggregation(AggregationBuilders.terms("language").field(Description.Fields.LANGUAGE_CODE)).withPageable(pageRequest);
NativeSearchQuery aggregateQuery = addTermSort(queryBuilder.build());
aggregateQuery.setTrackTotalHits(true);
SearchHits<Description> descriptions = elasticsearchTemplate.search(aggregateQuery, Description.class);
allAggregations.addAll(descriptions.getAggregations().asList());
timer.checkpoint("Fetch descriptions including module and language aggregations");
timer.finish();
// Merge aggregations
return PageWithBucketAggregationsFactory.createPage(descriptions, new Aggregations(allAggregations), pageRequest);
}
use of org.snomed.snowstorm.core.data.services.pojo.PageWithBucketAggregations in project snowstorm by IHTSDO.
the class MultiSearchService method findDescriptionsReferenceSets.
public PageWithBucketAggregations<Description> findDescriptionsReferenceSets(DescriptionCriteria criteria, PageRequest pageRequest) {
// all search results are required to determine total refset bucket membership
SearchHits<Description> allSearchHits = findDescriptionsHelper(criteria, null);
// paged results are required for the list of descriptions returned
SearchHits<Description> searchHits = findDescriptionsHelper(criteria, pageRequest);
List<Aggregation> allAggregations = new ArrayList<>();
Set<Long> conceptIds = new HashSet<>();
for (SearchHit<Description> desc : allSearchHits) {
conceptIds.add(Long.parseLong(desc.getContent().getConceptId()));
}
// Fetch concept refset membership aggregation
SearchHits<ReferenceSetMember> membershipResults = elasticsearchTemplate.search(new NativeSearchQueryBuilder().withQuery(boolQuery().must(termsQuery(ReferenceSetMember.Fields.ACTIVE, true)).filter(termsQuery(ReferenceSetMember.Fields.REFERENCED_COMPONENT_ID, conceptIds))).withPageable(PageRequest.of(0, 1)).addAggregation(AggregationBuilders.terms("membership").field(ReferenceSetMember.Fields.REFSET_ID).size(AGGREGATION_SEARCH_SIZE)).build(), ReferenceSetMember.class);
allAggregations.add(membershipResults.getAggregations().get("membership"));
PageWithBucketAggregations<Description> page = PageWithBucketAggregationsFactory.createPage(searchHits, new Aggregations(allAggregations), pageRequest);
return page;
}
Aggregations