Skip to content

[FEAT] 작가 검색 API #39

Description

@millkk04

작가 검색 API 구현 완료

구현 개요

  • Endpoint: GET /api/v1/search/authors
  • 기능: 검색어에 해당하는 작가 목록과 각 작가의 대표작(최대 2권)을 조회
  • 사용 위치: 검색 화면의 '작가' 탭

주요 특징

1. N+1 문제 해결

  • 2단계 조회 전략 적용
    1. 작가 목록 조회 (페이징)
    2. 작가별 도서 카운트 조회 (GROUP BY)
    3. 작가별 도서 목록 조회 (IN 쿼리)
  • 3개의 쿼리로 모든 데이터 조회
  • @EntityGraph보다 효율적이고 유지보수 용이

2. 페이징 지원

  • 클라이언트 요청에 따라 페이지 단위로 조회
  • 무한 스크롤 UI 지원
  • 최대 페이지 크기: 50

3. 대표작 자동 선정

  • 각 작가당 최대 2권의 대표작 표시
  • 최신 출판일 기준으로 정렬
  • UI 공간 효율성 확보

4. 역할 기반 필터링

  • BookAuthors.role = AUTHOR만 조회
  • 번역가(TRANSLATOR)는 제외
  • 정확한 작가 정보 제공

API 명세

Request

GET /api/v1/search/authors?query={검색어}&page={페이지}&size={크기}
Parameter Type Required Default Description
query String O - 검색 키워드 (작가명)
page int X 1 페이지 번호 (1부터 시작)
size int X 10 페이지 크기 (최대 50)

Response

{
  "page": 1,
  "size": 10,
  "isEnd": true,
  "totalCount": 1,
  "items": [
    {
      "authorId": 42,
      "name": "김영하",
      "profileImageUrl": "https://example.com/authors/kim-younha.jpg",
      "occupation": "소설가",
      "nationality": "한국",
      "bio": "1968년생 한국 소설가...",
      "bookCount": 15,
      "books": [
        {
          "bookId": 1234,
          "title": "살인자의 기억법",
          "thumbnailUrl": "https://example.com/books/1234.jpg",
          "authorNames": ["김영하"],
          "publisherName": "문학동네",
          "publishedAt": "2013-07-15T00:00:00"
        },
        {
          "bookId": 5678,
          "title": "빛의 제국",
          "thumbnailUrl": "https://example.com/books/5678.jpg",
          "authorNames": ["김영하"],
          "publisherName": "문학동네",
          "publishedAt": "2006-11-20T00:00:00"
        }
      ]
    }
  ]
}

예외 처리

1. 검색 결과 없음

{
  "page": 1,
  "size": 10,
  "isEnd": true,
  "totalCount": 0,
  "items": []
}
  • 빈 배열 반환 (404 아님)
  • 프론트엔드에서 "검색 결과가 없습니다" UI 표시

2. 잘못된 입력값

// 빈 검색어
GET /api/v1/search/authors?query=
→ 400 Bad Request: "검색 키워드는 필수입니다."

// 잘못된 페이지 번호
GET /api/v1/search/authors?query=김영하&page=0400 Bad Request: "페이지 번호는 1 이상이어야 합니다."

// 페이지 크기 초과
GET /api/v1/search/authors?query=김영하&size=100400 Bad Request: "페이지 크기는 1~50 사이여야 합니다."

3. 작가는 있지만 도서가 없는 경우

{
  "authorId": 99,
  "name": "신인작가",
  "bookCount": 0,
  "books": []
}
  • 정상 응답
  • UI에서 "등록된 작품이 없습니다" 표시

성능 임계값

  • 작가 수 < 1,000: 현재 전략으로 충분 (응답 시간 < 100ms)
  • 작가 수 1,000~10,000: 인덱스 튜닝 필요
  • 작가 수 > 10,000: Elasticsearch 도입 검토

향후 최적화 예정 후보 목록

  1. 캐싱 전략

    • Redis에 인기 작가 캐싱 (TTL 1시간)
    • 검색 결과 캐싱 (TTL 10분)
  2. Full-Text Search

    • MySQL Full-Text Index 적용
    • 또는 Elasticsearch 도입
    • 한글 형태소 분석기 추가
  3. 비동기 처리

    • 도서 카운트는 비동기로 조회
    • CompletableFuture 활용

주의사항

1. 동명이인 문제

  • 현재 ERD는 authors.name에 UNIQUE 제약이 있음
  • "김영하(소설가)"와 "김영하(시인)"을 구분 불가
  • 단기 해결: shortIntro 또는 bio에 구분 정보 포함
  • 장기 해결: UNIQUE 제약 제거 또는 name_disambiguation 컬럼 추가

2. 부분 검색 성능

  • 현재: LIKE '%keyword%' (전체 검색)
  • 문제: 인덱스를 활용하지 못함
  • 대안: LIKE 'keyword%' (접두사 검색) 또는 Full-Text Search

3. bio 길이 제한

  • DB: LONGTEXT (제한 없음)
  • API: 200자로 자르고 "..." 추가
  • 상세 페이지에서 전체 내용 제공 필요

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request
No fields configured for Feature.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions