Skip to content

Commit

Permalink
updated top adv algorithm and made listeners for update rating and to…
Browse files Browse the repository at this point in the history
…p rating
  • Loading branch information
KovalBohdan-0 committed Jul 1, 2024
1 parent 3c16b71 commit 0d07d7d
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 79 deletions.
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
package org.petmarket.advertisements.advertisement.listener;

import jakarta.persistence.PostPersist;
import jakarta.persistence.PostUpdate;
import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate;
import jakarta.transaction.Transactional;
import org.petmarket.advertisements.advertisement.entity.Advertisement;
import org.petmarket.advertisements.advertisement.service.AdvertisementService;
import org.springframework.context.annotation.Lazy;

import static org.petmarket.advertisements.advertisement.service.AdvertisementService.calculateRating;

@Transactional
public class AdvertisementListener {
// private final AdvertisementService advertisementService;
//
// public AdvertisementListener(@Lazy AdvertisementService advertisementService) {
// this.advertisementService = advertisementService;
// }
//
// @PostPersist
// @PostUpdate
// public void updateTopRating(Advertisement advertisement) {
// advertisementService.updateTopRating(advertisement);
// }
@PrePersist
@PreUpdate
public void updateTopRating(Advertisement advertisement) {
advertisement.setTopRating(calculateRating(advertisement));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import org.petmarket.errorhandling.ItemNotCreatedException;
import org.petmarket.errorhandling.ItemNotFoundException;
import org.petmarket.language.entity.Language;
import org.petmarket.language.repository.LanguageRepository;
import org.petmarket.location.entity.City;
import org.petmarket.location.entity.Location;
import org.petmarket.location.repository.CityRepository;
Expand Down Expand Up @@ -75,7 +74,6 @@
@Service
public class AdvertisementService {

private final LanguageRepository languageRepository;
private final AdvertisementRepository advertisementRepository;
private final ReviewRepository reviewRepository;
private final UserRepository userRepository;
Expand Down Expand Up @@ -283,15 +281,15 @@ public Collection<AdvertisementReviewResponseDto> getReviewsByAdvertisementId(Lo
@Transactional
public AdvertisementReviewResponseDto addReview(Long id, AdvertisementReviewRequestDto request,
BindingResult bindingResult, Authentication authentication) {
// ErrorUtils.checkItemNotCreatedException(bindingResult);
ErrorUtils.checkItemNotCreatedException(bindingResult);

User author = getUserByEmail(authentication.getName());
User user = getAdvertisement(id).getAuthor();
Advertisement advertisement = getAdvertisement(id);
//
// if (reviewService.existsByAuthorIdAndUserId(author.getId(), user.getId())) {
// throw new ItemNotCreatedException(REVIEW_ALREADY_EXISTS);
// }

if (reviewService.existsByAuthorIdAndUserId(author.getId(), user.getId())) {
throw new ItemNotCreatedException(REVIEW_ALREADY_EXISTS);
}

Review review = Review.builder()
.author(author)
Expand All @@ -302,18 +300,13 @@ public AdvertisementReviewResponseDto addReview(Long id, AdvertisementReviewRequ
.advertisement(advertisement)
.build();
reviewRepository.save(review);
// entityManager.flush();
// userCacheService.evictCaches(user);
// reviewService.updateAdvertisementIndexes(List.of(advertisement));
entityManager.flush();
userCacheService.evictCaches(user);
reviewService.updateAdvertisementIndexes(List.of(advertisement));

return reviewMapper.mapEntityToAdvertisementDto(review);
}

private Language getLanguage(String langCode) {
return languageRepository.findByLangCodeAndEnableIsTrue(langCode)
.orElseThrow(() -> new ItemNotFoundException(LANGUAGE_NOT_FOUND));
}

public Advertisement getAdvertisement(Long id) {
Advertisement advertisement = advertisementRepository.findById(id)
.orElseThrow(() -> new ItemNotFoundException(ADVERTISEMENT_NOT_FOUND));
Expand Down Expand Up @@ -405,11 +398,6 @@ public Page<Advertisement> getSimilarAdvertisements(Long currentAdvertisementId,
return new PageImpl<>(similarAdvertisements, pageable, searchQuery.fetchTotalHitCount());
}

public Advertisement getAdvertisementByImageId(Long imageId) {
return advertisementRepository.findAdvertisementByImageId(imageId)
.orElseThrow(() -> new ItemNotFoundException(ADVERTISEMENT_NOT_FOUND));
}

public List<Advertisement> getAdvertisementsByImageIds(List<Long> imageIds) {
return advertisementRepository.findAdvertisementsByImageIds(imageIds);
}
Expand Down Expand Up @@ -452,20 +440,20 @@ public void updateRating(Review review) {
public void updateAllRatings() {
int batchSize = 1000;
int page = 0;
Page<Review> reviews;
Page<Advertisement> advertisements;

do {
reviews = reviewRepository
.findAllByAdvertisementStatus(AdvertisementStatus.ACTIVE, PageRequest.of(page, batchSize));
advertisements = advertisementRepository
.findAllByStatus(AdvertisementStatus.ACTIVE, PageRequest.of(page, batchSize));

for (Review review : reviews) {
updateRating(review);
for (Advertisement advertisement : advertisements) {
advertisement.setRating(reviewRepository.findAverageRatingByAdvertisementId(advertisement.getId()));
}

entityManager.flush();
entityManager.clear();
page++;
} while (reviews.hasNext());
} while (advertisements.hasNext());

page = 0;
Page<User> users;
Expand All @@ -475,7 +463,6 @@ public void updateAllRatings() {

for (User user : users) {
user.setRating(reviewRepository.findAverageRatingByUserId(user.getId()));
entityManager.merge(user);
}

entityManager.flush();
Expand All @@ -498,28 +485,28 @@ public void updateAllRatings() {
log.info("All ratings have been updated");
}

private int calculateDescriptionLengthBonus(Advertisement advertisement) {
public static int calculateRating(Advertisement advertisement) {
return advertisement.getRating() * 10
+ advertisement.getAuthor().getRating() * 10
+ calculateDescriptionLengthBonus(advertisement)
+ calculateImageBonus(advertisement)
+ calculateAttributesBonus(advertisement);
}

private static int calculateDescriptionLengthBonus(Advertisement advertisement) {
return (advertisement.getTranslations() != null && advertisement.getTranslations().stream()
.anyMatch(tr -> tr.getDescription().length() > 20)) ? 30 : 0;
}

private int calculateImageBonus(Advertisement advertisement) {
private static int calculateImageBonus(Advertisement advertisement) {
return (advertisement.getImages() != null && !advertisement.getImages().isEmpty()) ? 150 : 0;
}

private int calculateAttributesBonus(Advertisement advertisement) {
private static int calculateAttributesBonus(Advertisement advertisement) {
int bonus = (advertisement.getAttributes() != null ? advertisement.getAttributes().size() : 0) * 30;
return Math.min(bonus, 150);
}

private int calculateRating(Advertisement advertisement) {
return advertisement.getRating() * 10
+ advertisement.getAuthor().getRating() * 10
+ calculateDescriptionLengthBonus(advertisement)
+ calculateImageBonus(advertisement)
+ calculateAttributesBonus(advertisement);
}

private Long getCategoryIdFromSearch(String search) {
if (search == null || search.isBlank()) {
return null;
Expand Down Expand Up @@ -637,12 +624,6 @@ private User getUserByEmail(String email) {
.orElseThrow(() -> new ItemNotFoundException(USER_NOT_FOUND));
}

private AdvertisementTranslate getTranslation(Advertisement advertisement, Language language) {
return advertisement.getTranslations().stream()
.filter(t -> t.getLanguage().equals(language))
.findFirst().orElseThrow(() -> new TranslateException(NO_TRANSLATION));
}

private void addTranslation(Advertisement advertisement, AdvertisementTranslate translation) {
if (checkLanguage(advertisement, translation.getLanguage())) {
throw new TranslateException(LANGUAGE_IS_PRESENT_IN_LIST);
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/org/petmarket/review/dto/AverageReview.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.petmarket.review.dto;

public interface AverageReview {
Integer getCount();

Integer getSum();
}
63 changes: 52 additions & 11 deletions src/main/java/org/petmarket/review/listener/ReviewListener.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,63 @@
package org.petmarket.review.listener;

import jakarta.persistence.*;
import org.petmarket.advertisements.advertisement.service.AdvertisementService;
import org.petmarket.advertisements.advertisement.entity.Advertisement;
import org.petmarket.advertisements.advertisement.repository.AdvertisementRepository;
import org.petmarket.review.dto.AverageReview;
import org.petmarket.review.entity.Review;
import org.springframework.context.annotation.Lazy;
import org.petmarket.review.repository.ReviewRepository;
import org.petmarket.users.entity.User;
import org.petmarket.users.repository.UserRepository;
import org.petmarket.utils.BeanUtils;

public class ReviewListener {
private final AdvertisementService advertisementService;
@PrePersist
public void updateRatingForNewReview(Review review) {
ReviewRepository reviewRepository = BeanUtils.getBean(ReviewRepository.class);
AdvertisementRepository advertisementRepository = BeanUtils.getBean(AdvertisementRepository.class);
UserRepository userRepository = BeanUtils.getBean(UserRepository.class);

public ReviewListener(@Lazy AdvertisementService advertisementService) {
this.advertisementService = advertisementService;
Advertisement advertisement = review.getAdvertisement();
User user = review.getUser();
AverageReview advertisementAverageReview = reviewRepository
.findAverageReviewByAdvertisementId(advertisement.getId());
AverageReview userAverageReview = reviewRepository
.findAverageReviewByUserId(review.getUser().getId());
advertisement.setRating((advertisementAverageReview.getSum() + review.getValue())
/ (advertisementAverageReview.getCount() + 1));
user.setRating((userAverageReview.getSum() + review.getValue()) / (userAverageReview.getCount() + 1));

advertisementRepository.save(advertisement);
userRepository.save(user);
}

@PostPersist
@PostUpdate
@PostRemove
public void updateRating(Review review) {
advertisementService.updateRating(review);
advertisementService.updateTopRating(review.getAdvertisement());
@PreRemove
public void updateRatingForReviewRemoval(Review review) {
ReviewRepository reviewRepository = BeanUtils.getBean(ReviewRepository.class);
AdvertisementRepository advertisementRepository = BeanUtils.getBean(AdvertisementRepository.class);
UserRepository userRepository = BeanUtils.getBean(UserRepository.class);

Advertisement advertisement = review.getAdvertisement();
User user = review.getUser();
AverageReview advertisementAverageReview = reviewRepository
.findAverageReviewByAdvertisementId(advertisement.getId());
AverageReview userAverageReview = reviewRepository
.findAverageReviewByUserId(review.getUser().getId());

if (advertisementAverageReview.getCount() == 1) {
advertisement.setRating(0);
} else {
advertisement.setRating((advertisementAverageReview.getSum() - review.getValue())
/ (advertisementAverageReview.getCount() - 1));
}

if (userAverageReview.getCount() == 1) {
user.setRating(0);
} else {
user.setRating((userAverageReview.getSum() - review.getValue()) / (userAverageReview.getCount() - 1));
}

advertisementRepository.save(advertisement);
userRepository.save(user);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package org.petmarket.review.repository;

import org.petmarket.advertisements.advertisement.entity.AdvertisementStatus;
import org.petmarket.review.dto.AverageReview;
import org.petmarket.review.entity.Review;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
Expand Down Expand Up @@ -68,5 +66,19 @@ SELECT COALESCE(AVG(review_value), 0) FROM reviews
""", nativeQuery = true)
Integer findAverageRatingByUserId(@Param("id") Long id);

Page<Review> findAllByAdvertisementStatus(AdvertisementStatus status, Pageable pageable);
@Query(value = """
SELECT COALESCE(COUNT(r), 0) AS count, COALESCE(SUM(r.value), 0) AS sum
FROM Review r
JOIN r.advertisement a
WHERE a.id = :id
""")
AverageReview findAverageReviewByAdvertisementId(Long id);

@Query(value = """
SELECT COALESCE(COUNT(r), 0) AS count, COALESCE(SUM(r.value), 0) AS sum
FROM Review r
JOIN r.user u
WHERE u.id = :id
""")
AverageReview findAverageReviewByUserId(Long id);
}
5 changes: 0 additions & 5 deletions src/main/java/org/petmarket/review/service/ReviewService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.search.mapper.orm.Search;
import org.hibernate.search.mapper.orm.massindexing.MassIndexer;
import org.hibernate.search.mapper.orm.session.SearchSession;
import org.petmarket.advertisements.advertisement.entity.Advertisement;
import org.petmarket.advertisements.advertisement.entity.AdvertisementStatus;
import org.petmarket.advertisements.advertisement.repository.AdvertisementRepository;
import org.petmarket.errorhandling.ItemNotFoundException;
import org.petmarket.order.repository.OrderRepository;
Expand All @@ -18,8 +15,6 @@
import org.petmarket.users.entity.User;
import org.petmarket.users.repository.UserRepository;
import org.petmarket.users.service.UserCacheService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.Collections;
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/org/petmarket/utils/BeanUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.petmarket.utils;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class BeanUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
BeanUtils.applicationContext = applicationContext;
}

public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
}

0 comments on commit 0d07d7d

Please sign in to comment.