use of com.b2international.snowowl.snomed.core.ecl.EclParser in project snow-owl by b2ihealthcare.
the class SnomedQueryOptimizer method optimize.
@Override
public QueryExpressionDiffs optimize(BranchContext context, Options params) {
final Collection<QueryExpression> inclusions = params.getCollection(QueryOptimizer.OptionKey.INCLUSIONS, QueryExpression.class);
final List<ExtendedLocale> locales = params.getList(QueryOptimizer.OptionKey.LOCALES, ExtendedLocale.class);
final EclParser eclParser = context.service(EclParser.class);
final LoadingCache<String, ExpressionConstraint> eclCache = CacheBuilder.newBuilder().build(CacheLoader.from(eclParser::parse));
final Multimap<String, QueryExpression> singleConceptInclusions = FluentIterable.from(inclusions).filter(ex -> isSingleConceptExpression(eclCache, ex.getQuery())).index(ex -> toSingleConceptId(eclCache, ex.getQuery()));
// if there are no single concept inclusions to optimize, exit early
if (singleConceptInclusions.isEmpty()) {
return new QueryExpressionDiffs(Collections.emptyList());
}
// Record the ancestors (both direct and indirect) of each single concept inclusion
final Multimap<String, QueryExpression> membersByAncestor = HashMultimap.create();
SnomedRequests.prepareSearchConcept().filterByIds(singleConceptInclusions.keySet()).setLimit(singleConceptInclusions.keySet().size()).stream(context).flatMap(SnomedConcepts::stream).forEach(child -> {
final Collection<QueryExpression> childExpressions = singleConceptInclusions.get(child.getId());
final List<String> parentIds = child.getParentIdsAsString();
final List<String> ancestorIds = child.getAncestorIdsAsString();
parentIds.forEach(parentId -> {
if (!IComponent.ROOT_ID.equals(parentId) && !Concepts.ROOT_CONCEPT.equals(parentId)) {
membersByAncestor.putAll(parentId, childExpressions);
}
});
ancestorIds.forEach(ancestorId -> {
if (!IComponent.ROOT_ID.equals(ancestorId) && !Concepts.ROOT_CONCEPT.equals(ancestorId)) {
membersByAncestor.putAll(ancestorId, childExpressions);
}
});
});
// Get number of referenced descendants (taking possible duplicates into account)
final Map<String, Long> uniqueDescendantsByParent = ImmutableMap.copyOf(Maps.transformValues(membersByAncestor.asMap(), descendants -> descendants.stream().map(QueryExpression::getQuery).distinct().count()));
final ImmutableList.Builder<QueryExpressionDiff> diffs = ImmutableList.builder();
// references can be replaced with a single << expression.
for (Entry<String, Long> uniqueDescendantsByParentEntry : uniqueDescendantsByParent.entrySet()) {
SnomedConcept parent = SnomedRequests.prepareGetConcept(uniqueDescendantsByParentEntry.getKey()).setLocales(locales).setExpand("pt(),descendants(direct:false,limit:0)").build().execute(context);
final String parentId = parent.getId();
final int referencedDescendants = Ints.checkedCast(uniqueDescendantsByParent.get(parentId));
final int totalDescendants = parent.getDescendants().getTotal();
if (totalDescendants == referencedDescendants) {
final List<QueryExpression> remove = List.copyOf(membersByAncestor.get(parentId).stream().filter(ex -> !ex.isPinned()).collect(Collectors.toList()));
// The optimization is a "net win" if we can remove at least two clauses from the original
if (remove.size() > 1) {
final QueryExpression replacement = new QueryExpression(IDs.base64UUID(), String.format("<%s%s", parent.getId(), getTerm(parent)), false);
final List<QueryExpression> addToInclusion = List.of(replacement);
final List<QueryExpression> addToExclusion = List.of();
final QueryExpressionDiff diff = new QueryExpressionDiff(addToInclusion, addToExclusion, remove);
diffs.add(diff);
}
}
}
return new QueryExpressionDiffs(diffs.build());
}
Aggregations