From c4491a55eebaccaa3d158523513f4f449e02470e Mon Sep 17 00:00:00 2001 From: Darya346 Date: Mon, 23 Feb 2026 00:14:59 +0300 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=B7=D0=B0=D0=BC=D0=B5=D1=87=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=B2=20getRecommendations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dal/FilmStorage.java | 1 + .../filmorate/dal/database/FilmDbStorage.java | 59 ++++++++++--------- .../dal/inmemory/InMemoryFilmStorage.java | 5 ++ .../filmorate/service/FilmService.java | 14 +++++ .../filmorate/service/UserService.java | 33 +++++++---- 5 files changed, 74 insertions(+), 38 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmStorage.java index ab96136..1fe9ca9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmStorage.java @@ -51,4 +51,5 @@ public interface FilmStorage { /// Удаление фильма по id void removeFilm(long filmId); + Collection getFilmsByIds(Collection ids); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/database/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dal/database/FilmDbStorage.java index 6e83ce2..eac5594 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/database/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/database/FilmDbStorage.java @@ -39,7 +39,7 @@ public Film createFilm(Film film) { film.setId(id); insertGenreIds(film); insertDirectorIds(film); - return film; + return findById(id).get(); } @Override @@ -56,7 +56,7 @@ public Film updateFilm(Film film) { ); insertGenreIds(film); insertDirectorIds(film); - return film; + return findById(film.getId()).get(); } @Override @@ -157,29 +157,19 @@ public void removeFilm(long filmId) { } private void insertGenreIds(Film film) { - Set genreIds = film.getGenreIds(); - if (genreIds.isEmpty()) { - jdbc.update("DELETE FROM genres_of_films WHERE film_id = ?", film.getId()); - return; - } jdbc.update("DELETE FROM genres_of_films WHERE film_id = ?", film.getId()); - String placeholders = String.join( - ",", Collections.nCopies(genreIds.size(), " (" + film.getId() + ", ?)") - ); + Set genreIds = film.getGenreIds(); + if (genreIds == null || genreIds.isEmpty()) return; + String placeholders = String.join(",", Collections.nCopies(genreIds.size(), " (" + film.getId() + ", ?)")); String sql = SQL_FILMS_INSERT_GENREIDS + placeholders; updateWithControl(sql, genreIds.toArray()); } private void insertDirectorIds(Film film) { - Set directorIds = film.getDirectorIds(); - if (directorIds.isEmpty()) { - jdbc.update("DELETE FROM directors_of_films WHERE film_id = ?", film.getId()); - return; - } jdbc.update("DELETE FROM directors_of_films WHERE film_id = ?", film.getId()); - String placeholders = String.join( - ",", Collections.nCopies(directorIds.size(), " (" + film.getId() + ", ?)") - ); + Set directorIds = film.getDirectorIds(); + if (directorIds == null || directorIds.isEmpty()) return; + String placeholders = String.join(",", Collections.nCopies(directorIds.size(), " (" + film.getId() + ", ?)")); String sql = SQL_FILMS_INSERT_DIRECTORIDS + placeholders; updateWithControl(sql, directorIds.toArray()); } @@ -198,17 +188,11 @@ private Collection findManyFilms(String query, Object... params) { } }); long userId = rs.getLong("user_id"); - if (!rs.wasNull() && film != null) { - film.addLike(userId); - } + if (!rs.wasNull() && film != null) film.addLike(userId); int genreId = rs.getInt("genre_id"); - if (!rs.wasNull() && film != null) { - film.addGenreId(genreId); - } + if (!rs.wasNull() && film != null) film.addGenreId(genreId); int directorId = rs.getInt("director_id"); - if (!rs.wasNull() && film != null) { - film.addDirectorId(directorId); - } + if (!rs.wasNull() && film != null) film.addDirectorId(directorId); } return new ArrayList<>(films.values()); }, params); @@ -221,4 +205,25 @@ private Set getGenreIdsByFilmId(long filmId) { private Set getDirectorIdsByFilmId(long filmId) { return findColumnByQuery(SQL_FILMS_FIND_DIRECTORIDS_BY_FILM_ID, Integer.class, filmId); } + + @Override + public Collection getFilmsByIds(Collection ids) { + if (ids == null || ids.isEmpty()) { + return Collections.emptyList(); + } + + String inSql = String.join(",", Collections.nCopies(ids.size(), "?")); + + String sql = String.format(""" + SELECT f.id, f.film_name, f.description, f.release_date, f.duration, f.mpa_id, + l.user_id, gof.genre_id, dof.director_id + FROM films f + LEFT JOIN likes l ON f.id = l.film_id + LEFT JOIN genres_of_films gof ON f.id = gof.film_id + LEFT JOIN directors_of_films dof ON f.id = dof.film_id + WHERE f.id IN (%s) + """, inSql); + + return findManyFilms(sql, ids.toArray()); + } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/inmemory/InMemoryFilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dal/inmemory/InMemoryFilmStorage.java index 39e60e9..bdbb0ed 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/inmemory/InMemoryFilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/inmemory/InMemoryFilmStorage.java @@ -82,4 +82,9 @@ public Collection search(String query, String by) { public void removeFilm(long filmId) { throw new MethodNotImplementedException(); } + + @Override + public Collection getFilmsByIds(Collection ids) { + throw new MethodNotImplementedException(); + } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 894a280..569e0c5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -354,4 +354,18 @@ public Collection search(String query, String by) { )) .toList(); } + + public Collection getFilmsByIds(Collection ids) { + if (ids == null || ids.isEmpty()) { + return Collections.emptyList(); + } + return filmStorage.getFilmsByIds(ids).stream() + .map(film -> FilmMapper.mapToFilmDto( + film, + mpas.get(film.getMpaId()), + getGenresByIds(film.getGenreIds()), + getDirectorsByIds(film.getDirectorIds()) + )) + .toList(); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 6799afe..621a247 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -206,7 +206,6 @@ private void logUserUpdate(UserUpdateRequest request, User user) { log.info("Данные для обновления: [{}]", updatedData); } - // Рекомендации public Collection getRecommendations(long userId) { log.info("Получение рекомендаций для пользователя id={}.", userId); easyCheckUser(userId); @@ -218,8 +217,7 @@ public Collection getRecommendations(long userId) { return Collections.emptyList(); } - long similarUserId = -1; - int maxOverlap = 0; + Map similarityMap = new HashMap<>(); for (Map.Entry> entry : allLikes.entrySet()) { long otherUserId = entry.getKey(); @@ -230,20 +228,33 @@ public Collection getRecommendations(long userId) { .filter(otherUserLikes::contains) .count(); - if (overlap > maxOverlap) { - maxOverlap = overlap; - similarUserId = otherUserId; + if (overlap > 0) { + similarityMap.put(otherUserId, overlap); } } - if (similarUserId == -1) { + if (similarityMap.isEmpty()) { return Collections.emptyList(); } - Set similarUserLikes = allLikes.get(similarUserId); - return similarUserLikes.stream() - .filter(filmId -> !targetUserLikes.contains(filmId)) - .map(filmService::findById) + List similarUserIds = similarityMap.entrySet().stream() + .sorted(Map.Entry.comparingByValue().reversed()) + .limit(15) + .map(Map.Entry::getKey) .collect(Collectors.toList()); + + Set recommendedFilmIds = new HashSet<>(); + for (Long simId : similarUserIds) { + Set likedBySimilarUser = allLikes.get(simId); + likedBySimilarUser.stream() + .filter(filmId -> !targetUserLikes.contains(filmId)) + .forEach(recommendedFilmIds::add); + } + + if (recommendedFilmIds.isEmpty()) { + return Collections.emptyList(); + } + + return filmService.getFilmsByIds(recommendedFilmIds); } } From 33681bbade95f0332e8ae8f56500fdce58f480cf Mon Sep 17 00:00:00 2001 From: Darya346 Date: Mon, 23 Feb 2026 00:49:48 +0300 Subject: [PATCH 2/2] fix: remove unused import in ReviewService --- .../ru/yandex/practicum/filmorate/service/ReviewService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index 54b1094..2dd323c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -18,7 +18,6 @@ import java.util.Collection; import java.util.Optional; -import java.util.stream.Stream; @Service @Slf4j