Skip to content

[HCR-369] 데이터 타입별 검색#58

Merged
tkv00 merged 1 commit into
devfrom
fix/HSC-369
Mar 19, 2026
Merged

[HCR-369] 데이터 타입별 검색#58
tkv00 merged 1 commit into
devfrom
fix/HSC-369

Conversation

@rettooo

@rettooo rettooo commented Mar 18, 2026

Copy link
Copy Markdown
Contributor

📝작업 내용


👀변경 사항


🎫 Jira Ticket

  • Jira Ticket: HCR-369

#️⃣관련 이슈

@rettooo rettooo self-assigned this Mar 18, 2026
@github-actions github-actions Bot added Customer Team 🐛 fix 기능에 대한 버그 수정 🔥 priority: P0 즉시 처리 필요(서비스/데모 블로커) 🗂️ area: BE 백엔드 영역 labels Mar 18, 2026
@github-actions github-actions Bot changed the title 데이터 타입별 검색 [HCR-369] 데이터 타입별 검색 Mar 18, 2026
@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 PR은 추천 시스템의 핵심 로직을 개선하여 추천 결과의 다양성을 확보하는 데 중점을 둡니다. 기존에는 특정 상품 타입(예: 모바일 요금제)으로 추천이 쏠리는 경향이 있었으나, 이제는 데이터 타입별로 후보를 분산하여 검색함으로써 보다 균형 잡힌 추천을 제공할 수 있게 됩니다. 또한, 특정 라이브러리(pgvector, aiokafka)가 설치되지 않은 환경에서도 애플리케이션이 안정적으로 동작하도록 의존성 처리를 유연하게 변경했습니다.

Highlights

  • 조건부 라이브러리 임포트: pgvectoraiokafka 라이브러리 임포트를 조건부로 변경하여 특정 환경(예: 테스트 환경)에서 의존성이 없을 경우에도 애플리케이션이 안정적으로 동작하도록 유연성을 높였습니다.
  • 추천 후보 다양성 개선: 추천 서비스에 데이터 타입별 벡터 검색 로직을 도입하여 추천 후보 풀의 다양성을 개선했습니다. 이는 특정 상품 타입으로 추천이 쏠리는 현상을 완화하는 데 기여합니다.
  • 타입별 검색 로직 추가: 타입별 검색을 위한 새로운 SQL 쿼리(SEARCH_SIMILAR_BY_TYPE_SQL)와 주요 상품 타입(MAIN_PRODUCT_TYPES), 타입별 검색 후보 수(RETRIEVAL_PER_TYPE_K)를 정의하는 상수를 추가했습니다.
  • 추천 함수 로직 변경: _run_recommendation_with_context_run_fallback_recommendation 함수를 수정하여, 먼저 타입별로 후보를 검색하여 최소한의 다양성을 확보한 후 부족분을 기존의 전체 검색 방식으로 채우는 새로운 추천 전략을 적용했습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

이번 PR은 추천 후보 상품을 검색할 때 상품 유형별로 검색하여 다양성을 높이는 새로운 전략을 도입했습니다. 전반적인 변경 사항은 좋아 보이지만, 몇 가지 개선할 점이 있습니다. 특히, 광범위한 except Exception 구문은 버그를 숨길 수 있으며, 후보 검색 로직에 상당한 코드 중복이 있어 유지보수성 향상을 위해 리팩토링이 필요해 보입니다.

Comment on lines +684 to +735
# 2-1) 타입별 검색으로 후보 풀 분산(최소 1개/타입 유도)
seen: set[int] = set()
product_ids: list[int] = []
for ptype in MAIN_PRODUCT_TYPES:
r = await session.execute(
SEARCH_SIMILAR_BY_TYPE_SQL,
{
"query_vec": query_vec,
"exclude_ids": exclude_ids,
"k": RETRIEVAL_CANDIDATES_K,
"ptype": ptype,
"k": RETRIEVAL_PER_TYPE_K,
},
)
rows = result.fetchall()
product_ids = [r[0] for r in rows]
for row in r.fetchall():
pid = row[0]
if pid in seen:
continue
product_ids.append(pid)
seen.add(pid)

