배포용 엑셀에 DB 전 테이블 반영

merchant_keyword(업체↔키워드 연결)와 generation_run(생성 감사 로그)이
빠져 있었다. 시트 2개를 추가해 DB 7개 테이블을 모두 담는다.

시트별 행수를 DB 와 대조해 전부 일치 확인:
  키워드 7,093 / 지역 70 / 업종 9 / 업체 4 /
  업체키워드 11 / QA 20 / 생성이력 4

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
hbyang 2026-09-14 10:27:37 +09:00
parent 8322bd45cb
commit 54f8f83a7a
3 changed files with 43 additions and 1 deletions

View File

@ -71,7 +71,7 @@ DB 가 기준이다. 데이터셋 JSON 은 생성 원본일 뿐 적재분과 완
| 산출물 | 명령 | 용도 |
|---|---|---|
| `data/배포용_키워드_DB덤프.xlsx` | `npm run db:export-xlsx` | 사람이 읽고 검수하는 용도. 6시트 |
| `data/배포용_키워드_DB덤프.xlsx` | `npm run db:export-xlsx` | **DB 7개 테이블 전부**. 8시트 |
| `data/ontology-dump.sql.gz` | `npm run db:dump` | **임베딩 포함 그대로 복원**. 13MB, git 제외 |
### A. pg_dump 복원 (권장)
@ -94,6 +94,22 @@ npm run dataset:ingest && npm run dataset:ingest-nationwide
텍스트에서 임베딩을 다시 만든다. 최초 1회 모델 다운로드(약 50초) + 임베딩 약 15초.
같은 모델이면 값이 동일하게 나오므로 A 와 결과가 같다.
### 엑셀 시트 (DB 테이블과 1:1)
| 시트 | 테이블 | 행 |
|---|---|---:|
| 키워드 | `keyword` | 7,093 |
| 지역 | `region` | 70 |
| 업종 | `industry` | 9 |
| 업체 | `merchant` | 4 |
| 업체키워드 | `merchant_keyword` | 11 |
| QA(AEO) | `qa_pair` | 20 |
| 생성이력 | `generation_run` | 4 |
| 배포가이드 | — | 25 |
임베딩만 담지 않는다 (384 float × 7천 행). `[임베딩]` 열에 보유 여부만 표시하며,
같은 모델로 재생성하면 동일하게 복원된다.
### 현재 적재 내용
| 출처 | 건수 | 내용 |

View File

@ -92,6 +92,30 @@ sheet(wb, 'QA(AEO)', ['업체', '질문', '답변', '상태'],
FROM qa_pair q JOIN merchant m ON m.id=q.merchant_id
ORDER BY m.name, q.created_at"""), [16, 44, 70, 10])
# 5-b) 업체↔키워드 연결
sheet(wb, '업체키워드',
['업체', '키워드', '관련도', '상태', '출처', '노출수', '클릭수', 'CTR', '근거'],
query("""SELECT m.name, k.canonical, round(mk.relevance::numeric,2), mk.status::text,
mk.source, mk.impressions, mk.clicks, round(mk.ctr::numeric,4),
COALESCE(mk.rationale,'')
FROM merchant_keyword mk
JOIN merchant m ON m.id=mk.merchant_id
JOIN keyword k ON k.id=mk.keyword_id
ORDER BY m.name, mk.relevance DESC"""),
[16, 30, 9, 10, 10, 10, 9, 9, 28])
# 5-c) 생성 이력 (감사 로그)
sheet(wb, '생성이력',
['업체', 'provider', 'model', '프롬프트버전', '트리거', '상태', '통계', '시작', '종료'],
query("""SELECT COALESCE(m.name,''), g.provider, g.model, g.prompt_version,
g.trigger, g.status, g.stats::text,
to_char(g.started_at,'YYYY-MM-DD HH24:MI'),
COALESCE(to_char(g.finished_at,'YYYY-MM-DD HH24:MI'),'')
FROM generation_run g
LEFT JOIN merchant m ON m.id=g.merchant_id
ORDER BY g.started_at DESC"""),
[16, 10, 20, 14, 12, 10, 60, 17, 17])
# 6) 배포 가이드
counts = collections.Counter(r[8] for r in kw)
guide = [
@ -99,6 +123,8 @@ guide = [
('', f"벡터 DB(keyword 테이블)에 실제 적재된 {len(kw):,}건 전부. 데이터셋 JSON 이 아니라 DB 가 기준이다."),
('', '출처별: ' + ' · '.join(f'{k} {v:,}' for k, v in counts.most_common())),
('', 'dataset = 군산 상세(매칭 엔진 개발용) / nationwide = 전국 54개 지역'),
('', 'DB 의 7개 테이블을 모두 담았다: keyword / region / industry / merchant /'),
('', 'merchant_keyword / qa_pair / generation_run.'),
('', ''),
('임베딩은 왜 없나', ''),
('', '384개 float × 7천 행이라 엑셀에 담을 수 없고 담아도 못 읽는다.'),