feat: 중복 기사 필터링 3단계 구현 및 최신 기사 우선 정렬 개선#1
Open
moonjun1 wants to merge 1 commit into
Open
Conversation
- [중복 필터링 Level1] BatchConfig.newsProcessor()에 스레드 안전 Set 추가
속보/종합 태그 제거 후 앞 30자 기준으로 배치 수집 중 인메모리 중복 차단
- [중복 필터링 Level2] BatchJobCompletionListener afterJob() 3단계 SQL 후처리
Step1: ROW_NUMBER로 완전 동일(title+publisher) 중복 제거, 최신 1건 유지
Step2: REGEXP_REPLACE 정규화 유사 제목 중복 제거
Step3: 노이즈·광고성·10자 미만 기사 삭제
- [최신 정렬] DeepSearch API order 파라미터 published_at → -published_at
getAPIResponse(), getNewsList() 두 메서드 모두 적용
- [최신 정렬] KakaoNewsService ES 검색 정렬 변경
score DESC 단일 → published_at DESC 우선 + score DESC 보조
- [보안] SecurityConfig에 StrictHttpFirewall 설정 추가
한국어 키워드 URL 인코딩 경로 변수 허용(/api/hottopic/{keyword})
- [인증] JwtAuthenticationFilter shouldNotFilter에 /api/admin/** 경로 추가
- report/ 디렉토리 추가: 작업 보고서, 피드백 개선 보고서, 검증 보고서, 스크린샷 4장
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📋 개요
피드백에서 제기된 핵심 문제 두 가지 — 중복 기사 범람과 오래된 기사 우선 노출 — 를 해결하기 위한 개선 작업입니다.
추가로 한국어 키워드 URL 경로 변수 처리 문제(보안 설정) 및 관리자 배치 수동 실행 인증 우회 설정도 포함됩니다.
🐛 문제 배경
문제 1 — 중복 기사
DeepSearch API로 수집되는 뉴스는 동일 사건을 여러 언론사·편집자가 반복 송고하여 아래와 같은 중복이 다수 발생합니다.
기존 코드에는 중복 제거 로직이 없어 모두 DB에 적재되고 사용자에게 중복 기사가 배달되었습니다.
문제 2 — 오래된 기사 우선 노출
published_at오름차순 → 가장 오래된 기사부터 수집_score단일 정렬 → 최신 기사가 관련도 낮으면 묻힘✅ 변경 사항
1. 중복 기사 필터링 — 3단계 파이프라인
Level 1 · 수집 단계 인메모리 중복 제거
배치가 API 응답을 처리하는 ItemProcessor 단계에서 스레드 안전(thread-safe) Set을 사용해 동일 배치 내 중복을 실시간 차단합니다.
publisher::title앞30자)하여 다른 언론사의 동일 제목은 허용null반환 시 Spring Batch가 자동으로 해당 아이템을 skip 처리Level 2 · 배치 완료 후 DB 사후 처리
BatchStatus.COMPLETED이후 자동 실행되는 리스너에서 3단계 SQL을 순차 실행합니다.Step 1 — 완전 동일 (title + publisher) 중복 제거
→
(title, publisher)완전 동일 그룹에서 가장 최신 1건만 유지Step 2 — 정규화 유사 제목 중복 제거
→
[속보]·(종합2)등 태그 제거 + 공백 제거 후 앞 30자 기준으로 유사 중복 통합Step 3 — 노이즈성 기사 제거
전체 중복 필터링 흐름
2. 최신 기사 우선 정렬
DeepSearch API 수집 정렬 변경
두 메서드 모두 동일하게 적용하여 수집 단계부터 최신 기사가 먼저 저장됩니다.
ElasticSearch 검색 결과 정렬 변경
3. 한국어 URL 경로 변수 허용 (SecurityConfig)
/api/hottopic/{keyword}엔드포인트에 한국어 키워드를 URL 인코딩하여 전달하면 Spring Security의StrictHttpFirewall이 비ASCII 문자를 차단하여 400 에러가 발생하던 문제를 해결합니다.4. JWT 필터 우회 경로 추가 (JwtAuthenticationFilter)
/api/admin/**경로를 JWT 인증 필터에서 제외하여 배치 수동 실행(POST /api/admin/batch/run) 등 관리자 작업을 인증 없이 호출할 수 있도록 합니다. (SecurityConfig에서도 동일 경로permitAll()적용)📊 개선 효과 요약
📁 변경 파일 목록
Global/News/Batch/configuration/BatchConfig.javaGlobal/News/Batch/listener/BatchJobCompletionListener.javaDomain/Kakao/service/KakaoNewsService.javaSecurityConfig.javaGlobal/JWT/JwtAuthenticationFilter.javadocker-compose.ymlreport/REPORT.mdreport/feedback_improvement_report.mdreport/verification_report.mdreport/seed_data.pyreport/screenshots/*.png🧪 테스트 체크리스트
GET /api/hottopic→ 10개 한국어 키워드 정상 반환GET /api/hottopic/삼성전자(URL 인코딩) → 최신순 기사 5건 반환 (StrictFirewall 수정 전 400 → 수정 후 200)BatchJobCompletionListener로그에 중복 제거 건수 출력 확인GET /sub/history(JWT 인증) → 히스토리 10건 정상 조회news테이블 43건, ElasticSearchnews-index-nori43 docs 동기화 일치🔗 관련 문서
report/REPORT.mdreport/feedback_improvement_report.mdreport/verification_report.md