# 2-2) 부족분은 기존 전체 검색(가중치 boost 포함 가능)으로 보충
if len(product_ids) < RETRIEVAL_CANDIDATES_K:
if use_type_boost:
result = await session.execute(
SEARCH_SIMILAR_WITH_TYPE_BOOST_SQL,
{
"query_vec": query_vec,
"exclude_ids": exclude_ids,
"k": RETRIEVAL_CANDIDATES_K,
"boost_type1": boost_type1,
"boost1": boost1,
"boost_type2": boost_type2,
"boost2": boost2,
},
)
else:
result = await session.execute(
SEARCH_SIMILAR_SQL,
{
"query_vec": query_vec,
"exclude_ids": exclude_ids,
"k": RETRIEVAL_CANDIDATES_K,
},
)
for row in result.fetchall():
pid = row[0]
if pid in seen:
continue
product_ids.append(pid)
seen.add(pid)
if len(product_ids) >= RETRIEVAL_CANDIDATES_K:
break

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

이 블록의 후보 상품 검색 로직이 _run_fallback_recommendation 함수(1078-1114행)에서도 거의 동일하게 반복되고 있습니다. 코드 중복은 유지보수를 어렵게 만들고 버그 발생 가능성을 높입니다.

이 로직을 별도의 private 헬퍼 함수로 추출하는 것을 고려해 보세요. 예를 들어, 다음과 같은 함수를 만들 수 있습니다.

async def _retrieve_candidate_products(
    session: AsyncSession,
    query_vec: list[float],
    exclude_ids: list[int],
    use_type_boost: bool,
    boost_type1: str,
    boost1: float,
    boost_type2: str,
    boost2: float,
) -> list[int]:
    # ... 여기에 중복 로직 구현 ...

이렇게 하면 _run_recommendation_with_context_run_fallback_recommendation 두 곳에서 이 헬퍼 함수를 호출하여 코드를 더 깔끔하고 재사용 가능하게 만들 수 있습니다. _run_fallback_recommendation의 경우 use_type_boostFalse로 전달하고 관련 boost 인자들을 기본값으로 넘기면 됩니다.

Comment thread app/core/database.py
Comment on lines +3 to +6
try:
from pgvector.asyncpg import register_vector
except Exception: # pragma: no cover
register_vector = None # type: ignore[assignment]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

except Exception은 너무 광범위합니다. ImportError와 같이 더 구체적인 예외를 잡는 것이 좋습니다. 이렇게 하면 pgvector 라이브러리가 없을 때 발생하는 ImportError만 처리하고, 다른 예기치 않은 오류는 숨기지 않게 됩니다.

Suggested change
try:
from pgvector.asyncpg import register_vector
except Exception: # pragma: no cover
register_vector = None # type: ignore[assignment]
try:
from pgvector.asyncpg import register_vector
except ImportError: # pragma: no cover
register_vector = None # type: ignore[assignment]

Comment on lines +6 to +11
try:
from aiokafka import AIOKafkaProducer
except Exception: # pragma: no cover
# 평가 스크립트/로컬 환경에서 Kafka 의존성이 없을 수 있다.
# Kafka 미설정 시 publish_recommendation_to_kafka에서 안전하게 스킵한다.
AIOKafkaProducer = None # type: ignore[assignment]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

except Exception은 너무 광범위하여 의도치 않은 다른 오류까지 숨길 수 있습니다. aiokafka 라이브러리가 설치되지 않았을 때 발생하는 ImportError만 명시적으로 처리하는 것이 더 안전합니다.

Suggested change
try:
from aiokafka import AIOKafkaProducer
except Exception: # pragma: no cover
# 평가 스크립트/로컬 환경에서 Kafka 의존성이 없을 수 있다.
# Kafka 미설정 시 publish_recommendation_to_kafka에서 안전하게 스킵한다.
AIOKafkaProducer = None # type: ignore[assignment]
try:
from aiokafka import AIOKafkaProducer
except ImportError: # pragma: no cover
# 평가 스크립트/로컬 환경에서 Kafka 의존성이 없을 수 있다.
# Kafka 미설정 시 publish_recommendation_to_kafka에서 안전하게 스킵한다.
AIOKafkaProducer = None # type: ignore[assignment]

@tkv00 tkv00 merged commit 2f72b6a into dev Mar 19, 2026
2 checks passed
@tkv00 tkv00 deleted the fix/HSC-369 branch March 20, 2026 01:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🗂️ area: BE 백엔드 영역 Customer Team 🐛 fix 기능에 대한 버그 수정 🔥 priority: P0 즉시 처리 필요(서비스/데모 블로커)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[HSC-369] 타입 분리해서 top3가 무조건 나올 수 있도록 수정

2 participants