-
Notifications
You must be signed in to change notification settings - Fork 4
Perf: [BADA-368] 추천 고도화 #399
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1cbedb5
ca3b38b
631ba86
5a87380
1be230b
604d8ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package com.TwoSeaU.BaData.domain.trade.controller; | ||
|
|
||
| import com.TwoSeaU.BaData.domain.trade.service.PostService; | ||
| import com.TwoSeaU.BaData.global.response.ApiResponse; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.PostMapping; | ||
| import org.springframework.web.bind.annotation.RequestMapping; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| @RestController | ||
| @RequiredArgsConstructor | ||
| @RequestMapping("/api/v1/trades") | ||
| public class MockController { | ||
| private final PostService postService; | ||
|
|
||
| @PostMapping("/mock/posts") | ||
| public ResponseEntity<ApiResponse<String>> createMockPost() { | ||
| return ResponseEntity.ok().body(ApiResponse.success(postService.generateGifticons())); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -3,7 +3,10 @@ | |||||
| import com.TwoSeaU.BaData.domain.trade.dto.response.PostsResponse; | ||||||
| import com.TwoSeaU.BaData.domain.trade.dto.response.SaveRecommendLikesResponse; | ||||||
| import com.TwoSeaU.BaData.domain.trade.service.LikeService; | ||||||
| import com.TwoSeaU.BaData.domain.trade.service.RecommendService; | ||||||
| import com.TwoSeaU.BaData.domain.trade.service.recommend.GlobalRecommendService; | ||||||
| import com.TwoSeaU.BaData.domain.trade.service.recommend.doubleVector.RecommendServiceDouble; | ||||||
| import com.TwoSeaU.BaData.domain.trade.service.recommend.floatVector.RecommendServiceFloat; | ||||||
| import com.TwoSeaU.BaData.domain.trade.service.recommend.pgVector.RecommendServicePg; | ||||||
| import com.TwoSeaU.BaData.global.response.ApiResponse; | ||||||
| import lombok.RequiredArgsConstructor; | ||||||
| import org.springframework.http.ResponseEntity; | ||||||
|
|
@@ -15,16 +18,40 @@ | |||||
| @RequiredArgsConstructor | ||||||
| @RequestMapping("/api/v1/trades/posts/recommend") | ||||||
| public class RecommendController { | ||||||
| private final RecommendService recommendService; | ||||||
| private final RecommendServiceDouble doubleRecommendServiceDouble; | ||||||
| private final RecommendServiceFloat floatRecommendServiceFloat; | ||||||
| private final RecommendServicePg pgvectorRecommendServicePg; | ||||||
| private final GlobalRecommendService globalRecommendService; | ||||||
| private final LikeService likeService; | ||||||
|
|
||||||
| @GetMapping("/double") | ||||||
| public ResponseEntity<ApiResponse<PostsResponse>> recommendPostsByDouble(@AuthenticationPrincipal User user, @RequestParam(defaultValue = "true") boolean isStart) { | ||||||
| return ResponseEntity.ok().body(ApiResponse.success(doubleRecommendServiceDouble.recommendPosts(user == null ? null : user.getUsername(), isStart))); | ||||||
| } | ||||||
|
|
||||||
| @GetMapping("/float") | ||||||
| public ResponseEntity<ApiResponse<PostsResponse>> recommendPostsByFloat(@AuthenticationPrincipal User user, @RequestParam(defaultValue = "true") boolean isStart) { | ||||||
| return ResponseEntity.ok().body(ApiResponse.success(floatRecommendServiceFloat.recommendPostsByFloat(user == null ? null : user.getUsername(), isStart))); | ||||||
| } | ||||||
|
|
||||||
| //@GetMapping("/pgvector") | ||||||
| @GetMapping | ||||||
| public ResponseEntity<ApiResponse<PostsResponse>> recommendPosts(@AuthenticationPrincipal User user, @RequestParam(defaultValue = "true") boolean isStart) { | ||||||
| return ResponseEntity.ok().body(ApiResponse.success(recommendService.recommendPosts(user == null ? null : user.getUsername(), isStart))); | ||||||
| public ResponseEntity<ApiResponse<PostsResponse>> recommendPostsByPgvector(@AuthenticationPrincipal User user, @RequestParam(defaultValue = "true") boolean isStart) { | ||||||
| return ResponseEntity.ok().body(ApiResponse.success(pgvectorRecommendServicePg.recommendPostsBypgVector(user == null ? null : user.getUsername(), isStart))); | ||||||
| } | ||||||
|
|
||||||
| @PostMapping("/likes/{postId}") | ||||||
| public ResponseEntity<ApiResponse<SaveRecommendLikesResponse>> likeRecommendation(@AuthenticationPrincipal User user, @PathVariable Long postId) { | ||||||
| return ResponseEntity.ok().body(ApiResponse.success(likeService.likesAtRecommendation(user == null ? null : user.getUsername(), postId))); | ||||||
| } | ||||||
|
|
||||||
| @PatchMapping("/vector/update/all/double") | ||||||
| public ResponseEntity<ApiResponse<String>> updateAllPostForDouble() { | ||||||
| return ResponseEntity.ok().body(ApiResponse.success(globalRecommendService.updateAllDoubleVector())); | ||||||
| } | ||||||
|
|
||||||
| @PatchMapping("/vector/update/all/float") | ||||||
| public ResponseEntity<ApiResponse<String>> updateAllPostVectorForPgvector() { | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 메서드명과 기능 불일치
-public ResponseEntity<ApiResponse<String>> updateAllPostVectorForPgvector() {
+public ResponseEntity<ApiResponse<String>> updateAllPostVectorForFloatAndPg() {📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| return ResponseEntity.ok().body(ApiResponse.success(globalRecommendService.updateAllFloatAndPgVector())); | ||||||
| } | ||||||
|
Comment on lines
+48
to
+56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 벌크 벡터 업데이트 엔드포인트 보안 우려 벌크 벡터 업데이트 엔드포인트들이 인증 없이 노출되어 있어 보안상 위험할 수 있습니다. 관리자 권한 검증을 추가해주세요: @PatchMapping("/vector/update/all/double")
-public ResponseEntity<ApiResponse<String>> updateAllPostForDouble() {
+public ResponseEntity<ApiResponse<String>> updateAllPostForDouble(@AuthenticationPrincipal User user) {
+ // 관리자 권한 검증 로직 추가
return ResponseEntity.ok().body(ApiResponse.success(globalRecommendService.updateAllDoubleVector()));
}또는 별도의 관리자 컨트롤러로 분리하는 것을 고려해주세요. 🤖 Prompt for AI Agents |
||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,7 +23,9 @@ public class Gifticon extends Post{ | |
| @Column(nullable = false) | ||
| private String partner; | ||
|
|
||
| private double[] vector; | ||
| private double[] doubleVector; | ||
|
|
||
| private float[] floatVector; | ||
|
|
||
| @ManyToOne(fetch = FetchType.EAGER) | ||
| @JoinColumn(name = "category_id", nullable = false) | ||
|
|
@@ -34,16 +36,21 @@ public class Gifticon extends Post{ | |
| public Gifticon(final User user, final String title, final String comment, final BigDecimal price, | ||
| final LocalDate deadLine, final String postImage, final Boolean isSold, | ||
| final String couponNumber, final String partner, final GifticonCategory category, | ||
| final double[] vector) { | ||
| final double[] doubleVector, final float[] floatVector) { | ||
| super(user, title, comment, price, deadLine, postImage, isSold); | ||
| this.couponNumber = couponNumber; | ||
| this.partner = partner; | ||
| this.category = category; | ||
| this.vector = vector; | ||
| this.doubleVector = doubleVector; | ||
| this.floatVector = floatVector; | ||
| } | ||
|
|
||
| public void updateDoubleVector(final double[] doubleVector) { | ||
| this.doubleVector = doubleVector; | ||
| } | ||
|
|
||
| public void updateVector(final double[] vector) { | ||
| this.vector = vector; | ||
| public void updateFloatVector(final float[] floatVector) { | ||
| this.floatVector = floatVector; | ||
| } | ||
|
Comment on lines
+48
to
54
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 벡터 차원 검증 필요 벡터 업데이트 시 예상 차원과 일치하는지 검증이 없습니다. 잘못된 차원의 벡터가 저장되면 추천 시스템에서 오류가 발생할 수 있습니다. public void updateDoubleVector(final double[] doubleVector) {
+ // 예상 벡터 차원 검증 추가
+ if (doubleVector != null && doubleVector.length != EXPECTED_VECTOR_SIZE) {
+ throw new IllegalArgumentException("Invalid vector dimension: " + doubleVector.length);
+ }
this.doubleVector = doubleVector;
}
public void updateFloatVector(final float[] floatVector) {
+ if (floatVector != null && floatVector.length != EXPECTED_VECTOR_SIZE) {
+ throw new IllegalArgumentException("Invalid vector dimension: " + floatVector.length);
+ }
this.floatVector = floatVector;
}
🤖 Prompt for AI Agents |
||
|
|
||
| public void updateBarcodeViewTime(final LocalDateTime barcodeViewTime) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package com.TwoSeaU.BaData.domain.trade.entity; | ||
|
|
||
| import jakarta.persistence.*; | ||
| import lombok.AccessLevel; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
|
|
||
| @Entity | ||
| @Getter | ||
| @NoArgsConstructor(access = AccessLevel.PRIVATE) | ||
| @AllArgsConstructor(access = AccessLevel.PRIVATE) | ||
| @Table(name = "post_vector") | ||
| public class PostVector { | ||
| @Id | ||
| private Long id; | ||
|
|
||
| @Column(name = "vector_pg", columnDefinition = "vector(57)") | ||
| private float[] vectorPg; | ||
|
Comment on lines
+18
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chain벡터 차원 수를 검증하세요.
벡터 차원을 확인하기 위해 다음 스크립트를 실행하세요: 🏁 Script executed: #!/bin/bash
# 벡터화 서비스에서 실제 생성되는 벡터 차원 확인
ast-grep --pattern 'vectorizePost($$$) {
$$$
return vectorUtils.concatenate($$$);
}'
# 카테고리와 파트너 인덱스 맵의 크기 확인
rg -A 3 "categoryToIndex.*put|partnerToIndex.*put"Length of output: 2853 🏁 Script executed: #!/bin/bash
# 전체 PostVectorizer 클래스 내용 및 벡터화 메서드 확인
sed -n '1,200p' src/main/java/com/TwoSeaU/BaData/domain/trade/service/PostVectorizer.java
# vectorizePost 메서드 시그니처와 내부 concatenate 호출 위치 확인
rg "vectorizePost" -A5 src/main/java/com/TwoSeaU/BaData/domain/trade/service/PostVectorizer.java
rg "concatenate" -A5 src/main/java/com/TwoSeaU/BaData/domain/trade/service/PostVectorizer.java
# 카테고리 및 제휴사 리스트 초기화 위치 확인
rg "List<.*categories" -A3 src/main/java/com/TwoSeaU/BaData/domain/trade/service/PostVectorizer.java
rg "List<.*partners" -A3 src/main/java/com/TwoSeaU/BaData/domain/trade/service/PostVectorizer.javaLength of output: 4581 벡터 차원 크기 검증 및 상수화 필요
선택 사항:
– src/main/java/com/TwoSeaU/BaData/domain/trade/entity/PostVector.java, 18–19번 라인 확인 🤖 Prompt for AI Agents |
||
|
|
||
| @OneToOne(fetch = FetchType.LAZY) | ||
| @MapsId | ||
| @JoinColumn(name = "id") | ||
| private Post post; | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,92 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package com.TwoSeaU.BaData.domain.trade.repository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.TwoSeaU.BaData.domain.trade.entity.Gifticon; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.TwoSeaU.BaData.domain.trade.exception.TradeException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.TwoSeaU.BaData.domain.trade.service.recommend.floatVector.RecommendServiceFloat; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 아키텍처 계층 분리 위반 Repository 계층에서 Service 계층의 클래스( 별도의 DTO 클래스를 생성하여 계층 간 의존성을 해결하는 것을 권장합니다: -import com.TwoSeaU.BaData.domain.trade.service.recommend.floatVector.RecommendServiceFloat;
+// RecommendationResult를 별도 DTO로 분리하여 domain.dto 패키지에 위치
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.TwoSeaU.BaData.global.response.GeneralException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import lombok.RequiredArgsConstructor; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.jdbc.core.JdbcTemplate; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.stereotype.Repository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javax.sql.DataSource; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.sql.Connection; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.sql.SQLException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Repository | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @RequiredArgsConstructor | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class JdbcRepository { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final GifticonRepository gifticonRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final DataSource dataSource; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final JdbcTemplate jdbcTemplate; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final int LIMIT = 10; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public List<RecommendServiceFloat.RecommendationResult> findSimilarPosts(final float[] userVector, final int alreadyViewCount) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final String sql = """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT id, vector_pg <=> ?::vector AS similarity | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FROM post_vector | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ORDER BY vector_pg <=> ?::vector | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| limit ? | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try (Connection conn = dataSource.getConnection()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return jdbcTemplate.query( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sql, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ps -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ps.setObject(1, toPgvectorString(userVector)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ps.setObject(2, toPgvectorString(userVector)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ps.setInt(3, LIMIT + alreadyViewCount); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (rs, rowNum) -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Long postId = rs.getLong("id"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.out.println("Post ID: " + postId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Gifticon gifticon = gifticonRepository.findById(postId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .orElseThrow(() -> new GeneralException(TradeException.POST_NOT_FOUND)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return new RecommendServiceFloat.RecommendationResult( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| gifticon, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rs.getDouble("similarity"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rs.getDouble("similarity") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (SQLException e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new RuntimeException("추천 게시글 검색 실패", e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+33
to
+57
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 리소스 관리 및 성능 개선 필요 여러 개선 사항이 필요합니다:
다음과 같이 개선하세요: - try (Connection conn = dataSource.getConnection()) {
- return jdbcTemplate.query(
- sql,
- ps -> {
- ps.setObject(1, toPgvectorString(userVector));
- ps.setObject(2, toPgvectorString(userVector));
- ps.setInt(3, LIMIT + alreadyViewCount);
- },
- (rs, rowNum) -> {
- Long postId = rs.getLong("id");
- System.out.println("Post ID: " + postId);
- Gifticon gifticon = gifticonRepository.findById(postId)
- .orElseThrow(() -> new GeneralException(TradeException.POST_NOT_FOUND));
+ return jdbcTemplate.query(
+ sql,
+ ps -> {
+ String vectorString = toPgvectorString(userVector);
+ ps.setObject(1, vectorString);
+ ps.setObject(2, vectorString);
+ ps.setInt(3, LIMIT + alreadyViewCount);
+ },
+ (rs, rowNum) -> {
+ Long postId = rs.getLong("id");
+ Gifticon gifticon = gifticonRepository.findById(postId)
+ .orElseThrow(() -> new GeneralException(TradeException.POST_NOT_FOUND));
- return new RecommendServiceFloat.RecommendationResult(
- gifticon,
- rs.getDouble("similarity"),
- rs.getDouble("similarity")
- );
- }
- );
-
- } catch (SQLException e) {
- throw new RuntimeException("추천 게시글 검색 실패", e);
- }
+ return new RecommendServiceFloat.RecommendationResult(
+ gifticon,
+ rs.getDouble("similarity"),
+ rs.getDouble("similarity")
+ );
+ }
+ );📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void insertPostVector(final Long postId, final float[] vector) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final String sql = "INSERT INTO post_vector (id, vector_pg) VALUES (?, ?::vector)"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try (Connection conn = dataSource.getConnection()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jdbcTemplate.update(sql, postId, toPgvectorString(vector)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (SQLException e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new RuntimeException("Post vector insert failed", e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+63
to
+67
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 불필요한 Connection 관리 JdbcTemplate이 연결을 내부적으로 관리하므로 수동 Connection 생성이 불필요합니다. - try (Connection conn = dataSource.getConnection()) {
- jdbcTemplate.update(sql, postId, toPgvectorString(vector));
- } catch (SQLException e) {
- throw new RuntimeException("Post vector insert failed", e);
- }
+ jdbcTemplate.update(sql, postId, toPgvectorString(vector));📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void updatePostVector(final Long postId, final float[] vector) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final String sql = "UPDATE post_vector SET vector_pg = ?::vector WHERE id = ?"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try (Connection conn = dataSource.getConnection()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jdbcTemplate.update(sql, toPgvectorString(vector), postId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (SQLException e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new RuntimeException("Post vector update failed", e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+73
to
+77
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Connection 관리 및 매개변수 순서 일관성
- try (Connection conn = dataSource.getConnection()) {
- jdbcTemplate.update(sql, toPgvectorString(vector), postId);
- } catch (SQLException e) {
- throw new RuntimeException("Post vector update failed", e);
- }
+ jdbcTemplate.update(sql, toPgvectorString(vector), postId);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private String toPgvectorString(float[] vector) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| StringBuilder sb = new StringBuilder(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sb.append("["); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (int i = 0; i < vector.length; i++) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sb.append(vector[i]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (i < vector.length - 1) sb.append(", "); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sb.append("]"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return sb.toString(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
필드명과 타입 불일치
필드명에 타입 정보가 중복되어 있어 가독성이 떨어집니다.
이에 따라 메서드 호출부도 수정해야 합니다.
📝 Committable suggestion
🤖 Prompt for AI Agents