ETL ํ์ดํ๋ผ์ธ
UBIST ์ฒ๋ฐฉ์กฐ์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ์ผ์์ PostgreSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก ์ ์ฌํ๋ ETL(Extract-Transform-Load) ํ์ดํ๋ผ์ธ์ ๊ตฌ์กฐ์ ์คํ ๋ฐฉ๋ฒ์ ์ค๋ช ํฉ๋๋ค.
UBIST ์์ ๊ตฌ์กฐ
UBIST์์ ์ ๊ณตํ๋ ์์ ํ์ผ์ Wide/Pivot ํํ์ ๋๋ค.
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ํ์ผ๋ช | UBIST_D1 Sales.xlsx |
| ์ํธ | Sheet1 |
| ํ ์ | ์ฝ 110,000ํ |
| ์ปฌ๋ผ ๊ตฌ์กฐ | 10๊ฐ ์ฐจ์ ์ปฌ๋ผ + 3๊ฐ ์งํ x 60๊ฐ์ = 191 ์ปฌ๋ผ |
| ๋ฐ์ดํฐ ๋ฒ์ | 268๊ฐ ์ ์กฐ์ฌ, 13,265๊ฐ ์ ํ, 60๊ฐ์๋ถ |
์ฐจ์ ์ปฌ๋ผ (10๊ฐ)
| ์์ ์ปฌ๋ผ | DB ์ปฌ๋ผ๋ช | ์ค๋ช |
|---|---|---|
| ์ ์กฐ์ฌ (A์ด) | manufacturer | 268๊ฐ ์ ์กฐ์ฌ. ์์ฌ๋ โ์ ๋์จโ |
| ํ๋งค์ฌ (B์ด) | seller | ํ๋งค์ฌ๋ช |
| ์ ํ (C์ด) | product | 13,265๊ฐ ์ ํ๋ช |
| ATC (E์ด) | atc_class | ATC ์ฝํจ๊ตฐ ๋ถ๋ฅ |
| ์ฑ๋ถ (F์ด) | ingredient | ์ฃผ์ฑ๋ถ๋ช |
| ์์ฝ์ฒ (G์ด) | kfda_class | ์์ฝ์ฒ ๋ถ๋ฅ |
| ์ ํ (H์ด) | dosage_form | ์ ํ (์ ์ , ์บก์ ๋ฑ) |
| ํฌ์ฌ๊ฒฝ๋ก (I์ด) | admin_route | ๊ฒฝ๊ตฌ, ์ฃผ์ฌ ๋ฑ |
| ๊ธ์ฌ๊ตฌ๋ถ (J์ด) | reimbursement_type | ๊ธ์ฌ/๋ณธ์ธ๋ถ๋ด/๋น๊ธ์ฌ |
| ๋ณ์ (K์ด) | bed_size | ์๋ฃ๊ธฐ๊ด ๊ท๋ชจ (300+/100 |
์งํ ์ปฌ๋ผ (3๊ฐ x 60๊ฐ์)
| ์งํ ์ ๋ฏธ์ฌ | DB ์ปฌ๋ผ๋ช | ๋จ์ |
|---|---|---|
| ์ฒ๋ฐฉ๊ฑด์_P | prescription_count | ๊ฑด |
| ์ฒ๋ฐฉ์กฐ์ ์ก(์) | prescription_amount | ์ |
| ์ฒ๋ฐฉ๋_P | prescription_qty | ์๋ |
WideโLong ๋ณํ
ETL์ ํต์ฌ์ Wide ํํ(์์ด ์ปฌ๋ผ)๋ฅผ Long ํํ(์์ด ํ)๋ก ๋ณํํ๋ ๊ฒ์ ๋๋ค.
๋ณํ ์ (Wide)
์ ์กฐ์ฌ | ์ ํ | ATC | 2025-01_์ฒ๋ฐฉ๊ฑด์ | 2025-01_์ฒ๋ฐฉ์ก | 2025-01_์ฒ๋ฐฉ๋ | 2025-02_์ฒ๋ฐฉ๊ฑด์ | ...
์ ๋์จ | A์ ํ | N02 | 150 | 5000000 | 300 | 160 | ...๋ณํ ํ (Long)
์ ์กฐ์ฌ | ์ ํ | ATC | ์ฐ์ | ์ฒ๋ฐฉ๊ฑด์ | ์ฒ๋ฐฉ์ก | ์ฒ๋ฐฉ๋
์ ๋์จ | A์ ํ | N02 | 2025-01 | 150 | 5000000 | 300
์ ๋์จ | A์ ํ | N02 | 2025-02 | 160 | 5200000 | 320๋ณํ ๊ท์น
- 3๊ฐ ์งํ(์ฒ๋ฐฉ๊ฑด์, ์ฒ๋ฐฉ์ก, ์ฒ๋ฐฉ๋)๊ฐ ๋ชจ๋ 0์ธ ์์ ์ ์ธํฉ๋๋ค (๋ถํ์ํ ์ ๋ก ๋ ์ฝ๋ ๋ฐฉ์ง).
- ๋์ผ ๋ฐฐ์น ๋ด ์ค๋ณต ํค(์ ์กฐ์ฌ+์ ํ+์ฐ์)๊ฐ ์กด์ฌํ๋ฉด UPSERT๋ก ์ต์ ๊ฐ์ ์ ์งํฉ๋๋ค.
- D์ด(์ ์กฐ์ฌ ์ค๋ณต)์ ๋ฌด์ํฉ๋๋ค (A์ด๊ณผ 100% ๋์ผ).
์คํ ๋ช ๋ น์ด
ETL ์คํฌ๋ฆฝํธ๋ scripts/ubist_import.py์
๋๋ค.
์ ์ฒด ์ ์ฌ
์ ์ฒด ๋ฐ์ดํฐ๋ฅผ ํ ๋ฒ์ ์ ์ฌํฉ๋๋ค. ์ต์ด ์คํ ๋๋ ์ ์ฒด ์ฌ์ ์ฌ ์ ์ฌ์ฉํฉ๋๋ค.
python3 scripts/ubist_import.py --file "UBIST_D1 Sales.xlsx" --directํน์ ์ฐ๋๋ง ์ ์ฌ
ํน์ ์ฐ๋์ ๋ฐ์ดํฐ๋ง ์ ์ฌํฉ๋๋ค. ์ฆ๋ถ ์ ๋ฐ์ดํธ ์ ์ฌ์ฉํฉ๋๋ค.
python3 scripts/ubist_import.py --file "UBIST_D1 Sales.xlsx" --year 2025๋๋ผ์ด๋ฐ (ํ ์คํธ)
์ค์ DB์ ์ ์ฌํ์ง ์๊ณ ๋ณํ ๊ฒฐ๊ณผ๋ง ํ์ธํฉ๋๋ค. ์ ํ์ผ ๊ฒ์ฆ ์ ์ฌ์ฉํฉ๋๋ค.
python3 scripts/ubist_import.py --file "UBIST_D1 Sales.xlsx" --dry-runํน์ ์ฐ๋ ์ญ์
ํน์ ์ฐ๋์ UBIST ๋ฐ์ดํฐ๋ฅผ DB์์ ์ญ์ ํฉ๋๋ค.
python3 scripts/ubist_import.py --delete-year 2021์คํ ํ๋ฆ
ETL ์คํฌ๋ฆฝํธ์ ๋ด๋ถ ์ฒ๋ฆฌ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์์ ํ์ผ ๋ก๋ (openpyxl, read_only ๋ชจ๋๋ก ๋ฉ๋ชจ๋ฆฌ ํจ์จํ)
- ํค๋ ํ์ฑ (1~2ํ: ์งํ ๊ทธ๋ฃน + ์ ํค๋ ๋งคํ)
- WideโLong ๋ณํ (ํ x ์ ์กฐํฉ์ ๊ฐ๋ณ ๋ ์ฝ๋๋ก ๋ถํด)
- ์ ๋ก๊ฐ ์คํต (3๊ฐ ์งํ ๋ชจ๋ 0์ด๋ฉด ํด๋น ๋ ์ฝ๋ ์ ์ธ)
- ๋ฐฐ์น ๋ด ์ค๋ณต ์ ๊ฑฐ (UPSERT ํค ๊ธฐ์ค)
- ๋ฒํฌ UPSERT (psycopg2 execute_values, 5,000ํ ๋จ์ ๋ฐฐ์น)
- ์ ์ฌ ์๋ฃ ํ ์บ์ ์๋ ๊ฐฑ์ (
refresh_all_kpi_cache()ํธ์ถ)
์๋ฌ ์ฒ๋ฆฌ
ํ์ผ ๊ด๋ จ ์๋ฌ
| ์๋ฌ | ์์ธ | ํด๊ฒฐ |
|---|---|---|
| FileNotFoundError | ํ์ผ ๊ฒฝ๋ก ์ค๋ฅ | --file ๊ฒฝ๋ก ํ์ธ, ํ์ผ๋ช
๊ณต๋ฐฑ ์ฃผ์ (๋ฐ์ดํ๋ก ๊ฐ์ธ๊ธฐ) |
| ํค๋ ํ์ฑ ์คํจ | ์์ ๊ตฌ์กฐ ๋ณ๊ฒฝ | UBIST ํ์ผ ํ์์ด ๋ณ๊ฒฝ๋์๋์ง ํ์ธ. ์ปฌ๋ผ ์์ ๊ฒ์ฆ |
| ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ | 96MB ํ์ผ ๋ก๋ ์ | read_only=True ๋ชจ๋ ํ์ธ. ์๋ฒ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ ํ๋ณด |
DB ๊ด๋ จ ์๋ฌ
| ์๋ฌ | ์์ธ | ํด๊ฒฐ |
|---|---|---|
| Connection refused | DB ์ฐ๊ฒฐ ์คํจ | Supabase Docker ์ปจํ ์ด๋ ์ํ ํ์ธ |
| UNIQUE violation | ์ค๋ณต ํค ์ถฉ๋ | UPSERT๊ฐ ์ ์ ๋์ํ๋ฉด ๋ฐ์ํ์ง ์์. ์คํฌ๋ฆฝํธ ๋ฒ์ ํ์ธ |
| Disk full | ๋์คํฌ ์ฉ๋ ๋ถ์กฑ | ๋์คํฌ ์ฌ์ ๊ณต๊ฐ ํ๋ณด ํ ์ฌ์คํ |
์ฌ์คํ ์์ ์ฑ
ETL ์คํฌ๋ฆฝํธ๋ UPSERT(INSERT ON CONFLICT UPDATE) ๋ฐฉ์์ผ๋ก ๋์ํ๋ฏ๋ก, ๊ฐ์ ํ์ผ์ ์ฌ๋ฌ ๋ฒ ์คํํด๋ ๋ฐ์ดํฐ๊ฐ ์ค๋ณต๋์ง ์์ต๋๋ค. ์๋ฌ ๋ฐ์ ์ ์์ธ์ ํด๊ฒฐํ ํ ๋์ผํ ๋ช ๋ น์ด๋ก ์ฌ์คํํ๋ฉด ๋ฉ๋๋ค.
์์กด์ฑ
ETL ์คํฌ๋ฆฝํธ ์คํ์ ํ์ํ Python ํจํค์ง์ ๋๋ค.
| ํจํค์ง | ์ญํ |
|---|---|
| openpyxl | ์์ ํ์ผ ํ์ฑ |
| psycopg2-binary | PostgreSQL ์ฐ๊ฒฐ ๋ฐ ๋ฒํฌ UPSERT |
| python-dotenv | .env ํ์ผ์์ ํ๊ฒฝ๋ณ์ ๋ก๋ |
pip install -r scripts/requirements.txtํ๊ฒฝ๋ณ์
ETL ์คํฌ๋ฆฝํธ๊ฐ ์ฌ์ฉํ๋ ํ๊ฒฝ๋ณ์์
๋๋ค. ํ๋ก์ ํธ ๋ฃจํธ์ .env ํ์ผ์ ์ค์ ํฉ๋๋ค.
| ํ๊ฒฝ๋ณ์ | ์ค๋ช |
|---|---|
| DATABASE_URL | PostgreSQL ์ฐ๊ฒฐ ๋ฌธ์์ด |
| POSTGRES_PASSWORD | PostgreSQL ๋น๋ฐ๋ฒํธ |
๋ค์ ๋จ๊ณ
- ์บ์ ๊ด๋ฆฌ โ ETL ์ดํ ์บ์ ๊ฐฑ์ ์ ๋ต
- ๋ฌธ์ ํด๊ฒฐ โ ETL ์คํจ ์ ๋์ ๋ฐฉ๋ฒ