|
2 | 2 | title: "09_DB 스키마 공개" |
3 | 3 | date: 2026-07-14T12:09:00 |
4 | 4 | slug: 12 |
| 5 | +authors: [sbin] |
5 | 6 | last_update: |
6 | | - date: 2026-07-20 |
| 7 | + date: 2026-07-21 |
7 | 8 | --- |
8 | 9 |
|
9 | 10 | ### 들어가며 |
10 | 11 |
|
11 | 12 | --- |
12 | 13 |
|
13 | | -테이블 어떻게 구성되었나 dbdiagram 여러개로 나누어서 설명 |
| 14 | +SceneMaker가 방송 영상을 분석해 저장하는 데이터 구조를 공개한다. |
14 | 15 |
|
15 | 16 | <!--truncate--> |
16 | 17 |
|
| 18 | +-github DB 스키마 링크 포함 필수- |
| 19 | + |
| 20 | + |
| 21 | +> 저장 형식은 정형 데이터, 비정형 데이터가 있다 . 프로젝트에서 사용한 DB는 아래와 같다. |
| 22 | +
|
| 23 | +| | MariaDB (관계형) | Milvus (VectorDB) | |
| 24 | +| --- | --- | --- | |
| 25 | +| 담는 것 | 정형 데이터. AI 결과를 **읽히는 형태** 로 (자막·요약·인물·감정) | 비정형 데이터. 텍스트의 **임베딩 벡터** + 검색용 메타 | |
| 26 | +| 역할 | **원본 진실** (Single Source of Truth) | **검색용 파생본** | |
| 27 | + |
| 28 | +### 전체 데이터 저장 흐름 |
| 29 | + |
| 30 | +--- |
| 31 | + |
| 32 | +데이터 저장소는 Mysql 과 Milvus 를 사용하고 있으며 아래의 흐름으로 데이터가 저장된다. |
| 33 | + |
| 34 | + |
| 35 | + |
| 36 | +관계형 테이블은 `t_video` 를 중심으로 `v_id` 로 연결된다. |
| 37 | + |
| 38 | +```text |
| 39 | +t_video ─┬─ t_dialogue / t_dialogue_refine (대사) |
| 40 | + ├─ t_segment / t_segment_refine (6초 화면분석) |
| 41 | + ├─ t_chapter (씬/서브) |
| 42 | + ├─ t_scene (사건 단위 장면) |
| 43 | + ├─ t_category (분류, 자기참조 계층) |
| 44 | + └─ t_code (상태 코드) |
| 45 | +``` |
| 46 | + |
| 47 | + |
| 48 | +각 데이터베이스들의 구성을 확인해보자. |
| 49 | + |
| 50 | + |
| 51 | +### 1. MariaDB 테이블 |
| 52 | + |
| 53 | +--- |
| 54 | + |
| 55 | + |
| 56 | + |
| 57 | +#### t_video — 영상 (중심 테이블) |
| 58 | + |
| 59 | +영상 한 편의 메타와 최종 요약을 담는다. |
| 60 | + |
| 61 | +| 컬럼 | 타입 | 설명 | |
| 62 | +| --- | --- | --- | |
| 63 | +| `v_id` | mediumint | **PK** , 영상 ID | |
| 64 | +| `p_v_id` | mediumint | 시리즈 연결(예: 시즌2→시즌1 참조) | |
| 65 | +| `cate_id` | smallint | FK → `t_category` | |
| 66 | +| `name` | varchar(45) | 영상명 | |
| 67 | +| `dir` | varchar(200) | 영상 저장 위치 | |
| 68 | +| `summary` / `summary_stt` | text | 전체 줄거리 / STT 단계 요약 | |
| 69 | +| `cast` | text | STT가 남긴 등장인물 | |
| 70 | +| `status_code` | smallint | FK → `t_code` , 처리 상태 | |
| 71 | +| `reg/upd_datetime` | datetime | 입력·변경 시각 | |
| 72 | + |
| 73 | +#### t_category — 카테고리 (자기참조 계층) |
| 74 | + |
| 75 | +`p_cate_id` 로 상위 카테고리를 가리켜 "스포츠 → 야구" 같은 계층을 만듭니다. |
| 76 | + |
| 77 | +| 컬럼 | 설명 | |
| 78 | +| --- | --- | |
| 79 | +| `cate_id` (PK) / `cate_name` | 카테고리 ID / 이름 | |
| 80 | +| `p_cate_id` | 상위 카테고리 | |
| 81 | + |
| 82 | +#### t_dialogue — 대사 (자막) |
| 83 | + |
| 84 | +STT 결과. `(v_id, idx)` 가 PK인 시간순 대사입니다. |
| 85 | + |
| 86 | +| 컬럼 | 타입 | 설명 | |
| 87 | +| --- | --- | --- | |
| 88 | +| `v_id, idx` | | **PK** , 영상·대사순서 | |
| 89 | +| `start_time / end_time` | time(1) | 발화 구간 | |
| 90 | +| `speaker` / `speaker_name` | char(4) / varchar | 발화자 라벨 / 교정된 실명 | |
| 91 | +| `lang` | char | 발화 언어 | |
| 92 | +| `dialogue` | varchar(500) | 대사 본문 | |
| 93 | + |
| 94 | +> `t_dialogue_refine` 은 인물명 보정을 거친 2차본으로, 스키마는 거의 동일합니다. |
| 95 | +
|
| 96 | +#### t_segment — 6초 화면분석 (검색 원자) |
| 97 | + |
| 98 | +영상을 6초 단위로 자른 화면 분석 결과. 검색의 최소 단위입니다. |
| 99 | + |
| 100 | +| 컬럼 | 타입 | 설명 | |
| 101 | +| --- | --- | --- | |
| 102 | +| `v_id, seg_id` | | **PK** | |
| 103 | +| `start_time / end_time` | time | 6초 구간 | |
| 104 | +| `summary` | varchar(1024) | 화면 내용 요약 | |
| 105 | +| `adv` | tinyint | 광고 포함 여부 | |
| 106 | +| `meta` | JSON | 카테고리별 구조 속성(스포츠=스코어/이닝…) | |
| 107 | +| `status_code / status_reason` | | 처리 상태 | |
| 108 | + |
| 109 | +> `t_segment_refine` 은 보정본으로 `cast · ocr · sound · action` (JSON) 필드가 추가됨. (agent-vision 산출물) |
| 110 | +
|
| 111 | +#### t_chapter — 씬 / 서브 (계층 요약) |
| 112 | + |
| 113 | +`level` 로 씬(2)과 서브·막(1)을 구분하고, `parent_chap_id` 로 씬→서브를 연결합니다. |
| 114 | + |
| 115 | +| 컬럼 | 설명 | |
| 116 | +| --- | --- | |
| 117 | +| `v_id, chap_id` (PK) | | |
| 118 | +| `level` | 1=서브(막) / 2=씬 | |
| 119 | +| `parent_chap_id` | 씬이 속한 서브 | |
| 120 | +| `start/end_time` , `start/end_seg` | 시간·세그먼트 범위 | |
| 121 | +| `title` / `summary` | 라벨 / 줄거리(임베딩 대상) | |
| 122 | +| `cast` / `keywords` / `emotion` | 등장인물 / 키워드 / 감정 | |
| 123 | +| `meta` | 확장 JSON | |
| 124 | + |
| 125 | +#### t_scene — 사건 단위 장면 |
| 126 | + |
| 127 | +장르별 사건 단위(스포츠=홈런/삼진 등). 검색 필터용 구조 속성을 JSON으로 가집니다. |
| 128 | + |
| 129 | +| 컬럼 | 설명 | |
| 130 | +| --- | --- | |
| 131 | +| `v_id, scene_id` (PK) | | |
| 132 | +| `scene_type` / `description` | 사건 유형 / 서술(임베딩 대상) | |
| 133 | +| `is_replay` / `is_ad` | 리플레이·광고 배제 플래그 | |
| 134 | +| `attributes` | JSON (스포츠=투수/타자/이닝/스코어…) | |
| 135 | + |
| 136 | +> 이 밖에 `t_play` (야구 특화, `t_scene` 으로 대체됨)·`t_segment_2` (실험용) 레거시 테이블이 있다. |
| 137 | +
|
| 138 | +--- |
| 139 | + |
| 140 | +### 2. Milvus 컬렉션 — sm_1024 |
| 141 | + |
| 142 | +> 관계형 데이터 중 검색 대상(자막·화면·씬·서브)을 임베딩해 담는 벡터 컬렉션 |
| 143 | +의미 기반 검색이기에, 비정형 데이터를 사용하였다. |
| 144 | + |
| 145 | +**한 행 = 벡터 + 검색용 메타 복사본** . |
| 146 | + |
| 147 | +| 필드 | 타입 | 설명 | |
| 148 | +| --- | --- | --- | |
| 149 | +| `pk` | VARCHAR(64) | **PK** , `"v_id:ref_type:ref_id"` | |
| 150 | +| `vector` | FLOAT_VECTOR(1024) | 임베딩 벡터 (유일한 벡터 값) | |
| 151 | +| `v_id` | INT32 | 영상 ID (→ RDB) | |
| 152 | +| `ref_type` | VARCHAR(16) | segment / scene / chapter / dialogue | |
| 153 | +| `ref_id` | INT16 | RDB의 seg_id / chap_id / idx | |
| 154 | +| `p_ref_id` | INT16 | 소속 씬(부모 맥락) | |
| 155 | +| `start/end_sec` , `start/end_time` | INT16 / VARCHAR | 시간 범위 | |
| 156 | +| `cast` | VARCHAR(500) | 등장인물 | |
| 157 | +| `text` | VARCHAR(2048) | 임베딩 원문 | |
| 158 | +| `dialogue / segment / scene` | JSON | 원본 스냅샷 | |
| 159 | + |
| 160 | +- **인덱스** : `vector` → HNSW / **유사도** : COSINE |
| 161 | +- **동적 필드** (`enable_dynamic_field=True` ): `cate_id, emotion, highlight, events, is_ad` |
| 162 | + |
| 163 | + |
| 164 | +--- |
| 165 | + |
| 166 | +### 3. 두 저장소의 연결 |
| 167 | + |
| 168 | +Milvus의 각 벡터는 `pk = v_id : ref_type : ref_id` 로 관계형 원본 행과 1:1로 이어집니다. |
| 169 | + |
| 170 | +```text |
| 171 | +Milvus "42:segment:120" ←→ RDB t_segment (v_id=42, seg_id=120) |
| 172 | +``` |
| 173 | + |
| 174 | +`ref_type` 이 어느 테이블인지를, `ref_id` 가 그 테이블의 PK 일부(`seg_id` /`chap_id` /`idx` )를 가리킵니다. |
| 175 | + |
| 176 | +### 4. 저장 순서 |
| 177 | + |
| 178 | +데이터는 파이프라인을 따라 아래 순서로 쌓입니다. (작은 원자 → 파생 → 벡터 색인) |
| 179 | + |
| 180 | +| 순서 | 저장 | 담당 | |
| 181 | +| --- | --- | --- | |
| 182 | +| 1 | `t_video` (껍데기) | 등록 | |
| 183 | +| 2 | `t_dialogue` · `t_segment` | agent-stt · agent-vision | |
| 184 | +| 3 | `t_chapter` · `t_scene` | agent-scenario | |
| 185 | +| 4 | `t_video.summary` | agent-scenario | |
| 186 | +| 5 | **Milvus** `sm_1024` (벡터 색인) | agent-scenario | |
| 187 | + |
| 188 | +관계형 저장이 모두 끝난 뒤, 마지막에 벡터 색인이 이뤄집니다. |
| 189 | + |
| 190 | + |
| 191 | + |
17 | 192 | ### 마무리 |
18 | 193 |
|
19 | 194 | --- |
20 | 195 |
|
| 196 | +전체 DDL과 컬렉션 정의는 저장소에 공개돼 있습니다. SceneMaker는 Apache 2.0으로 배포됩니다. |
| 197 | + |
| 198 | + |
| 199 | +*본 글은 과학기술정보통신부·정보통신산업진흥원 「2026년 오픈소스 AI·SW 개발·활용 지원사업」의 지원으로 수행된 연구 결과입니다.* |
| 200 | + |
21 | 201 |
|
0 commit comments