Skip to content
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

[feat] text 기반 게시물 검색 api 개발 #9

Merged
merged 13 commits into from
Dec 29, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.gachon.checkmate.domain.checkList.repository;

import org.gachon.checkmate.domain.checkList.entity.CheckList;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface CheckListRepository extends JpaRepository<CheckList, Long> {
Optional<CheckList> findByUserId(Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import org.gachon.checkmate.domain.member.converter.GenderTypeConverter;
import org.gachon.checkmate.domain.member.converter.MbtiTypeConverter;
import org.gachon.checkmate.domain.member.converter.RoomTypeConverter;
import org.gachon.checkmate.domain.post.entity.PostMaker;
import org.gachon.checkmate.domain.post.entity.Post;
import org.gachon.checkmate.domain.scrap.entity.Scrap;
import org.gachon.checkmate.global.common.BaseTimeEntity;

Expand Down Expand Up @@ -40,7 +40,7 @@ public class User extends BaseTimeEntity {
private CheckList checkList;
@OneToMany(mappedBy = "user")
@Builder.Default
private List<PostMaker> postMakerList = new ArrayList<>();
private List<Post> postList = new ArrayList<>();
@OneToMany(mappedBy = "user")
@Builder.Default
private List<Scrap> scrapList = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.gachon.checkmate.domain.post.controller;

import lombok.RequiredArgsConstructor;
import org.gachon.checkmate.domain.post.dto.response.PostSearchResponseDto;
import org.gachon.checkmate.domain.post.service.PostService;
import org.gachon.checkmate.global.common.SuccessResponse;
import org.gachon.checkmate.global.config.auth.UserId;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RequiredArgsConstructor
@RequestMapping("/api/post")
@RestController
public class PostController {
private final PostService postService;

@GetMapping("/search")
public ResponseEntity<SuccessResponse<?>> searchTextPost(@UserId final Long userId,
@RequestParam final String text,
final Pageable pageable) {
final List<PostSearchResponseDto> responseDto = postService.searchTextPost(userId, text, pageable);
return SuccessResponse.ok(responseDto);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.gachon.checkmate.domain.post.dto.response;

import lombok.Builder;
import org.gachon.checkmate.domain.post.dto.support.PostSearchDto;

@Builder
public record PostSearchResponseDto(
String title,
String content,
String importantKey,
String similarityKey,
int scrapCount,
int remainDate,
int accuracy
) {
public static PostSearchResponseDto of(PostSearchDto postSearchDto,
int remainDate,
int accuracy) {
return PostSearchResponseDto.builder()
.title(postSearchDto.title())
.content(postSearchDto.content())
.importantKey(postSearchDto.importantKey().getDesc())
.similarityKey(postSearchDto.similarityKey().getDesc())
.scrapCount(postSearchDto.scrapCount())
.remainDate(remainDate)
.accuracy(accuracy)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.gachon.checkmate.domain.post.dto.support;

import com.querydsl.core.annotations.QueryProjection;
import org.gachon.checkmate.domain.checkList.entity.PostCheckList;
import org.gachon.checkmate.domain.post.entity.ImportantKeyType;
import org.gachon.checkmate.domain.post.entity.SimilarityKeyType;

import java.time.LocalDate;

public record PostSearchDto(
String title,
String content,
ImportantKeyType importantKey,
SimilarityKeyType similarityKey,
LocalDate endDate,
int scrapCount,
PostCheckList postCheckList
) {
@QueryProjection
public PostSearchDto(String title, String content, ImportantKeyType importantKey, SimilarityKeyType similarityKey, LocalDate endDate, int scrapCount, PostCheckList postCheckList) {
this.title = title;
this.content = content;
this.importantKey = importantKey;
this.similarityKey = similarityKey;
this.endDate = endDate;
this.scrapCount = scrapCount;
this.postCheckList = postCheckList;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.gachon.checkmate.domain.checkList.entity.PostCheckList;
import org.gachon.checkmate.domain.member.converter.RoomTypeConverter;
import org.gachon.checkmate.domain.member.entity.RoomType;
import org.gachon.checkmate.domain.member.entity.User;
import org.gachon.checkmate.domain.post.converter.ImportantKeyTypeConverter;
import org.gachon.checkmate.domain.post.converter.SimilarityKeyTypeConverter;
import org.gachon.checkmate.domain.scrap.entity.Scrap;
Expand All @@ -26,7 +27,7 @@ public class Post extends BaseTimeEntity {
private Long id;
private String title;
private String content;
private LocalDate EndDate;
private LocalDate endDate;
@Convert(converter = RoomTypeConverter.class)
private RoomType roomType;
@Convert(converter = ImportantKeyTypeConverter.class)
Expand All @@ -35,9 +36,9 @@ public class Post extends BaseTimeEntity {
private SimilarityKeyType similarityKeyType;
@OneToOne(mappedBy = "post", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private PostCheckList postCheckList;
@OneToMany(mappedBy = "post")
@Builder.Default
private List<PostMaker> postMakerList = new ArrayList<>();
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
@OneToMany(mappedBy = "post")
@Builder.Default
private List<Scrap> scrapList = new ArrayList<>();
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.gachon.checkmate.domain.post.repository;

import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.gachon.checkmate.domain.post.dto.support.PostSearchDto;
import org.gachon.checkmate.domain.post.dto.support.QPostSearchDto;
import org.gachon.checkmate.domain.post.entity.Post;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.stereotype.Repository;

import java.time.LocalDate;
import java.util.List;

import static org.gachon.checkmate.domain.checkList.entity.QPostCheckList.postCheckList;
import static org.gachon.checkmate.domain.post.entity.QPost.post;

@RequiredArgsConstructor
@Repository
public class PostQuerydslRepository {
private final JPAQueryFactory queryFactory;

public Page<PostSearchDto> searchTextPost(String text, Pageable pageable) {
List<PostSearchDto> content = queryFactory
.select(new QPostSearchDto(
post.title,
post.content,
post.importantKeyType,
post.similarityKeyType,
post.endDate,
post.scrapList.size(),
postCheckList
))
.from(post)
.leftJoin(post.postCheckList, postCheckList)
.where(
post.title.contains(text),
post.endDate.before(LocalDate.now())
)
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();

JPAQuery<Post> countQuery = queryFactory
.selectFrom(post);
return PageableExecutionUtils.getPage(content, pageable, countQuery::fetchCount);
}
}
RyuKwanKon marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package org.gachon.checkmate.domain.post.service;

import lombok.RequiredArgsConstructor;
import org.gachon.checkmate.domain.checkList.entity.CheckList;
import org.gachon.checkmate.domain.checkList.entity.PostCheckList;
import org.gachon.checkmate.domain.checkList.repository.CheckListRepository;
import org.gachon.checkmate.domain.post.dto.response.PostSearchResponseDto;
import org.gachon.checkmate.domain.post.dto.support.PostSearchDto;
import org.gachon.checkmate.domain.post.repository.PostQuerydslRepository;
import org.gachon.checkmate.global.error.exception.EntityNotFoundException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.stream.Collectors;

import static org.gachon.checkmate.global.error.ErrorCode.CHECK_LIST_NOT_FOUND;


@RequiredArgsConstructor
@Transactional
@Service
public class PostService {
private final CheckListRepository checkListRepository;
private final PostQuerydslRepository postQuerydslRepository;

public List<PostSearchResponseDto> searchTextPost(Long userId, String text, Pageable pageable) {
CheckList checkList = getCheckList(userId);
Page<PostSearchDto> postSearchDtoList = getPostSearchDto(text, pageable);
return createPostSearchResponseDto(postSearchDtoList, checkList);
}

private List<PostSearchResponseDto> createPostSearchResponseDto(Page<PostSearchDto> postSearchDtoList, CheckList checkList) {
return postSearchDtoList.stream()
.map(postSearchDto ->
PostSearchResponseDto.of(
postSearchDto,
getRemainDate(postSearchDto.endDate()),
getAccuracy(postSearchDto.postCheckList(), checkList)
))
.collect(Collectors.toList());
}

private int getAccuracy(PostCheckList postCheckList, CheckList checkList) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

정확도 구하는 부분에서
image
이런식으로 음주의 경우 안마심. 2~3회, 4~5회 이런식으로 있는데 내가 4~5회로 체크했다고 가정할 때
"안마심" 과 "2~3회" 체크한 게시물 두개 모두 정확도를 해당 부부분에서 0점을 가져가는게 맞을지 고민이 됩니다. 너무 복잡해지려나요

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

빈도에 해당하는 checklist의 정확도를 측정하는 로직을 최신화했습니다. 의견주시고 확인하시면 resolve conversation 눌러주세요

int count = 0;
count += getRateForFrequencyElement(postCheckList.getCleanType().getCode(), checkList.getCleanType().getCode(), 5);
RyuKwanKon marked this conversation as resolved.
Show resolved Hide resolved
count += getRateForFrequencyElement(postCheckList.getDrinkType().getCode(), checkList.getDrinkType().getCode(), 4);
count += getRateForFrequencyElement(postCheckList.getHomeType().getCode(), checkList.getHomeType().getCode(), 4);
count = postCheckList.getLifePatterType().equals(checkList.getLifePatterType()) ? count + 1 : count;
count = postCheckList.getNoiseType().equals(checkList.getNoiseType()) ? count + 1 : count;
count = postCheckList.getSleepType().equals(checkList.getSleepType()) ? count + 1 : count;
return (int) (count / 6) * 100;
}

private int getRateForFrequencyElement(String firstEnumCode, String secondEnumCode, int size) {
return 1 - Math.abs(Integer.parseInt(firstEnumCode) - Integer.parseInt(secondEnumCode)) / size;
}

private int getRemainDate(LocalDate endDate) {
return (int) endDate.until(LocalDate.now(), ChronoUnit.DAYS);
}

private Page<PostSearchDto> getPostSearchDto(String text, Pageable pageable) {
return postQuerydslRepository.searchTextPost(text, pageable);
}

private CheckList getCheckList(Long userId) {
return checkListRepository.findByUserId(userId)
.orElseThrow(() -> new EntityNotFoundException(CHECK_LIST_NOT_FOUND));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.gachon.checkmate.global.config;

import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QuerydslConfig {
@Autowired
EntityManager em;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(em);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public enum ErrorCode {
* 404 Not Found
*/
ENTITY_NOT_FOUND(HttpStatus.NOT_FOUND, "엔티티를 찾을 수 없습니다."),
CHECK_LIST_NOT_FOUND(HttpStatus.NOT_FOUND, "체크리스트를 찾을 수 없습니다."),

/**
* 405 Method Not Allowed
Expand Down