This is an automated email from the ASF dual-hosted git repository. jleroux pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/trunk by this push: new 2f07f48054 Improved: Optimize the 'get average product rating' method logic (OFBIZ-12680) 2f07f48054 is described below commit 2f07f4805478e0552f074f98dc50df7a3aa001cc Author: Jacques Le Roux <jacques.le.r...@les7arts.com> AuthorDate: Tue Aug 30 16:53:49 2022 +0200 Improved: Optimize the 'get average product rating' method logic (OFBIZ-12680) Problem: When calculating the average product rating for any product, the 'get average product rating' method first retrieves the whole list of reviews and then iterates all product reviews to determine. This approach takes time to respond when there are thousands of reviews of a single product. It takes significantly longer to display many products together with their reviews. (e.g. search result page) Solution: We can use the 'average' function to get the average rather than iterating all the product reviews. Thanks: sourabh jain for the patch, Priya Sharma to help understand --- .../entry/catalog/ProductDetail.groovy | 2 +- .../ofbiz/product/product/ProductWorker.java | 61 +++++++++++++--------- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/applications/order/groovyScripts/entry/catalog/ProductDetail.groovy b/applications/order/groovyScripts/entry/catalog/ProductDetail.groovy index 3150980b20..d715be8501 100644 --- a/applications/order/groovyScripts/entry/catalog/ProductDetail.groovy +++ b/applications/order/groovyScripts/entry/catalog/ProductDetail.groovy @@ -210,7 +210,7 @@ if (product) { if (reviews) { ratingReviews = EntityUtil.filterByAnd(reviews, [EntityCondition.makeCondition("productRating", EntityOperator.NOT_EQUAL, null)]) if (ratingReviews) { - context.averageRating = ProductWorker.getAverageProductRating(product, reviews, productStoreId) + context.averageRating = ProductWorker.getAverageProductRating(product, reviews, productStoreId, delegator) context.numRatings = ratingReviews.size() } } diff --git a/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductWorker.java b/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductWorker.java index fc46b17946..768f390638 100644 --- a/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductWorker.java +++ b/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductWorker.java @@ -43,6 +43,7 @@ import org.apache.ofbiz.entity.GenericEntityException; import org.apache.ofbiz.entity.GenericValue; import org.apache.ofbiz.entity.condition.EntityCondition; import org.apache.ofbiz.entity.condition.EntityOperator; +import org.apache.ofbiz.entity.model.DynamicViewEntity; import org.apache.ofbiz.entity.util.EntityQuery; import org.apache.ofbiz.entity.util.EntityTypeUtil; import org.apache.ofbiz.entity.util.EntityUtil; @@ -657,14 +658,14 @@ public final class ProductWorker { } catch (GenericEntityException e) { Debug.logError(e, MODULE); } - return ProductWorker.getAverageProductRating(product, productStoreId); + return ProductWorker.getAverageProductRating(product, productStoreId, delegator); } - public static BigDecimal getAverageProductRating(GenericValue product, String productStoreId) { - return getAverageProductRating(product, null, productStoreId); + public static BigDecimal getAverageProductRating(GenericValue product, String productStoreId, Delegator delegator) { + return getAverageProductRating(product, null, productStoreId, delegator); } - public static BigDecimal getAverageProductRating(GenericValue product, List<GenericValue> reviews, String productStoreId) { + public static BigDecimal getAverageProductRating(GenericValue product, List<GenericValue> reviews, String productStoreId, Delegator delegator) { if (product == null) { Debug.logWarning("Invalid product entity passed; unable to obtain valid product rating", MODULE); return BigDecimal.ZERO; @@ -685,37 +686,45 @@ public final class ProductWorker { if ("PRDR_FLAT".equals(entityFieldType)) { productRating = productEntityRating; } else { - // get the product rating from the ProductReview entity; limit by product store if ID is passed - Map<String, String> reviewByAnd = UtilMisc.toMap("statusId", "PRR_APPROVED"); - if (productStoreId != null) { - reviewByAnd.put("productStoreId", productStoreId); - } - // lookup the reviews if we didn't pass them in if (reviews == null) { + Map<String, String> reviewByAnd = UtilMisc.toMap("statusId", "PRR_APPROVED"); + if (productStoreId != null) { + reviewByAnd.put("productStoreId", productStoreId); + } + if (product != null) { + reviewByAnd.put("productId", (String) product.get("productId")); + } try { - reviews = product.getRelated("ProductReview", reviewByAnd, UtilMisc.toList("-postedDateTime"), true); + DynamicViewEntity avgProductReview = new DynamicViewEntity(); + avgProductReview.addMemberEntity("PR", "ProductReview"); + avgProductReview.addAlias("PR", "productRatingAvg", "productRating", null, null, null, "avg"); + avgProductReview.addAlias("PR", "productId"); + avgProductReview.addAlias("PR", "statusId"); + avgProductReview.addAlias("PR", "productStoreId"); + GenericValue averageProductReview = EntityQuery.use(delegator).select("productRatingAvg") + .from(avgProductReview).where(reviewByAnd).queryFirst(); + productRating = averageProductReview.getBigDecimal("productRatingAvg"); } catch (GenericEntityException e) { Debug.logError(e, MODULE); } - } - - // tally the average - BigDecimal ratingTally = BigDecimal.ZERO; - BigDecimal numRatings = BigDecimal.ZERO; - if (reviews != null) { - for (GenericValue productReview: reviews) { - BigDecimal rating = productReview.getBigDecimal("productRating"); - if (rating != null) { - ratingTally = ratingTally.add(rating); - numRatings = numRatings.add(BigDecimal.ONE); + } else { + // tally the average + BigDecimal ratingTally = BigDecimal.ZERO; + BigDecimal numRatings = BigDecimal.ZERO; + if (reviews != null) { + for (GenericValue productReview: reviews) { + BigDecimal rating = productReview.getBigDecimal("productRating"); + if (rating != null) { + ratingTally = ratingTally.add(rating); + numRatings = numRatings.add(BigDecimal.ONE); + } } } + if (ratingTally.compareTo(BigDecimal.ZERO) > 0 && numRatings.compareTo(BigDecimal.ZERO) > 0) { + productRating = ratingTally.divide(numRatings, GEN_ROUNDING); + } } - if (ratingTally.compareTo(BigDecimal.ZERO) > 0 && numRatings.compareTo(BigDecimal.ZERO) > 0) { - productRating = ratingTally.divide(numRatings, GEN_ROUNDING); - } - if ("PRDR_MIN".equals(entityFieldType)) { // check for min if (productEntityRating.compareTo(productRating) > 0) {