use of com.b2international.snowowl.snomed.common.SnomedConstants.Concepts in project snow-owl by b2ihealthcare.
the class NormalFormGenerator method precomputeProperties.
private void precomputeProperties(final long conceptId, final boolean useNodeGraphs) {
final LongSet parentIds = reasonerTaxonomy.getInferredAncestors().getDestinations(conceptId, true);
/*
* Non IS-A relationships are fetched from ancestors; redundancy must be removed. Since we are working through the list
* of concepts in breadth-first order, we only need to look at cached results from the direct parents, and "distill"
* a non-redundant set of components out of them.
*/
final LongKeyMap<Collection<StatementFragment>> candidateNonIsARelationships = PrimitiveMaps.newLongKeyOpenHashMap();
for (final LongIterator itr = parentIds.iterator(); itr.hasNext(); ) /* empty */
{
final long parentId = itr.next();
candidateNonIsARelationships.put(parentId, statementCache.get(parentId));
}
// Stated axiom fragments are non-IS A, but any stated relationships need to be filtered (if they are still present)
final Collection<StatementFragment> ownStatedRelationships = reasonerTaxonomy.getStatedRelationships().get(conceptId);
final Collection<StatementFragment> ownStatedNonIsaRelationships = ownStatedRelationships.stream().filter(r -> r.getTypeId() != IS_A).collect(Collectors.toList());
candidateNonIsARelationships.put(conceptId, ImmutableList.<StatementFragment>builder().addAll(ownStatedNonIsaRelationships).addAll(reasonerTaxonomy.getAxiomNonIsARelationships().get(conceptId)).addAll(reasonerTaxonomy.getAdditionalGroupedRelationships().get(conceptId)).build());
// Collect existing inferred relationships for cross-referencing group numbers
final Collection<StatementFragment> ownInferredRelationships = reasonerTaxonomy.getExistingInferredRelationships().get(conceptId);
final Collection<StatementFragment> ownInferredNonIsaRelationships = ownInferredRelationships.stream().filter(r -> r.getTypeId() != IS_A).collect(Collectors.toList());
/*
* Do the same as the above, but for CD members
*/
final LongKeyMap<Collection<ConcreteDomainFragment>> candidateMembers = PrimitiveMaps.newLongKeyOpenHashMap();
for (final LongIterator itr = parentIds.iterator(); itr.hasNext(); ) /* empty */
{
final long parentId = itr.next();
candidateMembers.put(parentId, concreteDomainCache.get(parentId));
}
final String referencedComponentId = Long.toString(conceptId);
final Collection<ConcreteDomainFragment> ownStatedMembers = reasonerTaxonomy.getStatedConcreteDomainMembers().get(referencedComponentId);
final Collection<ConcreteDomainFragment> ownAdditionalGroupedMembers = reasonerTaxonomy.getAdditionalGroupedConcreteDomainMembers().get(referencedComponentId);
candidateMembers.put(conceptId, ImmutableList.<ConcreteDomainFragment>builder().addAll(ownStatedMembers).addAll(ownAdditionalGroupedMembers).build());
final Collection<ConcreteDomainFragment> ownInferredMembers = reasonerTaxonomy.getInferredConcreteDomainMembers().get(referencedComponentId);
// Remove redundancy
final NormalFormGroupSet targetGroupSet = getTargetGroupSet(conceptId, parentIds, ownInferredNonIsaRelationships, ownInferredMembers, candidateNonIsARelationships, candidateMembers, useNodeGraphs);
// Extract results; place them in the cache, so following concepts can re-use it
statementCache.put(conceptId, ImmutableList.copyOf(relationshipsFromGroupSet(targetGroupSet)));
concreteDomainCache.put(conceptId, ImmutableList.copyOf(membersFromGroupSet(targetGroupSet)));
}
use of com.b2international.snowowl.snomed.common.SnomedConstants.Concepts in project snow-owl by b2ihealthcare.
the class ConceptChangeProcessor method update.
/*
* Updates already existing concept document with changes from concept and the current revision.
* New concepts does not have currentRevision and dirty concepts may not have a loaded Concept CDOObject,
* therefore both can be null, but not at the same time.
* In case of new objects the Concept object should not be null, in case of dirty, the currentVersion should not be null,
* but there can be a dirty concept if a property changed on it.
* We will use whatever we actually have locally to compute the new revision.
*/
private void update(SnomedConceptDocument.Builder doc, List<SnomedDescriptionFragment> preferredDescriptions, @Nullable SnomedConceptDocument newOrDirtyRevision, SnomedConceptDocument cleanRevision) {
checkArgument(newOrDirtyRevision != null || cleanRevision != null, "Either the newOrDirtyRevision is null or the cleanRevision but not both");
final String id = newOrDirtyRevision != null ? newOrDirtyRevision.getId() : cleanRevision.getId();
final long idLong = Long.parseLong(id);
final boolean active = newOrDirtyRevision != null ? newOrDirtyRevision.isActive() : cleanRevision.isActive();
if (newOrDirtyRevision != null) {
doc.active(active).released(newOrDirtyRevision.isReleased()).effectiveTime(newOrDirtyRevision.getEffectiveTime()).moduleId(newOrDirtyRevision.getModuleId()).exhaustive(newOrDirtyRevision.isExhaustive()).definitionStatusId(newOrDirtyRevision.getDefinitionStatusId()).refSetType(newOrDirtyRevision.getRefSetType()).referencedComponentType(newOrDirtyRevision.getReferencedComponentType()).mapTargetComponentType(newOrDirtyRevision.getMapTargetComponentType()).doi(doiData.getDoiScore(idLong));
} else {
doc.active(active).released(cleanRevision.isReleased()).effectiveTime(cleanRevision.getEffectiveTime()).moduleId(cleanRevision.getModuleId()).exhaustive(cleanRevision.isExhaustive()).definitionStatusId(cleanRevision.getDefinitionStatusId()).refSetType(cleanRevision.getRefSetType()).referencedComponentType(cleanRevision.getReferencedComponentType()).mapTargetComponentType(cleanRevision.getMapTargetComponentType()).doi(doiData.getDoiScore(idLong));
}
/*
* Extract semantic tags from active FSNs received in preferredDescriptions (these are expected to be preferred in at
* least one language reference set).
*/
final SortedSet<String> semanticTags = preferredDescriptions.stream().filter(f -> Concepts.FULLY_SPECIFIED_NAME.equals(f.getTypeId())).map(f -> SnomedDescriptionIndexEntry.extractSemanticTag(f.getTerm())).filter(semanticTag -> !semanticTag.isEmpty()).collect(Collectors.toCollection(TreeSet::new));
final boolean inStated = statedTaxonomy.getNewTaxonomy().containsNode(idLong);
final boolean inInferred = inferredTaxonomy.getNewTaxonomy().containsNode(idLong);
if (inStated || inInferred) {
iconId.update(id, Iterables.getFirst(semanticTags, ""), active, doc);
}
if (inStated) {
stated.update(id, doc);
}
if (inInferred) {
inferred.update(id, doc);
}
final Collection<String> currentMemberOf = cleanRevision == null ? Collections.emptySet() : cleanRevision.getMemberOf();
final Collection<String> currentActiveMemberOf = cleanRevision == null ? Collections.emptySet() : cleanRevision.getActiveMemberOf();
new ReferenceSetMembershipUpdater(referringRefSets.removeAll(id), currentMemberOf, currentActiveMemberOf).update(doc);
doc.semanticTags(semanticTags);
doc.preferredDescriptions(preferredDescriptions);
}
use of com.b2international.snowowl.snomed.common.SnomedConstants.Concepts in project snow-owl by b2ihealthcare.
the class ConceptChangeProcessor method processNewConcepts.
private void processNewConcepts(StagingArea staging) {
final Multimap<String, SnomedDescriptionFragment> newDescriptionFragmentsByConcept = HashMultimap.create();
// changed descriptions are coming from potential merges/rebases
Streams.concat(staging.getNewObjects(SnomedDescriptionIndexEntry.class), staging.getChangedObjects(SnomedDescriptionIndexEntry.class)).filter(SnomedDescriptionIndexEntry::isActive).filter(description -> !Concepts.TEXT_DEFINITION.equals(description.getTypeId())).filter(description -> !getPreferredLanguageMembers(description).isEmpty()).forEach(description -> newDescriptionFragmentsByConcept.put(description.getConceptId(), toDescriptionFragment(description)));
// index new concepts
staging.getNewObjects(SnomedConceptDocument.class).forEach(concept -> {
final String id = concept.getId();
final Builder doc = SnomedConceptDocument.builder().id(id);
// in case of a new concept, all of its descriptions should be part of the staging area as well
final List<SnomedDescriptionFragment> preferredDescriptions = newDescriptionFragmentsByConcept.removeAll(id).stream().sorted(DESCRIPTION_FRAGMENT_ORDER).collect(Collectors.toList());
update(doc, preferredDescriptions, concept, null);
stageNew(doc.build());
});
}
use of com.b2international.snowowl.snomed.common.SnomedConstants.Concepts in project snow-owl by b2ihealthcare.
the class ConceptChangeProcessor method process.
@Override
public void process(StagingArea staging, RevisionSearcher searcher) throws IOException {
// collect member changes
this.referringRefSets = HashMultimap.create(memberChangeProcessor.process(staging, searcher));
processNewConcepts(staging);
// collect dirty concepts that require additional properties to be set for index
final Map<String, RevisionDiff> dirtyConceptDiffsById = Maps.uniqueIndex(staging.getChangedRevisions(SnomedConceptDocument.class).iterator(), diff -> diff.newRevision.getId());
final Set<String> dirtyConceptIds = collectDirtyConceptIds(staging);
// remaining new/dirty/detached descriptions should be properly processed for preferredDescriptions field
final Map<String, SnomedDescriptionIndexEntry> affectedDescriptionsById = getDescriptionDocuments(staging, searcher);
final Multimap<String, SnomedDescriptionIndexEntry> affectedDescriptionsByConcept = Multimaps.index(affectedDescriptionsById.values(), SnomedDescriptionIndexEntry::getConceptId);
dirtyConceptIds.addAll(affectedDescriptionsByConcept.keySet());
// remove all new/detached concept IDs, we've already processed them
staging.getRemovedObjects(SnomedConceptDocument.class).map(SnomedConceptDocument::getId).forEach(dirtyConceptIds::remove);
staging.getNewObjects(SnomedConceptDocument.class).map(SnomedConceptDocument::getId).forEach(dirtyConceptIds::remove);
if (!dirtyConceptIds.isEmpty()) {
final Map<ObjectId, RevisionDiff> changedRevisions = staging.getChangedRevisions();
// fetch all dirty concept documents by their ID
final Set<String> missingCurrentConceptIds = dirtyConceptIds.stream().filter(id -> !changedRevisions.containsKey(ObjectId.of(SnomedConcept.TYPE, id))).collect(Collectors.toSet());
final Map<String, SnomedConceptDocument> currentConceptDocumentsById = newHashMap(Maps.uniqueIndex(searcher.get(SnomedConceptDocument.class, missingCurrentConceptIds), Revision::getId));
dirtyConceptIds.stream().map(id -> ObjectId.of(SnomedConcept.TYPE, id)).filter(changedRevisions::containsKey).map(changedRevisions::get).map(diff -> (SnomedConceptDocument) diff.oldRevision).forEach(doc -> currentConceptDocumentsById.put(doc.getId(), doc));
// update dirty concepts
for (final String id : dirtyConceptIds) {
final SnomedConceptDocument concept = dirtyConceptDiffsById.containsKey(id) ? (SnomedConceptDocument) dirtyConceptDiffsById.get(id).newRevision : null;
final SnomedConceptDocument currentDoc = currentConceptDocumentsById.get(id);
if (currentDoc == null) {
throw new IllegalStateException("Current concept revision should not be null for: " + id);
}
final Builder doc = SnomedConceptDocument.builder(currentDoc);
final Collection<SnomedDescriptionIndexEntry> affectedDescriptions = affectedDescriptionsByConcept.get(id);
if (!affectedDescriptions.isEmpty()) {
final Map<String, SnomedDescriptionFragment> updatedPreferredDescriptions = newHashMap(Maps.uniqueIndex(currentDoc.getPreferredDescriptions(), SnomedDescriptionFragment::getId));
// add new/dirty fragments if they are preferred and active terms
for (SnomedDescriptionIndexEntry affectedDescription : affectedDescriptions) {
if (staging.isNew(affectedDescription) || staging.isChanged(affectedDescription)) {
updatedPreferredDescriptions.remove(affectedDescription.getId());
if (affectedDescription.isActive() && !getPreferredLanguageMembers(affectedDescription).isEmpty()) {
updatedPreferredDescriptions.put(affectedDescription.getId(), toDescriptionFragment(affectedDescription));
}
}
}
// remove deleted descriptions
for (SnomedDescriptionIndexEntry affectedDescription : affectedDescriptions) {
if (staging.isRemoved(affectedDescription)) {
updatedPreferredDescriptions.remove(affectedDescription.getId());
}
}
final List<SnomedDescriptionFragment> preferredDescriptions = updatedPreferredDescriptions.values().stream().sorted(DESCRIPTION_FRAGMENT_ORDER).collect(Collectors.toList());
update(doc, preferredDescriptions, concept, currentDoc);
} else {
update(doc, currentDoc.getPreferredDescriptions(), concept, currentDoc);
}
stageChange(currentDoc, doc.build());
}
}
}
use of com.b2international.snowowl.snomed.common.SnomedConstants.Concepts in project snow-owl by b2ihealthcare.
the class RelationshipChangeConverter method expand.
@Override
public void expand(final List<RelationshipChange> results) {
if (!expand().containsKey(RelationshipChange.Expand.RELATIONSHIP)) {
return;
}
/*
* Depending on the relationship change search request, we might need to issue
* SNOMED CT searches against multiple branches; find out which ones we have.
*/
final Multimap<String, RelationshipChange> itemsByBranch = getItemsByBranch(results);
// Check if we only need to load inferred relationships in their entirety
final Options expandOptions = expand().getOptions(RelationshipChange.Expand.RELATIONSHIP);
final boolean inferredOnly = expandOptions.getBoolean("inferredOnly");
final Options relationshipExpandOptions = expandOptions.getOptions("expand");
final Options sourceOptions = relationshipExpandOptions.getOptions(SnomedRelationship.Expand.SOURCE);
final Options typeOptions = relationshipExpandOptions.getOptions(SnomedRelationship.Expand.TYPE);
final Options destinationOptions = relationshipExpandOptions.getOptions(SnomedRelationship.Expand.DESTINATION);
final boolean needsSource = relationshipExpandOptions.keySet().contains(SnomedRelationship.Expand.SOURCE);
final boolean needsType = relationshipExpandOptions.keySet().contains(SnomedRelationship.Expand.TYPE);
final boolean needsDestination = relationshipExpandOptions.keySet().contains(SnomedRelationship.Expand.DESTINATION);
// Do not allow expansion of members
final boolean needsMembers = relationshipExpandOptions.keySet().contains(MEMBERS);
if (needsMembers) {
throw new BadRequestException("Members can not be expanded on reasoner relationship changes.");
}
for (final String branch : itemsByBranch.keySet()) {
final Collection<RelationshipChange> itemsForCurrentBranch = itemsByBranch.get(branch);
/*
* Expand concepts on the relationship currently set on each item first, as they
* might have changed when compared to the "origin" relationship.
*/
if (needsSource) {
expandConcepts(branch, itemsForCurrentBranch, sourceOptions, ReasonerRelationship::getSourceId, ReasonerRelationship::setSource);
}
if (needsType) {
expandConcepts(branch, itemsForCurrentBranch, typeOptions, ReasonerRelationship::getTypeId, ReasonerRelationship::setType);
}
if (needsDestination) {
expandConcepts(branch, itemsForCurrentBranch, destinationOptions, ReasonerRelationship::getDestinationId, ReasonerRelationship::setDestination);
}
// Now fetch the rest of the properties for the relationships (except IS As where no ID is recorded)
final Set<String> relationshipIds = itemsForCurrentBranch.stream().filter(c -> !inferredOnly || ChangeNature.NEW.equals(c.getChangeNature())).map(c -> c.getRelationship().getOriginId()).filter(id -> id != null).collect(Collectors.toSet());
final Request<BranchContext, SnomedRelationships> relationshipSearchRequest = SnomedRequests.prepareSearchRelationship().filterByIds(relationshipIds).setLimit(relationshipIds.size()).setExpand(relationshipExpandOptions).setLocales(locales()).build();
final SnomedRelationships relationships = new BranchRequest<>(branch, new RevisionIndexReadRequest<>(relationshipSearchRequest)).execute(context());
final Map<String, SnomedRelationship> relationshipsById = Maps.uniqueIndex(relationships, SnomedRelationship::getId);
for (final RelationshipChange item : itemsForCurrentBranch) {
final ReasonerRelationship reasonerRelationship = item.getRelationship();
final String originId = reasonerRelationship.getOriginId();
switch(item.getChangeNature()) {
case NEW:
if (originId == null) {
// reasonerRelationship.setCharacteristicType(...) is already set
// reasonerRelationship.setDestination(...) is already set
reasonerRelationship.setDestinationNegated(false);
// reasonerRelationship.setGroup(...) is already set
reasonerRelationship.setModifierId(Concepts.EXISTENTIAL_RESTRICTION_MODIFIER);
// reasonerRelationship.setReleased(...) is already set
// reasonerRelationship.setSource(...) is already set
// reasonerRelationship.setType(...) is already set
// reasonerRelationship.setUnionGroup(...) is already set
// reasonerRelationship.setValue(...) is already set
} else {
final SnomedRelationship expandedRelationship = relationshipsById.get(originId);
// reasonerRelationship.setCharacteristicType(...) is already set
reasonerRelationship.setDestination(expandedRelationship.getDestination());
reasonerRelationship.setDestinationNegated(expandedRelationship.isDestinationNegated());
// reasonerRelationship.setGroup(...) is already set
reasonerRelationship.setModifierId(expandedRelationship.getModifierId());
// reasonerRelationship.setReleased(...) is already set
// reasonerRelationship.setSource(...) is already set
reasonerRelationship.setType(expandedRelationship.getType());
// reasonerRelationship.setUnionGroup(...) is already set
reasonerRelationship.setValueAsObject(expandedRelationship.getValueAsObject());
}
break;
case UPDATED:
if (!inferredOnly) {
final SnomedRelationship expandedRelationship = relationshipsById.get(originId);
reasonerRelationship.setCharacteristicTypeId(expandedRelationship.getCharacteristicTypeId());
reasonerRelationship.setDestination(expandedRelationship.getDestination());
reasonerRelationship.setDestinationNegated(expandedRelationship.isDestinationNegated());
// reasonerRelationship.setGroup(...) is already set
reasonerRelationship.setModifierId(expandedRelationship.getModifierId());
// reasonerRelationship.setReleased(...) is already set
reasonerRelationship.setSource(expandedRelationship.getSource());
reasonerRelationship.setType(expandedRelationship.getType());
reasonerRelationship.setUnionGroup(expandedRelationship.getUnionGroup());
reasonerRelationship.setValueAsObject(expandedRelationship.getValueAsObject());
}
break;
case REDUNDANT:
if (!inferredOnly) {
final SnomedRelationship expandedRelationship = relationshipsById.get(originId);
reasonerRelationship.setCharacteristicTypeId(expandedRelationship.getCharacteristicTypeId());
reasonerRelationship.setDestination(expandedRelationship.getDestination());
reasonerRelationship.setDestinationNegated(expandedRelationship.isDestinationNegated());
reasonerRelationship.setGroup(expandedRelationship.getRelationshipGroup());
reasonerRelationship.setModifierId(expandedRelationship.getModifierId());
// reasonerRelationship.setReleased(...) is already set
reasonerRelationship.setSource(expandedRelationship.getSource());
reasonerRelationship.setType(expandedRelationship.getType());
reasonerRelationship.setUnionGroup(expandedRelationship.getUnionGroup());
reasonerRelationship.setValueAsObject(expandedRelationship.getValueAsObject());
}
break;
default:
throw new IllegalStateException(String.format("Unexpected relationship change '%s' found with SCTID '%s'.", item.getChangeNature(), item.getRelationship().getOriginId()));
}
}
}
}
Aggregations