use of org.snomed.snowstorm.core.data.domain.ConceptMini 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.domain.ConceptMini in project snowstorm by IHTSDO.
the class MRCMService method retrieveConceptModelAttributeHierarchy.
public ConceptMini retrieveConceptModelAttributeHierarchy(String branch, List<LanguageDialect> languageDialects) {
logger.info("Loading concept model attribute hierarchy.");
TimerUtil timer = new TimerUtil("attribute-tree", Level.INFO);
String topId = Concepts.CONCEPT_MODEL_ATTRIBUTE;
long topIdLong = parseLong(topId);
// Load all attributes including terms
List<ConceptMini> allAttributes = ecl("<<" + topId, branch, languageDialects);
timer.checkpoint("load all with terms");
Map<Long, ConceptMini> attributeMap = allAttributes.stream().collect(Collectors.toMap(ConceptMini::getConceptIdAsLong, Function.identity()));
if (!attributeMap.containsKey(topIdLong)) {
throw new IllegalStateException("Concept not found: " + topId + " | Concept model attribute (attribute) |.");
}
Set<Long> remainingAttributes = new HashSet<>(attributeMap.keySet());
remainingAttributes.remove(topIdLong);
BranchCriteria branchCriteria = versionControlHelper.getBranchCriteria(branch);
NativeSearchQueryBuilder queryConceptQuery = new NativeSearchQueryBuilder().withQuery(boolQuery().must(branchCriteria.getEntityBranchCriteria(QueryConcept.class)).must(termQuery(QueryConcept.Fields.STATED, false)).filter(termsQuery(QueryConcept.Fields.CONCEPT_ID, remainingAttributes))).withFields(QueryConcept.Fields.CONCEPT_ID, QueryConcept.Fields.PARENTS).withPageable(LARGE_PAGE);
try (SearchHitsIterator<QueryConcept> queryConcepts = elasticsearchTemplate.searchForStream(queryConceptQuery.build(), QueryConcept.class)) {
queryConcepts.forEachRemaining(hit -> {
for (Long parent : hit.getContent().getParents()) {
ConceptMini parentMini = attributeMap.get(parent);
if (parentMini.getExtraFields() == null || parentMini.getExtraFields().get(CHILDREN) == null) {
parentMini.addExtraField(CHILDREN, new ArrayList<>());
}
@SuppressWarnings("unchecked") List<ConceptMini> children = (List<ConceptMini>) parentMini.getExtraFields().get(CHILDREN);
children.add(attributeMap.get(hit.getContent().getConceptIdL()));
children.sort(Comparator.comparing(ConceptMini::getFsnTerm));
}
});
}
timer.finish();
return attributeMap.get(topIdLong);
}
use of org.snomed.snowstorm.core.data.domain.ConceptMini in project snowstorm by IHTSDO.
the class FHIRValueSetProvider method validateCode.
private Parameters validateCode(IdType id, UriType urlType, StringType codeSystem, CodeType code, String display, StringType version, DateTimeType date, Coding coding, Coding codeableConcept, String context, BooleanType abstractBool, String displayLanguage, List<LanguageDialect> languageDialects) throws FHIROperationException {
String url = urlType == null ? null : urlType.primitiveValue();
doParameterValidation(url, codeSystem, code, coding, codeableConcept, context, display, date, version, abstractBool);
// Can we get a codeSystem from the URL?
if (url != null && url.startsWith(SNOMED_URI) && url.indexOf("?") > SNOMED_URI.length()) {
if (codeSystem != null) {
throw new FHIROperationException(IssueType.INVARIANT, "Cannot handle CodeSystem defined via both url and codeSystem parameter");
}
codeSystem = new StringType(url.substring(0, url.indexOf("?")));
}
if (version != null) {
if (codeSystem == null) {
codeSystem = new StringType(SNOMED_URI + "/version/" + version.toString());
} else {
fhirHelper.append(codeSystem, "/version/" + version.toString());
}
}
// From either a saved VS instance or some implcit url, can we recover some ECL?
String ecl = getECL(id, url == null ? null : url);
if (ecl != null) {
String conceptId = fhirHelper.recoverConceptId(code, coding);
BranchPath branchPath = fhirHelper.getBranchPathFromURI(codeSystem);
// Construct ECL to find the intersection of these two sets
String intersectionEcl = conceptId + " AND (" + ecl + ")";
Page<ConceptMini> result = fhirHelper.eclSearch(intersectionEcl, null, null, languageDialects, branchPath, FHIRHelper.SINGLE_ITEM_PAGE);
if (result.getContent().size() == 1) {
ConceptMini concept = result.getContent().get(0);
if (!concept.getConceptId().equals(conceptId)) {
throw new FHIROperationException(IssueType.PROCESSING, "ECL recovered an unexpected concept id (" + concept.getConceptId() + ") using " + intersectionEcl);
}
Concept fullConcept = conceptService.find(conceptId, languageDialects, branchPath.toString());
return paramMapper.mapToFHIR(fullConcept, display);
} else {
// Now it might be that in this case we do not have this ValueSet loaded at all - or it's been
// defined or the substrate has changed such that it has no members. MAINT-1261 refers
result = fhirHelper.eclSearch(ecl, null, null, languageDialects, branchPath, FHIRHelper.SINGLE_ITEM_PAGE);
if (result.getContent().size() == 0) {
throw new FHIROperationException(IssueType.PROCESSING, "Concept not found and additionally the Valueset contains no members when expanded against the specified substrate. Check any relevant reference set is actually loaded. ECL = " + ecl + ", branch path = " + branchPath);
}
return paramMapper.conceptNotFound();
}
} else {
// TODO We have some sort of enumerated valueset saved, we need to just search through the members
throw new FHIROperationException(IssueType.NOTSUPPORTED, "Validating code against enumerated ValueSets has still to be implemented");
}
}
use of org.snomed.snowstorm.core.data.domain.ConceptMini in project snowstorm by IHTSDO.
the class HapiValueSetMapper method addExpansion.
private void addExpansion(ValueSet vs, List<ConceptMini> concepts, Map<String, Concept> conceptDetails, List<LanguageDialect> designations, Boolean includeDesignations) {
// Will autocreate
ValueSetExpansionComponent expansion = vs.getExpansion();
for (ConceptMini concept : concepts) {
ValueSetExpansionContainsComponent component = expansion.addContains().setCode(concept.getConceptId()).setSystem(SNOMED_URI);
if (conceptDetails != null && conceptDetails.containsKey(concept.getConceptId())) {
Concept c = conceptDetails.get(concept.getConceptId());
for (Description d : c.getActiveDescriptions()) {
if (includeDesignations && d.hasAcceptability(designations)) {
component.addDesignation(asDesignation(d));
}
// Use the preferred term in the specified display language.
if (!designations.isEmpty() && d.hasAcceptability(Concepts.PREFERRED, designations.get(0)) && d.getTypeId().equals(Concepts.SYNONYM)) {
component.setDisplay(d.getTerm());
boolean inactive = !c.isActive();
if (inactive) {
component.setInactive(inactive);
}
}
}
}
}
}
use of org.snomed.snowstorm.core.data.domain.ConceptMini in project snowstorm by IHTSDO.
the class MultiSearchController method findDescriptions.
@ApiOperation("Search descriptions across multiple Code Systems.")
@RequestMapping(value = "multisearch/descriptions", method = RequestMethod.GET)
@JsonView(value = View.Component.class)
public ItemsPage<BrowserDescriptionSearchResult> findDescriptions(// 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");
DescriptionCriteria descriptionCriteria = new DescriptionCriteria().term(term).active(active).modules(module).searchLanguageCodes(language).type(type).conceptActive(conceptActive);
PageRequest pageRequest = ControllerHelper.getPageRequest(offset, limit);
Page<Description> descriptions = multiSearchService.findDescriptions(descriptionCriteria, pageRequest);
timer.checkpoint("description search");
Map<String, List<Description>> branchDescriptions = new HashMap<>();
Map<String, List<String>> branchConceptIds = new HashMap<>();
for (Description description : descriptions) {
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);
}
List<BrowserDescriptionSearchResult> results = new ArrayList<>();
for (Description description : descriptions) {
BrowserDescriptionSearchResult result = new BrowserDescriptionSearchResult(description.getTerm(), description.isActive(), description.getLanguageCode(), description.getModuleId(), conceptMiniMap.get(description.getConceptId()));
result.addExtraField("branchPath", description.getPath());
results.add(result);
}
timer.finish();
return new ItemsPage<>(new PageImpl<>(results, pageRequest, descriptions.getTotalElements()));
}
Aggregations