Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.opensource.docgrid.domain.document.entity.Document;
import com.opensource.docgrid.domain.document.entity.DocumentChunk;
import com.opensource.docgrid.domain.document.entity.DocumentVersion;
import com.opensource.docgrid.domain.document.entity.FileObject;
import com.opensource.docgrid.domain.document.enums.DocumentStatus;
import com.opensource.docgrid.domain.document.enums.DocumentType;
import com.opensource.docgrid.domain.document.enums.DocumentVersionStatus;
import com.opensource.docgrid.domain.document.repository.DocumentChunkRepository;
Expand Down Expand Up @@ -101,6 +103,7 @@ public PreparationResult prepare(
// 4. 최초 UPLOADED 요청만 PARSING 상태와 시작 이벤트를 같은 Transaction에 기록한다.
if (documentVersion.getStatus() == DocumentVersionStatus.UPLOADED) {
documentVersion.markParsing();
markDocumentIndexingIfNotSearchable(documentVersion.getDocument());
indexingEventRepository.save(IndexingEvent.builder()
.embeddingJob(embeddingJob)
.eventType(IndexingEventType.PARSE_STARTED)
Expand All @@ -119,6 +122,23 @@ public PreparationResult prepare(
));
}

/**
* 검색 가능한 Version이 아직 없는 문서에 한해 진행 상태를 INDEXING으로 노출한다.
*
* <p>이미 INDEXED인 문서의 재인덱싱에는 적용하지 않는다. 검색 경로가
* {@code d.status = 'INDEXED'}로 필터하므로(VectorSearchRepository,
* AccessibleDocumentQueryService), 재인덱싱 중 상태를 바꾸면 기존에 검색되던 문서가
* 새 Version을 처리하는 동안 검색 결과에서 이탈한다.
*
* <p>UPLOADED는 최초 업로드와, FAILED 문서에 새 Version을 올려 재시도하는 경우를 함께
* 가리킨다. 두 경우 모두 검색 대상 Version이 없어 노출해도 검색 가용성에 영향이 없다.
*/
private void markDocumentIndexingIfNotSearchable(Document document) {
if (document.getStatus() == DocumentStatus.UPLOADED) {
document.markIndexing();
}
}

/**
* 계산된 Draft를 현재 실행 소유권으로 검증한 뒤 Version Chunk Set으로 원자 저장한다.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class DocumentChunkTransactionServiceTest {

private DocumentChunkTransactionService service;
private EmbeddingJob embeddingJob;
private Document document;
private DocumentVersion documentVersion;
private EmbeddingJobAttempt attempt;

Expand Down Expand Up @@ -120,6 +121,30 @@ void prepare_marksParsingAndReturnsSnapshot() {
assertThat(eventCaptor.getValue().getEventType()).isEqualTo(IndexingEventType.PARSE_STARTED);
}

@Test
@DisplayName("검색 가능한 Version이 없는 문서는 파싱 시작 시 INDEXING으로 전환된다")
void prepare_marksDocumentIndexingWhenNotSearchable() {
prepareEntities(DocumentType.TXT, DocumentVersionStatus.UPLOADED, DocumentStatus.UPLOADED);
givenValidContext();

service.prepare(JOB_ID, ATTEMPT_ID, WORKER_ID, CLAIM_TOKEN);

assertThat(document.getStatus()).isEqualTo(DocumentStatus.INDEXING);
}

@Test
@DisplayName("이미 INDEXED인 문서의 재인덱싱은 검색 가용성을 위해 INDEXED를 유지한다")
void prepare_keepsIndexedDocumentSearchableWhileReindexing() {
prepareEntities(DocumentType.TXT, DocumentVersionStatus.UPLOADED, DocumentStatus.INDEXED);
givenValidContext();

service.prepare(JOB_ID, ATTEMPT_ID, WORKER_ID, CLAIM_TOKEN);

// 검색 경로가 d.status = 'INDEXED'로 필터하므로 여기서 상태가 바뀌면 기존 Version이 검색에서 이탈한다.
assertThat(document.getStatus()).isEqualTo(DocumentStatus.INDEXED);
assertThat(documentVersion.getStatus()).isEqualTo(DocumentVersionStatus.PARSING);
}

@Test
@DisplayName("PARSING 재개는 상태와 시작 이벤트를 다시 만들지 않는다")
void prepare_resumesParsingWithoutDuplicateEvent() {
Expand Down Expand Up @@ -266,6 +291,14 @@ private void givenValidContext() {
}

private void prepareEntities(DocumentType documentType, DocumentVersionStatus versionStatus) {
prepareEntities(documentType, versionStatus, DocumentStatus.INDEXING);
}

private void prepareEntities(
DocumentType documentType,
DocumentVersionStatus versionStatus,
DocumentStatus documentStatus
) {
WorkerNode worker = WorkerNode.builder()
.workerName("worker")
.instanceId("instance")
Expand All @@ -274,11 +307,11 @@ private void prepareEntities(DocumentType documentType, DocumentVersionStatus ve
.build();
ReflectionTestUtils.setField(worker, "id", WORKER_ID);

Document document = Document.builder()
document = Document.builder()
.title("문서")
.documentType(documentType)
.sourceType(DocumentSourceType.UPLOAD)
.status(DocumentStatus.INDEXING)
.status(documentStatus)
.visibility(VisibilityType.PRIVATE)
.build();
ReflectionTestUtils.setField(document, "id", 3L);
Expand Down