use of com.b2international.snowowl.snomed.reasoner.equivalence.IEquivalentConceptMerger in project snow-owl by b2ihealthcare.
the class SaveJobRequest method mergeEquivalentConcepts.
private Set<String> mergeEquivalentConcepts(final BranchContext context, final BulkRequestBuilder<TransactionContext> bulkRequestBuilder, final SnomedNamespaceAndModuleAssigner assigner) {
if (!fixEquivalences) {
return Collections.emptySet();
}
// XXX: Restrict merging to active components only
final String expand = "equivalentConcepts(expand(" + "descriptions(active:true)," + "relationships(active:true)," + "inboundRelationships(active:true)," + "members(active:true)))";
final Multimap<SnomedConcept, SnomedConcept> equivalentConcepts = HashMultimap.create();
ClassificationRequests.prepareSearchEquivalentConceptSet().setLimit(SCROLL_LIMIT).setExpand(expand).filterByClassificationId(classificationId).stream(context).flatMap(EquivalentConceptSets::stream).filter(equivalentSet -> !equivalentSet.isUnsatisfiable()).forEach(equivalentSet -> {
final List<SnomedConcept> conceptsToRemove = newArrayList(equivalentSet.getEquivalentConcepts());
final SnomedConcept conceptToKeep = conceptsToRemove.remove(0);
equivalentConcepts.putAll(conceptToKeep, conceptsToRemove);
});
// Are there any equivalent concepts present? or Were all equivalent concepts unsatisfiable?
if (equivalentConcepts.isEmpty()) {
return Collections.emptySet();
}
IEquivalentConceptMerger merger = Extensions.getFirstPriorityExtension(IEquivalentConceptMerger.EXTENSION_POINT, IEquivalentConceptMerger.class);
if (merger == null) {
merger = new IEquivalentConceptMerger.Default();
}
final String mergerName = merger.getClass().getSimpleName();
LOG.info("Reasoner service will use {} for equivalent concept merging.", mergerName);
final Set<String> conceptIdsToSkip = merger.merge(equivalentConcepts);
final Set<String> conceptIdsToKeep = equivalentConcepts.keySet().stream().map(SnomedConcept::getId).collect(Collectors.toSet());
// Prepare to provide namespace-module for inbound relationship source concepts as well
final Set<String> relationshipChangeConceptIds = newHashSet(conceptIdsToKeep);
// Add source concepts on new/about to be inactivated inbound relationships, pointing to "kept" concepts
for (final SnomedConcept conceptToKeep : equivalentConcepts.keySet()) {
for (final SnomedRelationship relationship : conceptToKeep.getInboundRelationships()) {
if (relationship.getId().startsWith(IEquivalentConceptMerger.PREFIX_NEW)) {
relationshipChangeConceptIds.add(relationship.getSourceId());
} else if (!relationship.isActive()) {
relationshipChangeConceptIds.add(relationship.getSourceId());
}
}
}
assigner.collectRelationshipNamespacesAndModules(relationshipChangeConceptIds, context);
for (final SnomedConcept conceptToKeep : equivalentConcepts.keySet()) {
for (final SnomedRelationship relationship : conceptToKeep.getInboundRelationships()) {
// Already handled as another concept's outbound relationship
if (relationship.getId() == null) {
continue;
}
if (relationship.getId().startsWith(IEquivalentConceptMerger.PREFIX_NEW)) {
relationship.setId(null);
addComponent(bulkRequestBuilder, assigner, relationship);
} else if (!relationship.isActive()) {
removeOrDeactivate(bulkRequestBuilder, assigner, relationship);
}
}
for (final SnomedRelationship relationship : conceptToKeep.getRelationships()) {
// Already handled as another concept's inbound relationship
if (relationship.getId() == null) {
continue;
}
if (relationship.getId().startsWith(IEquivalentConceptMerger.PREFIX_NEW)) {
relationship.setId(null);
addComponent(bulkRequestBuilder, assigner, relationship);
} else if (!relationship.isActive()) {
removeOrDeactivate(bulkRequestBuilder, assigner, relationship);
}
}
}
// CD members are always "outbound", however, so the concept SCTID set can be reduced
assigner.clear();
assigner.collectConcreteDomainModules(conceptIdsToKeep, context);
for (final SnomedConcept conceptToKeep : equivalentConcepts.keySet()) {
for (final SnomedReferenceSetMember member : conceptToKeep.getMembers()) {
if (member.getId().startsWith(IEquivalentConceptMerger.PREFIX_NEW)) {
member.setId(null);
addComponent(bulkRequestBuilder, assigner, member);
} else if (member.getId().startsWith(IEquivalentConceptMerger.PREFIX_UPDATED)) {
// Trim the prefix from the ID to restore its original form
member.setId(member.getId().substring(IEquivalentConceptMerger.PREFIX_UPDATED.length()));
bulkRequestBuilder.add(member.toUpdateRequest());
} else if (!member.isActive()) {
removeOrDeactivate(bulkRequestBuilder, assigner, member);
}
}
}
// Descriptions are also "outbound"
assigner.clear();
assigner.collectRelationshipNamespacesAndModules(conceptIdsToKeep, context);
for (final SnomedConcept conceptToKeep : equivalentConcepts.keySet()) {
for (final SnomedDescription description : conceptToKeep.getDescriptions()) {
if (description.getId().startsWith(IEquivalentConceptMerger.PREFIX_NEW)) {
description.setId(null);
addComponent(bulkRequestBuilder, assigner, description);
} else if (description.getId().startsWith(IEquivalentConceptMerger.PREFIX_UPDATED)) {
// Trim the prefix from the ID to restore its original form
description.setId(description.getId().substring(IEquivalentConceptMerger.PREFIX_UPDATED.length()));
bulkRequestBuilder.add(description.toUpdateRequest());
} else if (!description.isActive()) {
removeOrDeactivate(bulkRequestBuilder, assigner, description);
}
}
}
// Inactivation of "removed" concepts also requires modules to be collected according to the assigner rules
assigner.clear();
assigner.collectRelationshipNamespacesAndModules(conceptIdsToSkip, context);
for (final SnomedConcept conceptToRemove : equivalentConcepts.values()) {
// Check if the concept needs to be removed or deactivated
if (!conceptToRemove.isActive()) {
removeOrDeactivate(bulkRequestBuilder, assigner, conceptToRemove);
}
}
assigner.clear();
return conceptIdsToSkip;
}
Aggregations