콘텐츠로 이동

Research 엔진 vs Seed 엔진 개요

🔍 Newsfork: Research 엔진 vs Seed 엔진

섹션 제목: “🔍 Newsfork: Research 엔진 vs Seed 엔진”

Newsfork는 2단계 파이프라인으로 구성되어 있습니다:

[Research Engine] → [Seed Engine] → [Scraper Engine]
"어디서" "어떻게" "실제 수집"

각 엔진은 명확하게 분리된 책임을 가지며, 독립적으로 개발/테스트/확장할 수 있도록 설계되었습니다.


“Research Engine discovers WHERE to look.”

Research 엔진은 URL 발견에만 집중합니다. 콘텐츠 품질, 수집 방법, 유효성을 판단하지 않습니다.

research/
├── datasets/ # 발견된 URL 데이터셋 (불변)
│ └── country=sg/category=news/2026-01-25_0001.json
├── liveness/ # 도메인 생존 확인 결과
│ └── country=sg/2026-01-25.json
├── blocked/ # 차단된 도메인 (403, captcha)
│ └── country=sg/2026-01-25.json
└── dead/ # 죽은 도메인 (DNS 실패, 접근 불가)
└── country=sg/2026-01-25.json
  • URL 발견: Google Search, crt.sh, Wayback Machine 등을 통한 URL 수집
  • 도메인 정규화: www.mom.gov.sgmom.gov.sg
  • Domain ID 생성: gov:sg:mom.gov.sg 형식으로 고유 식별자 생성
  • 생존 확인: Phase 1-A 생존성 체크 (HTTP 200 응답 확인)
  • 불변 스냅샷: 발견된 URL들의 시점별 불변 데이터셋 생성
  • 메타데이터 관리: D1에 배치 상태 및 통계 저장
  • 콘텐츠 타입 결정 (RSS/HTML/API)
  • 콘텐츠 성격 분류 (뉴스/정책/가이드)
  • 메타데이터 추출
  • Seed 계약 생성
{
"meta": {
"dataset_id": "sg-news-2026-01-25-0001",
"country": "SG",
"category": "news",
"discovered_at": "2026-01-25T03:12:00Z",
"research_methods": ["google_search", "crtsh"],
"queries": ["Singapore government news site:.gov.sg"],
"record_count": 8
},
"records": [
{
"raw_url": "https://www.mom.gov.sg/newsroom",
"normalized_domain": "mom.gov.sg",
"domain_id": "gov:sg:mom.gov.sg",
"source_type": "gov",
"discovery_method": "google_search",
"confidence": 0.95,
"content_hints": ["news", "government_content"]
}
]
}
[API Request] POST /api/v1/queues/research
[Queue Batch Creation] → D1에 배치 메타데이터 저장
[Queue Consumer] → 메시지 배치 처리
[Domain Functions]
├── discoverUrlsFromSource()
├── createResearchOutput()
└── generateDatasetId()
[Storage]
├── R2 (Raw datasets)
├── D1 (Metadata, batch state)
└── GitHub (Audit trail)
MethodEndpointDescription
GET/api/v1/researchResearch 출력 목록 조회
GET/api/v1/research/:country/:category/:date특정 Research 조회
POST/api/v1/researchResearch 출력 생성
POST/api/v1/queues/researchResearch 배치 생성

🌱 Seed 엔진 (수집 계약 생성 단계)

섹션 제목: “🌱 Seed 엔진 (수집 계약 생성 단계)”

“Seed Engine defines HOW to fetch.”

Seed 엔진은 Research 엔진이 발견한 URL들을 기반으로 **수집 계약(Contract)**을 생성합니다.

seed-engine/
├── raw/country=sg/category=news/date=2026-01-28/
│ ├── raw_0001.json # Research 엔진 출력을 입력으로 받음
│ ├── raw_0002.json
│ ├── raw_metadata.json
│ └── raw_NNNN.json.success # 처리 완료 체크포인트
└── prod/country=sg/category=news/date=2026-01-28/{domain}/
├── domain_metadata.json # 도메인별 수집 메타데이터
├── robots.txt # 수집된 robots.txt
├── sitemap.xml # 수집된 sitemap.xml
└── domain_metadata.json.success
  • Raw 데이터 처리: Research 엔진 출력을 입력으로 받아 처리
  • 도메인별 그룹화: URL들을 registrable_domain 기준으로 그룹화
  • Technical 메타데이터 수집:
    • robots.txt 다운로드 및 분석
    • sitemap.xml 수집
    • 서버 응답 헤더 분석
  • Seed 계약 생성: 실제 스크래핑을 위한 기술적 계약서 작성
  • 체크포인트 시스템: .success 파일을 통한 idempotent 처리
  • URL 발견 (Research 엔진의 역할)
  • 실제 콘텐츠 스크래핑 (Scraper 엔진의 역할)
  • 콘텐츠 품질 평가
