문서가 적을 때 온톨로지 빌드는 API 요청 하나로 끝났습니다. 입력이 수만 개 청크와 CSV로 늘자 빌드는 몇 시간이 됐고, 다른 인스턴스에서 진행 상황을 물으면 작업을 찾지 못했습니다. 공유 캐시에 상태를 복제해봤지만 캐시가 만료되면 취소와 재개 정보를 복원할 수 없었습니다. 빌드 작업이 캐시가 아니라 운영 기록이었다는 것을 확인한 과정입니다.
요청 하나로 끝나던 빌드가 몇 시간이 됐습니다
문서가 적을 때 빌드는 단순했습니다. 입력을 읽고 모델을 호출한 뒤 그래프를 저장하면 끝났습니다.
입력이 수만 개 청크와 CSV로 늘자 빌드가 몇 분에서 몇 시간 동안 이어졌습니다. 그리고 "지금 어디까지 됐나"라는 요청이 함께 늘었습니다.
답할 수가 없었습니다. 작업 상태가 API 프로세스 메모리에 있었기 때문입니다. 여러 인스턴스가 요청을 나눠 받으면서, 작업을 만든 인스턴스와 상태를 조회한 인스턴스가 달라지면 찾지 못했습니다. 재시작하면 이력도 사라졌습니다.
진행 상황을 그래프의 처리 마커에서 복원하는 방법도 써봤습니다. 그러자 대량 쓰기와 상태 조회가 같은 저장소를 두고 경쟁했습니다.
그래프는 지식의 최종 상태를 담는 곳인데, 저희는 거기서 실행의 현재 상태까지 읽으려 하고 있었습니다.
캐시에 복제했더니 무엇이 최신인지 다시 정해야 했습니다
인스턴스 사이의 공유 문제니 공유 캐시에 상태를 두면 될 것 같았습니다. Redis에 작업 상태를 복제했습니다.
인스턴스 간 공유는 해결됐습니다. 다른 문제가 나왔습니다.
작업 데이터베이스인 PostgreSQL에도 빌드 이력이 남아 있어서 어느 쪽이 최신인지 다시 정해야 했습니다. 캐시가 만료되거나 Redis가 재시작한 뒤 취소와 재개 정보를 어떻게 복원할지도 남았습니다.
여기서 저희가 빌드 작업을 무엇으로 다루고 있었는지가 드러났습니다. 캐시에 두는 것은 잠깐 재사용하면 좋고 없어도 다시 만들 수 있는 값입니다.
빌드 작업은 그런 값이 아니었습니다. 완료된 뒤에도 실패 원인과 재시작 지점을 확인해야 하는 운영 기록입니다. 없어지면 다시 만들 수 없습니다.
그래서 작업 레코드를 PostgreSQL에 영속화하고 Redis 작업 캐시는 제거했습니다. 상태와 단조 증가 카운터, 취소 요청을 한 레코드에서 갱신하면 다른 인스턴스에서도 재시작 뒤에도 같은 값을 읽습니다.
PostgreSQL과 RDF 그래프 저장소를 하나로 합치지는 않았습니다. 둘 다 데이터를 오래 저장하지만 조회 형태가 다릅니다.
작업 상태 작업 ID로 한 행을 자주 읽고 갱신한다 → PostgreSQL
지식 결과 클래스와 관계를 SPARQL로 탐색한다 → Fuseki
저장 기술을 두 개 쓰려는 구성이 아니라 접근 패턴과 수명주기가 다른 것을 나눈 것입니다.
상태를 어디에 둘지 정할 때 "여러 곳에서 읽어야 한다"만 보면 캐시가 답으로 보입니다. 그 앞에 물어야 할 것은 이 값이 사라졌을 때 다시 만들 수 있는가입니다. 다시 만들 수 없으면 캐시에 둘 수 없습니다.
진행률은 그래프를 다시 세지 않고 기록합니다
작업 레코드에는 전체 입력 수, 처리한 입력 수, 현재 단계, 취소 요청, 완료 상태를 저장합니다. 워커는 청크 그룹을 끝낼 때 처리 수를 올리고, 화면은 이 값을 읽습니다.
진행률 조회가 그래프의 트리플 수와 관계없이 일정한 비용으로 끝납니다.
빌드 작업 저장소 그래프 저장소
------------------ -----------------
전체·처리 청크 수 클래스·인스턴스
현재 단계 관계·속성
취소·실패·완료 상태 원문 출처
상태 전이도 제한했습니다. 대기에서 실행으로, 실행에서 완료나 실패나 취소로만 갑니다.
다만 여기에 오해할 수 있는 부분이 있어 적어둡니다. 작업 레코드가 재시작 뒤에도 복원된다는 것이 중단된 워커가 자동으로 이어서 실행된다는 뜻은 아닙니다. 재개 정책과 실제 처리 단위의 멱등성은 별도 계약이 필요합니다.
취소 요청도 작업 레코드에 남깁니다. 워커는 그룹 경계에서 이를 확인하고 멈춥니다. 그래프 업로드 도중에 프로세스를 강제로 끊는 것보다, 어디까지 완료됐는지 확정할 수 있는 경계에서 끝내는 편이 재시작에 유리합니다.
이 단계에서 실행 상태와 결과 저장소의 책임은 나뉘었지만, 상태 조회가 항상 빠르다는 보장이 생긴 것은 아니었습니다. 백그라운드 작업 안의 동기 문서 스캔과 데이터베이스 조회가 이벤트 루프를 점유하는 문제는 남아 있었습니다. 작업 모델을 나누는 것과 실행 자원을 나누는 것은 다른 문제였고, 뒤의 것은 자동 후처리 범위가 커진 뒤 5편에서 다시 다뤘습니다.
한글 문서가 추출되기도 전에 버려지고 있었습니다
긴 빌드에서 모델 호출 전에 쓸모없는 입력을 거르는 것은 중요합니다. 그래서 입력 게이트를 뒀습니다.
문자열 길이와 공백 비율을 봤습니다. 영문 텍스트를 기준으로 만든 규칙이었습니다.
한글 문장과 표, 숫자와 코드가 섞인 문서가 여기서 비자연어로 분류되고 있었습니다. 실제 처리해야 할 문서가 모델을 만나기도 전에 버려졌습니다.
게이트를 만들 때 저희가 던진 질문이 "자연스러운 영어 문장인가"였습니다. 물어야 했던 것은 "추출할 기호와 의미가 있는가"였습니다.
질문을 바꾸자 판정 방식도 따라 바뀌었습니다. 한중일 문자가 있으면 통과시키고, base64는 문자 모양이 아니라 실제 디코딩 가능 여부로 판정합니다. 영숫자가 전혀 없거나 같은 문자만 반복되는 극단적인 경우만 제외합니다.
게이트의 역할도 다시 적었습니다. 문서의 품질을 최종 판정하지 않고, 모델을 호출해볼 가치가 명백히 없는 입력만 걷어냅니다. 애매한 입력은 뒤 단계로 보내고 추출 결과가 비었는지는 별도 상태로 기록합니다.
유효한 문서를 일찍 버리는 비용이 불필요한 한 번의 호출보다 크기 때문입니다.
필터를 설계할 때 통과율과 차단율을 먼저 봅니다. 그 전에 틀렸을 때 어느 쪽 비용이 큰지 정해두면 임계값 논쟁이 짧아집니다.
표와 문서는 같은 컬렉션 안에서도 다른 경로를 타야 했습니다
초기 분기는 컬렉션 단위였습니다. 파일 절반 이상이 표면 CSV 경로로, 아니면 전부 문서 경로로 보냈습니다.
현실의 컬렉션은 섞여 있었습니다. 다수결로 정한 경로가 나머지 파일에는 맞지 않았습니다.
파일 단위로 표와 문서를 나누고 같은 그래프에 합치는 경로를 만들었습니다. 문서는 청크 그룹으로 스트리밍하며 모델이 개념과 관계를 추출합니다. 표는 스키마와 행 구조를 결정적으로 변환합니다.
CSV 인스턴스에는 형태소 기반 중복 병합을 적용하지 않습니다. 기본키와 외래키로 만든 식별자를 의미 유사도로 합치면 서로 다른 행이 사라집니다.
대용량 RDF는 한 번에 전송하지 않고 배치로 나눠 병렬 업로드합니다. 로컬 격리 환경에서 60,007개와 120,007개 트리플을 각각 나눠 적재한 뒤, 저장소를 다시 조회한 수가 일치하는지 확인했습니다.
완료라고 적혀 있어도 검증을 통과했다는 뜻은 아니었습니다
모델이 JSON을 반환했다고 빌드 전체를 설명할 수는 없습니다. 입력 판별, 추출, 구조 검증, 스키마 저장, RDF 업로드, 출처를 단계별 관측 대상으로 나눴습니다. 어느 단계에서 멈췄는지 알아야 재시도 범위를 정할 수 있습니다.
여기서 완료 상태의 의미를 정확히 적어둘 필요가 있습니다.
현재 완료 로직은 RDF 트리플이 있는데 PostgreSQL 스키마가 비어 있어도 경고를 남긴 뒤 완료로 전환할 수 있습니다. 처리한 청크 목록 저장도 실패해도 진행하는 방식입니다.
그러니까 완료는 워커가 끝났다는 실행 상태이지 모든 스키마와 출처 검증이 통과했다는 품질 인증이 아닙니다. 경고와 품질 보고서를 함께 봐야 합니다.
상태 값 하나에 여러 뜻을 담으면 그 값을 읽는 쪽이 각자 다르게 해석합니다. 화면은 초록색을 칠하고, 후속 작업은 진행해도 된다고 판단하고, 운영자는 확인을 마칩니다. 셋 중 하나만 맞아도 그 값은 계속 쓰입니다.
오래 걸려도 제어 가능한 것과 좋은 그래프를 만드는 것은 달랐습니다
이 편의 작업으로 빌드는 몇 시간이 걸려도 상태를 물을 수 있고, 취소할 수 있고, 어디서 멈췄는지 알 수 있는 작업이 됐습니다.
되짚어보면 세 번 모두 같은 실수였습니다. 실행 상태를 그래프에서 읽으려 했고, 운영 기록을 캐시에 뒀고, 완료라는 한 단어에 실행 상태와 품질 인증을 함께 담았습니다.
매번 서로 다른 수명을 가진 것들을 같은 자리에 두고 있었습니다.
그리고 안정적으로 끝나는 것과 좋은 그래프를 만드는 것은 다른 문제입니다. 완료된 빌드가 쓸 만한 그래프를 만들었는지는 아직 아무도 재고 있지 않았습니다. 다음 편에서는 트리플 수나 완료 상태 대신 무엇을 봐야 하는지를 다룹니다.

