jstastny-cz commented on code in PR #2328:
URL:
https://github.com/apache/incubator-kie-kogito-apps/pull/2328#discussion_r3378886355
##########
data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/JPAQuery.java:
##########
@@ -110,23 +121,80 @@ public List<T> execute() {
return (List<T>)
query.getResultList().stream().map(mapper).collect(toList());
}
- protected Function<AttributeFilter<?>, Predicate>
filterPredicateFunction(Root<E> root, CriteriaBuilder builder) {
+ /**
+ * Determines if DISTINCT is needed based on whether the query uses
collection attributes
+ * that would result in JOINs and potential duplicate rows.
+ */
+ private boolean needsDistinct() {
+ if (filters == null || filters.isEmpty()) {
+ return false;
+ }
+ return filters.stream().anyMatch(this::filterNeedsDistinct);
+ }
+
+ /**
+ * Recursively checks if a filter needs DISTINCT due to collection
operations or attributes.
+ */
+ private boolean filterNeedsDistinct(AttributeFilter<?> filter) {
+ return switch (filter.getCondition()) {
+ case CONTAINS, CONTAINS_ALL, CONTAINS_ANY ->
+ // Collection operations on collection attributes need DISTINCT
+ filter.getAttribute() != null &&
isCollectionAttribute(filter.getAttribute());
+ case AND, OR -> {
+ // Check nested filters recursively
+ List<AttributeFilter<?>> nestedFilters =
(List<AttributeFilter<?>>) filter.getValue();
+ yield
nestedFilters.stream().anyMatch(this::filterNeedsDistinct);
+ }
+ case NOT -> filterNeedsDistinct((AttributeFilter<?>)
filter.getValue());
+ case EQUAL, LIKE, IN, GT, GTE, LT, LTE, BETWEEN, IS_NULL, NOT_NULL
->
+ // These operations on collection attributes need DISTINCT
+ filter.getAttribute() != null &&
isCollectionAttribute(filter.getAttribute());
+ default -> false;
+ };
+ }
+
+ protected Function<AttributeFilter<?>, Predicate>
filterPredicateFunction(Root<E> root, CriteriaBuilder builder, CriteriaQuery<?>
criteriaQuery) {
return filter -> jsonPredicateBuilder.filter(b ->
filter.isJson()).map(b -> b.buildPredicate(filter, root, builder))
- .orElseGet(() -> buildPredicateFunction(filter, root,
builder));
+ .orElseGet(() -> buildPredicateFunction(filter, root, builder,
criteriaQuery));
}
- protected final Predicate buildPredicateFunction(AttributeFilter filter,
Root<E> root, CriteriaBuilder builder) {
+ protected final Predicate buildPredicateFunction(AttributeFilter filter,
Root<E> root, CriteriaBuilder builder, CriteriaQuery<?> criteriaQuery) {
Review Comment:
This is all new code, right? so the fact it was not correctly translating
query into SQL might be because of that and the actual logic. I expect that if
we try to merge into a single subquery, we need to properly adjust logic in the
inner scope of the logical condition. In your example, we'd basically need `NOT
EXISTS(... JOIN c1_0 ... JOIN c2_0 WHERE (c1_0.id=? AND c2_0.id=?)` ? instead
of OR?
I'd be interested in the resulting SQL Query plan really - if we merge
EXISTS clauses into one or we combine several using AND/OR - would it be
possible to attempt run EXPLAIN to get the query resulting query plans? If you
have such queries from previous runs then you could use those, if not perhaps
you could "simulate" only the SQL query without the need to actually implement
the changes just to test SQL query plan.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]