POST /api/v1/seeds/orchestrate
// R2에서 raw/ 파일들을 스캔하여 SEED_QUEUE로 전송
Input: R2: raw/.../raw_NNNN.json
Output: SEED_QUEUE 메시지들
// 입력: raw/country=sg/category=news/date=2026-01-28/raw_0001.json
// 처리: JSON 파싱 → 도메인별 그룹화
// 출력: DOMAIN_QUEUE 메시지들 + .success 체크포인트
{
file_path: "raw/country=sg/category=news/date=2026-01-28/raw_0001.json",
partition_info: {
country: "sg",
category: "news",
date: "2026-01-28"
}
}
// 입력: 도메인별 URL 그룹
// 처리: robots.txt, sitemap.xml 수집
// 출력: prod/{domain}/domain_metadata.json + 증거 파일들
const { domain, urls, partition_info } = message;
// robots.txt, sitemap.xml 수집 후 prod/에 저장
{
"domain": "mom.gov.sg",
"urls": [
{
"url": "https://mom.gov.sg/employment-practices/employment-act",
"title": "Employment Act - Ministry of Manpower"
}
],
"robots_txt_size": 1024,
"sitemap_xml_size": 2048,
"processed_at": "2026-01-30T10:00:00.000Z"
}
MethodEndpointDescription
POST/api/v1/seeds/orchestrateSeed 처리 오케스트레이션
GET/api/v1/seeds/status처리 상태 조회

🔗 엔진 간 연결 및 데이터 흐름

섹션 제목: “🔗 엔진 간 연결 및 데이터 흐름”
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Research │ │ Seed │ │ Scraper │
│ Engine │───▶│ Engine │───▶│ Engine │
│ │ │ │ │ │
│ "어디서 찾을까?" │ │ "어떻게 가져올까?"│ │ "실제로 수집" │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
▼ ▼ ▼
research/datasets/ raw/ + prod/ final/content/
- URL 발견 - 기술 메타데이터 - 실제 콘텐츠
- 도메인 정규화 - robots.txt - 구조화된 데이터
- 생존성 확인 - sitemap.xml - 최종 산출물
엔진입력처리출력책임
Research검색 쿼리, 도메인 힌트URL 발견, 도메인 정규화research/datasets/*.json”어디서 찾을까?”
SeedResearch 출력기술 메타데이터 수집raw/, prod/”어떻게 가져올까?”
ScraperSeed 출력실제 콘텐츠 수집final/content/”실제로 수집”
  • news: 시간에 민감한 뉴스
  • policy: 법률, 규정, 시스템
  • guide: 사용법, 지침서
  • faq: Q&A 구조화된 정보
  • data: 수치/통계/원시 데이터
  • research: 학술/연구 논문
  • announcement: 단순 공지, 이벤트
  • directory: 목록형 정보
  • opinion: 논평, 칼럼
  • alert: 긴급/경고 정보
  • government: 정부 기관
  • organization: 일반 조직
  • ngo: 비정부기구
  • company: 기업
  • web: 일반 웹 페이지
  • social: 소셜 미디어
  • video: 비디오 콘텐츠
  • audio: 팟캐스트
  • document: PDF, DOC 파일

R2 버킷 구조:
├── research/datasets/ # Research 엔진 출력
├── research/liveness/ # 생존성 확인 결과
├── research/blocked/ # 차단된 도메인
├── research/dead/ # 죽은 도메인
├── raw/ # Seed 엔진 입력 (불변)
├── prod/ # Seed 엔진 출력 (파이프라인 산출물)
└── final/ # Scraper 엔진 출력 (최종 콘텐츠)
Research 엔진:
├── RESEARCH_QUEUE → URL 발견 작업
└── LIVENESS_QUEUE → 도메인 생존성 확인
Seed 엔진:
├── SEED_QUEUE → Raw 파일 처리
└── DOMAIN_QUEUE → 도메인별 메타데이터 수집
Idempotent 처리를 위한 .success 파일:
├── raw_0001.json.success # Seed 처리 완료
├── domain_metadata.json.success # Domain 수집 완료
└── liveness_check.json.success # 생존성 확인 완료
Routes Layer (HTTP)
├── /api/v1/research/* # Research API
└── /api/v1/seeds/* # Seed API
Domain Layer (비즈니스 로직)
├── research/ # Research 도메인 함수
└── seed/ # Seed 도메인 함수
Infrastructure Layer (Cloudflare)
├── r2/ # R2 스토리지 어댑터
├── d1/ # D1 데이터베이스 어댑터
├── queues/ # Queue 핸들러
└── kv/ # KV 캐시 어댑터

측면Research 엔진Seed 엔진
목적URL 발견수집 계약 생성
입력검색 쿼리, 힌트Research 출력
출력URL 목록기술 메타데이터
판단하지 않음 (발견만)기술적 분석
스토리지research/raw/, prod/
불변성완전 불변Raw 불변, Prod 갱신 가능
의존성외부 검색 APIResearch 출력
처리 방식배치 처리스트리밍 파이프라인
체크포인트배치 레벨파일/도메인 레벨

  • 스케줄링: 정기적 배치 실행 (일 1-2회)
  • 확장성: 국가/카테고리별 병렬 처리
  • 모니터링: 배치 성공률, 발견된 URL 수
  • 실패 처리: DLQ를 통한 재처리
  • 트리거: Research 출력 기반 이벤트 드리븐
  • 확장성: 파일/도메인별 병렬 처리
  • 모니터링: 처리 진행률, 메타데이터 수집 성공률
  • 실패 처리: 체크포인트 기반 재시작

이 2단계 분리를 통해 각 엔진이 명확한 책임을 가지며, 독립적으로 개발/테스트/확장할 수 있습니다:

  • Research 엔진: “무엇을 찾을까”에 집중
  • Seed 엔진: “어떻게 가져올까”에 집중

이러한 관심사의 분리(Separation of Concerns)를 통해 시스템의 복잡성을 관리하고, 각 엔진의 전문성을 극대화할 수 있습니다.