연해자평 2,333페이지 데이터베이스 완벽 구축 사례

소개



시도하고자 했던 것

중국 송나라 시대 명리학의 핵심 고전인 『연해자평』 2,333페이지를 완전히 디지털화하여

PostgreSQL 데이터베이스에 저장 가능한 표준 구조로 변환하는 작업을 진행했습니다.

최종 목표는 UNESCO 디지털 문화유산 등재를 위한 "한바둑" 명리학 통합 시스템 구축입니다.

그 이유

문화 보존의 시급성:

전통 명리학 지식이 산발적으로 흩어져 있음

한문 원전에 대한 접근성이 낮음

체계적인 DB 구축으로 AI 활용 가능성 확보

기술적 도전:

초기에 2,193건만 확보되었으나 목표는 2,333건

140건의 누락 데이터 추적 필요

여러 형식(9필드/20필드)의 데이터 통합

OCR 오류 및 PDF 바이너리 문제 해결

개인적 동기:

박사급 IT 전문가이자 한학 전공자로서의 사명감

은퇴 후 10년간 축적한 4,000장의 PPT 자료 활용

110만 건 규모의 명리학 데이터베이스 구축 비전



진행 방법



사용한 도구

AI 도구:

Claude 4 (Sonnet) - 데이터 분석, 코드 작성, 문제 해결

Python 3 - 데이터 처리 및 변환

JSON - 데이터 저장 형식

시스템:

Linux (Ubuntu 24) 환경

PostgreSQL (향후 DB 구축용)

1.4TB 외장 저장소

핵심 프롬프트 전략

1단계: 누락 분석 프롬프트

"2333건이 정상인데 현재 2193건만 있습니다. 누락된 부분을 알려주세요."

Claude의 응답으로 체계적인 파일 검증 시작:

각 JSON 파일의 페이지 범위 추출

중복 파일 탐지

누락 범위 정확히 식별

2단계: 파일 구조 분석 프롬프트

"어느 파일 구조가 맞는지 확인 후 진행하자구요?"

결과: 두 가지 구조 발견

9필드 구조 (신규 파일들)

20필드 구조 (기존 430건)

3단계: 스타일 차이 확인 프롬프트

"페이지 1부터 560까지 형식을 재검토해 줘, 본문 561과는 자료 스타일이 틀려요."

발견한 문제:

페이지 1-200: OCR 실패 (깨진 문자)

페이지 201-400: 한문 원문

페이지 401-560: 한글 해설

페이지 561-690: 내용 비어있음 (재작업 필요)

실제 작업 코드

파일 구조 확인 코드:

python

import json import re def analyze_file_structure(file_path): with open(file_path, 'r', encoding='utf-8') as f: data = json.load(f) # 구조 판별 if isinstance(data, dict): print(f"구조: metadata + records") records = data.get('records', []) else: print(f"구조: 직접 배열") records = data # 페이지 범위 추출 pages = [] for rec in records: source = rec.get('source', '') or rec.get('source_file', '') match = re.search(r'부분(\d+)\.pdf$', source) if match: pages.append(int(match.group(1))) if pages: pages.sort() print(f"레코드 수: {len(records)}건") print(f"페이지 범위: {min(pages)}~{max(pages)}") print(f"연속성: {'✅ 연속' if max(pages)-min(pages)+1 == len(pages) else '❌ 불연속'}")

9필드 → 20필드 변환 함수:

python

from datetime import datetime def convert_9_to_20(record): """9필드 구조를 20필드 구조로 변환""" source = record.get('source', '') match = re.search(r'부분(\d+)\.pdf$', source) page_num = int(match.group(1)) if match else 0 return { 'document_title': source, 'document_type': record.get('type', 'pdf'), 'category': '연해자평', 'subcategory': f'페이지_{page_num}', 'author': '저자미상', 'source_file': source, 'source_type': 'pdf', 'publication_year': '', 'publisher': '', 'content_full': record.get('rawContent', ''), 'content_summary': '', 'content_keywords': ','.join(record.get('keywords', [])) if isinstance(record.get('keywords'), list) else '', 'related_theory': '', 'trust_level': 5, 'created_at': record.get('timestamp', datetime.now().isoformat()), 'dify_dataset_id': '', '_author': '', '_date': '', '_source_file': source, '_merged_at': datetime.now().isoformat() }

중복 제거 및 정렬 코드:

python

def merge_and_deduplicate(all_records): """페이지 번호 기준 중복 제거 및 정렬""" # 페이지별로 정리 page_dict = {} for rec in all_records: page = get_page_number(rec) if page > 0: if page in page_dict: print(f"⚠️ 중복 발견: 페이지 {page}") page_dict[page] = rec # 나중 것으로 덮어쓰기 # 리스트로 변환 및 정렬 deduplicated = list(page_dict.values()) deduplicated.sort(key=get_page_number) return deduplicated def get_page_number(record): """레코드에서 페이지 번호 추출""" source = record.get('source_file', '') or record.get('source', '') match = re.search(r'부분(\d+)\.pdf$', source) return int(match.group(1)) if match else 0

최종 통합 코드:

python

