jdbc.batchUpdate(SqlParameterSource[]) 단일 호출 + IdGenerator.newId() 공통화. 테스트는 본 범위 밖 (#343 후속 테스트 인프라). 설계서: docs/design/331-vector-batch-insert/README.md (Approved) Refs: #331 (Architect)
3.7 KiB
3.7 KiB
설계서: VectorService batch insert + IdGenerator 공통화 (#331)
상태: Approved 작성: [AI] Architect · 최종수정: 2026-06-15 추적성 — Redmine: #331 · 부모: #293 (검색/벡터 Reviewer 후속, 09-Done) · 구현 파일:
backend-java/src/main/java/com/tasteby/service/VectorService.java· 테스트: 본 이슈 범위 밖 (단위 테스트 인프라 도입은 #343 후속 묶음에 해당)
1. 목적 (Why)
VectorService.saveRestaurantVectors가 chunk N개를 N번의 단건 jdbc.update로 처리한다. 현재 buildChunks가 1개 청크만 반환해 N=1이지만, 향후 chunk 분할 도입 시 N+1 INSERT 비효율. 또한 UUID 생성 코드가 인라인 변환(UUID.randomUUID().toString().replace("-", "").substring(0, 32).toUpperCase())으로 다른 곳의 IdGenerator.newId()와 중복.
2. 범위
- 포함
jdbc.batchUpdate(sql, SqlParameterSource[])로 단일 호출 전환.- UUID 생성을
IdGenerator.newId()공통 유틸로 교체.
- 제외
- 단위/통합 테스트 도입 (테스트 인프라 미도입 — 별도 후속 #343 묶음).
buildChunks의 chunk 분할 로직 자체 변경 (현재 단일 청크 정책 유지).restaurant_vectors스키마 변경.
3. 인수조건
saveRestaurantVectors가 한 번의jdbc.batchUpdate호출로 N개 청크 삽입.- UUID 인라인 변환 제거 →
IdGenerator.newId()호출. - 회귀 없음 — 신규 식당 등록 시
restaurant_vectors에 정상 row 추가. - N=0 가드(
chunks.isEmpty())는 유지.
4. 컨텍스트 & 제약
- Spring
NamedParameterJdbcTemplate.batchUpdate(String, SqlParameterSource[])사용. - Oracle VECTOR 타입 파라미터는
float[]로 그대로 바인딩 가능 (MapSqlParameterSource.addValue). - 한 batch 안
int[]반환 → batch 결과 카운트는 사용하지 않음(throw if 어쩌고 미적용). IdGenerator.newId()시그니처:public static String newId()→ 32-char uppercase hex (현재 인라인과 동일).
5. 아키텍처 개요
saveRestaurantVectors(restaurantId, chunks)
├ if chunks.isEmpty() → return
├ embeddings = genAi.embedTexts(chunks)
├ params[] = build N개 MapSqlParameterSource
│ .addValue("id", IdGenerator.newId())
│ .addValue("rid", restaurantId)
│ .addValue("chunk", chunks.get(i))
│ .addValue("emb", float[] embeddings[i])
└ jdbc.batchUpdate(sql, params)
6. 함수 명세
| 함수 | 책임 | 비고 |
|---|---|---|
VectorService.saveRestaurantVectors(id, chunks) (수정) |
batchUpdate 1회 | IdGenerator 사용 |
7. 흐름
- embed 호출 (기존).
SqlParameterSource[]생성.jdbc.batchUpdate(sql, params)단일 호출.
8. 엣지케이스
- chunks 빈 배열: 조기 return (기존 유지).
- embed 결과와 chunks 크기 불일치: 현재 OCI GenAI는 입력 N → 출력 N 보장. 안전 가드 추가는 본 범위 밖 (필요 시 후속).
9. 테스트 (수동만)
- dev에서 신규 식당 등록(데몬 또는 수동 trigger) →
SELECT count(*) FROM restaurant_vectors WHERE restaurant_id = '...'정상 row 확인.
10. 리스크 & 대안
- 선택:
NamedParameterJdbcTemplate.batchUpdate. 단일 트랜잭션 + 단일 round-trip. - 대안 A:
JdbcTemplate.batchUpdate(BatchPreparedStatementSetter)— 더 저수준이지만 named param 손실. - 대안 B: MERGE로 upsert — 동일 restaurant_id 재처리 시 중복 제거 가능. 다만 본 이슈 범위 밖.
11. 미해결 질문
- chunk 분할 정책(현재 1개 단일 청크) — 후속 (검색 정확도 vs 토큰 비용 트레이드오프 결정).
- batchUpdate 결과 row 수 검증 — 운영 모니터링 도구 도입 후 결정.