docs: 뉴스 스킬 복수 키워드 불균형 문제 분석
This commit is contained in:
parent
5c888055e8
commit
d9b3842aad
153
troubleshooting/250827_claude_news_keyword_imbalance.md
Normal file
153
troubleshooting/250827_claude_news_keyword_imbalance.md
Normal file
@ -0,0 +1,153 @@
|
||||
# 뉴스 스킬 복수 키워드 검색 시 불균형 문제
|
||||
|
||||
## 발생일시
|
||||
2025-08-27 17:44 KST
|
||||
|
||||
## 문제 상황
|
||||
복수 키워드(`드라마`, `IT infrastructure`) 검색 시 한 키워드(IT)의 뉴스만 반환되는 문제
|
||||
|
||||
### 증상
|
||||
- 입력: `드라마`, `IT infrastructure` 2개 키워드
|
||||
- 기대: 드라마 뉴스 + IT 뉴스 균등 분배
|
||||
- 실제: IT 뉴스만 20개 반환
|
||||
|
||||
## 원인 분석
|
||||
|
||||
### 현재 로직 (`google_news_collector.py`)
|
||||
```python
|
||||
# 83-91번 라인
|
||||
for search_term in search_terms:
|
||||
news_items = await self._search_single_term(context, search_term, max_items)
|
||||
all_news.extend(news_items) # 각 키워드마다 max_items(20개)씩 추가
|
||||
|
||||
unique_news = self._remove_duplicates(all_news)
|
||||
return unique_news[:max_items] # 최종 20개로 자름
|
||||
```
|
||||
|
||||
### 문제점
|
||||
1. **과도한 수집**: 각 키워드마다 20개씩 수집 (총 40개)
|
||||
2. **단순 병합**: 순서대로 병합 후 상위 20개만 반환
|
||||
3. **불균형**: IT 뉴스가 먼저/많이 수집되면 드라마 뉴스가 잘림
|
||||
|
||||
### 데이터 흐름
|
||||
```
|
||||
드라마 검색 → 20개 수집
|
||||
IT 검색 → 20개 수집
|
||||
병합 → 40개
|
||||
중복 제거 → 35개 (예시)
|
||||
상위 20개 자름 → IT 뉴스 위주
|
||||
```
|
||||
|
||||
## 해결 방안
|
||||
|
||||
### Option 1: 균등 분배 (권장)
|
||||
```python
|
||||
async def search_news(self, keywords: List[str] = None, max_items: int = None) -> List[NewsArticle]:
|
||||
search_terms = keywords or self.config.search_terms
|
||||
max_items = max_items or self.config.max_items
|
||||
|
||||
# 키워드별 균등 할당
|
||||
items_per_keyword = max_items // len(search_terms)
|
||||
remainder = max_items % len(search_terms)
|
||||
|
||||
all_news = []
|
||||
|
||||
for idx, search_term in enumerate(search_terms):
|
||||
# 나머지 처리 (첫 키워드들에 1개씩 추가)
|
||||
keyword_limit = items_per_keyword + (1 if idx < remainder else 0)
|
||||
news_items = await self._search_single_term(context, search_term, keyword_limit)
|
||||
all_news.extend(news_items)
|
||||
|
||||
return all_news # 이미 균등 분배됨
|
||||
```
|
||||
|
||||
### Option 2: 라운드 로빈 병합
|
||||
```python
|
||||
def _merge_round_robin(self, news_lists: List[List[NewsArticle]]) -> List[NewsArticle]:
|
||||
"""각 리스트에서 번갈아가며 선택"""
|
||||
merged = []
|
||||
max_len = max(len(lst) for lst in news_lists)
|
||||
|
||||
for i in range(max_len):
|
||||
for lst in news_lists:
|
||||
if i < len(lst):
|
||||
merged.append(lst[i])
|
||||
if len(merged) >= self.config.max_items:
|
||||
return merged
|
||||
|
||||
return merged
|
||||
```
|
||||
|
||||
### Option 3: 가중치 기반 분배
|
||||
```python
|
||||
# 환경변수나 파라미터로 키워드별 가중치 설정
|
||||
keyword_weights = {
|
||||
"드라마": 0.5, # 50%
|
||||
"IT infrastructure": 0.5 # 50%
|
||||
}
|
||||
|
||||
for keyword, weight in keyword_weights.items():
|
||||
keyword_limit = int(max_items * weight)
|
||||
# ...
|
||||
```
|
||||
|
||||
## 검증 방법
|
||||
|
||||
### 테스트 스크립트
|
||||
```python
|
||||
# /home/admin/ivada_project/skill_news/test_balance.py
|
||||
import asyncio
|
||||
from app.services.google_news_collector import GoogleNewsCollector
|
||||
|
||||
async def test_keyword_balance():
|
||||
collector = GoogleNewsCollector()
|
||||
keywords = ["드라마", "IT infrastructure"]
|
||||
|
||||
results = await collector.search_news(keywords, max_items=20)
|
||||
|
||||
# 키워드별 카운트
|
||||
drama_count = sum(1 for r in results if "드라마" in r.title.lower())
|
||||
it_count = sum(1 for r in results if "it" in r.title.lower() or "인프라" in r.title.lower())
|
||||
|
||||
print(f"드라마 뉴스: {drama_count}개")
|
||||
print(f"IT 뉴스: {it_count}개")
|
||||
print(f"균형도: {min(drama_count, it_count) / max(drama_count, it_count) * 100:.1f}%")
|
||||
|
||||
asyncio.run(test_keyword_balance())
|
||||
```
|
||||
|
||||
## 즉시 조치
|
||||
|
||||
### 빠른 수정 (Option 1 적용)
|
||||
```bash
|
||||
# 1. 코드 수정
|
||||
cd /home/admin/ivada_project/skill_news
|
||||
vim app/services/google_news_collector.py
|
||||
|
||||
# 2. Docker 재시작
|
||||
docker compose down && docker compose up -d --build
|
||||
|
||||
# 3. 테스트
|
||||
curl -X POST http://localhost:8505/api/news/search \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"keywords": ["드라마", "IT infrastructure"], "max_items": 20}'
|
||||
```
|
||||
|
||||
## 영향도
|
||||
- **사용자 경험**: 다양한 주제의 뉴스를 원하는 사용자 불만족
|
||||
- **서비스 품질**: 키워드 검색 기능의 신뢰도 하락
|
||||
- **확장성**: 3개 이상 키워드 시 문제 심화
|
||||
|
||||
## 교훈
|
||||
1. **병합 알고리즘은 균형을 고려해야 함**
|
||||
2. **복수 소스 데이터는 단순 연결보다 인터리빙 필요**
|
||||
3. **사용자 의도 파악이 중요** (모든 키워드 = 균등 관심)
|
||||
|
||||
## 참고
|
||||
- Google News API는 OR 연산자 지원하지만 균형 보장 안됨
|
||||
- 키워드별 개별 검색이 더 정확한 결과 제공
|
||||
- 향후 사용자별 키워드 선호도 학습 고려
|
||||
|
||||
---
|
||||
*작성: Claude*
|
||||
*보고: 황한용님*
|
||||
Loading…
x
Reference in New Issue
Block a user