# 1. 기존 파일 로드 with open('연해자평_통합_1973건.json', 'r', encoding='utf-8') as f: existing_data = json.load(f) # 2. 재작업 파일 로드 및 변환 rework_files = [ 'json-200재작업.json', 'json-690재작업.json', 'json-720재작업.json' ] new_records = [] for file_path in rework_files: with open(file_path, 'r', encoding='utf-8') as f: data = json.load(f) for rec in data['records']: converted = convert_9_to_20(rec) new_records.append(converted) # 3. 통합 및 중복 제거 all_records = existing_data + new_records final_data = merge_and_deduplicate(all_records) # 4. 저장 with open('연해자평_최종완성_2333건.json', 'w', encoding='utf-8') as f: json.dump(final_data, f, ensure_ascii=False, indent=2) print(f"✅ 완성: {len(final_data)}건")

작업 흐름도

1단계: 초기 분석 ├─ 기존 파일 확인: 2,193건 ├─ 목표 확인: 2,333건 └─ 누락: 140건 ❌ 2단계: 누락 추적 ├─ 파일별 페이지 범위 분석 ├─ 중복 파일 탐지 (210건) └─ 실제 누락: 130건 발견 3단계: 문제 해결 ├─ OCR 실패 (1-200): 재작업 완료 ├─ PDF 바이너리 (561-690): 재작업 완료 └─ 빈 페이지 (691-720): 재작업 완료 4단계: 데이터 통합 ├─ 9필드 → 20필드 변환 ├─ 중복 제거 ├─ 페이지 순서 정렬 └─ 최종 검증 5단계: 완성 ✅ └─ 2,333건 완벽 통합




결과와 배운 점



주요 성과

정량적 결과:

✅ 최종 레코드: 2,333건 (100%)

✅ 페이지 범위: 1~2,333 (연속)

✅ 누락: 0건

✅ 중복: 0건

✅ 파일 크기: 8.5 MB

✅ 구조: 20필드 표준화

정성적 성과:

체계적인 데이터 검증 프로세스 확립

재사용 가능한 변환 함수 개발

완벽한 문서화 (작업 보고서, 백업 가이드)

배운 점 & 꿀팁

1. Claude와의 협업 패턴

DO (효과적이었던 것):

문제를 단계별로 나누어 질문

"누락 확인" → "구조 분석" → "내용 검증"

구체적인 데이터 제시

"2333건이 맞는데 2193건만 있어요" (명확한 수치)

결과 확인 후 다음 단계 진행

"검토해 봐요" → 확인 후 → "통합 진행"

DON'T (비효율적이었던 것):

한 번에 모든 것을 요구

막연한 요청 ("데이터 정리해줘")

중간 검증 없이 진행

2. 데이터 품질 관리 핵심

🔍 체계적 검증이 핵심:

python

# 매 단계마다 검증 코드 실행 def verify_data(records): # 1. 개수 확인 print(f"레코드 수: {len(records)}") # 2. 페이지 연속성 pages = [get_page_number(r) for r in records] missing = set(range(1, 2334)) - set(pages) print(f"누락: {len(missing)}건") # 3. 중복 확인 duplicates = [p for p in pages if pages.count(p) > 1] print(f"중복: {len(set(duplicates))}건") # 4. 내용 확인 empty = [p for r in records if len(r.get('content_full', '')) < 10] print(f"비어있음: {len(empty)}건")

3. 파일명 컨벤션의 중요성

좋은 예:

연해자평_최종완성_2333건_2025-11-22.json 연해자평_v1.1_OCR수정_2025-11-23.json

나쁜 예:

final.json data_new.json test123.json

4. 중복 문제 해결 전략

발견한 패턴:

json-1300 파일이 2개 (200건 vs 100건)

json-1140 파일이 2개 (서로 다른 범위)

작은 파일들이 큰 파일에 포함됨

해결책:

python

# 페이지 번호로 딕셔너리 관리 page_dict = {} for rec in all_records: page = get_page_number(rec) page_dict[page] = rec # 자동 중복 제거 # 최종적으로 딕셔너리 값만 추출 final_records = list(page_dict.values())

시행착오

문제 1: 561-690 범위가 비어있음

증상: rawContent가 '\n\n' (2 bytes)만 원인: 재작업 파일이 제대로 생성되지 않음 해결: 재작업 파일 재업로드 → 교체

문제 2: 페이지 1-200 OCR 실패

증상: 깨진 문자들 (t. . 、 1 ` / .. •) 원인: PDF OCR 품질 문제 해결: 재작업 진행 (향후 추가 개선 필요)

문제 3: 파일 구조 불일치

증상: 9필드 vs 20필드 원인: 작업 시기별로 다른 형식 사용 해결: 변환 함수 개발 (convert_9_to_20)

도움이 필요한 부분

현재 과제:

페이지 1-200 OCR 품질 개선

더 나은 OCR 도구 추천 필요

또는 수동 교정 전략

PostgreSQL 스키마 최적화

110만 건 규모 처리 방법

인덱싱 전략

AI 벡터 임베딩

텍스트 → 벡터 변환 최적 방법

Dify 연동 전략



도움 받은 글 (옵션)



GPTers 커뮤니티

"Ruby on Rails 학습 준비 사례" - 시스템 설계 아이디어

"연해자평 디지털화 초기 작업" - 프로젝트 시작점

외부 참고 자료

기술 문서:

Python JSON 공식 문서

PostgreSQL JSONB 타입 가이드

Anthropic Claude API 문서

명리학 참고:

연해자평 원전 (한문)

명리학 용어 사전

24절기 천문 데이터 (KASI)

프로젝트 관리:

Git 버전 관리 전략

데이터 품질 관리 체크리스트

백업 및 복구 전략



1

뉴스레터 무료 구독

👉 이 게시글도 읽어보세요