pharmacy-pos-qr-system/docs/PostgresGRAPH전환.md
시골약사 032795c0fa docs: GraphRAG 및 그래프 DB 전환 기획 문서 추가
약국 POS 시스템의 GraphRAG 기반 추천 시스템 구축 관련 문서:

## 핵심 설계 문서

1. 질병코드기반 제품추천.md
   - ICD-10 질병 코드 활용 추천 시스템 설계
   - 계층 구조 (질병 → 질병군 → 제품군 → 개별 제품)
   - 처방전 기반 추천 알고리즘

2. complex-product-graph-modeling.md
   - 복합제(비맥스제트 등) 그래프 모델링
   - 성분 간 시너지 효과 표현
   - 복합 증상 매칭 쿼리 예시

3. pubmed-graphrag-workflow.md
   - PubMed → GraphRAG 전체 워크플로우 (5단계)
   - 논문 검색, 근거 추출, 지식 그래프 구축
   - MCP Server 개발 가이드

## 그래프 DB 비교 및 평가

4. sqlite-graph-evaluation.md
   - SQLite vs SQLite-Graph vs Neo4j 비교
   - 현 시점(2026-01) 평가: 기존 SQL 유지 권장
   - 6개월 후 재평가 계획

5. opensource-graph-db-comparison.md
   - 오픈소스 그래프 DB 비교 (Neo4j, ArangoDB 등)

6. 온톨로지로전환.md
   - 관계형 DB → 온톨로지 구조 전환 가이드
   - PubMed RAG 활용 방안
   - 추론 규칙 설계

## PubMed GraphRAG 활용

7. pycnogenol-multi-indication-graphrag.md
   - 피크노제놀 다중 적응증 GraphRAG 구축 사례
   - 7가지 적응증별 근거 수준

8. grpahrag_아쉬아간다.md
   - Ashwagandha GraphRAG 구축 사례

9. pubdmed이용ai.md
   - PubMed + AI 통합 활용 가이드

## 추가 워크플로우

10. pubmed-graphrag-workflow_next.md
    - 다음 단계 워크플로우

11. PostgresGRAPH전환.md
    - PostgreSQL + Apache AGE 전환 가이드

모든 문서는 한국어로 작성되었으며, 코드 예시는 영어로 포함.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-24 21:04:56 +09:00

561 lines
15 KiB
Markdown

# PostgreSQL Apache AGE 기반 약국 GraphRAG 추천 시스템 기획서
**작성일**: 2026-01-24
**프로젝트**: 약국 POS QR 마일리지 시스템 → 근거 기반 AI 추천 시스템 전환
---
## 1. 프로젝트 개요
### 목표
기존 SQLite 기반 약국 시스템을 **PostgreSQL + Apache AGE**로 확장하여, **PubMed 논문 근거 기반 GraphRAG 제품 추천 시스템** 구축
### 핵심 가치
-**근거 기반 추천**: "왜 이 제품을 추천하는가?" → 논문(PMID) 근거 제시
-**복합 증상 매칭**: "피로 + 소화불량 + 스트레스" → 최적 복합제 추천
-**추론 경로 시각화**: Statin → 근육약화 → CoQ10 추천 경로
-**AI 카테고리 관리**: 무분별한 증가 방지, 23개 기본 카테고리 유지
---
## 2. 현황 분석
### 현재 시스템
- **MSSQL (PIT3000)**: 판매 거래 데이터
- **SQLite (mileage.db)**: 제품 마스터, 카테고리, 질병 코드
- **PubMed 파이프라인**: 완성 (여러 연구 스크립트로 근거 수집 중)
### 주요 데이터
- 제품 마스터: 바코드 기준 (동일 제품 다른 이름 가능)
- 카테고리: 23개 기본 (진통제, 소화제, 복합비타민 등)
- 질병 코드: ICD-10 기반
- 제품-카테고리 매핑: 다대다 (relevance_score 0.0~1.0)
### 현재 한계
- ❌ 복잡한 관계 표현 불가 (약물 → 부작용 → 예방 관계)
- ❌ 추론 경로 제시 불가
- ❌ PubMed 근거와 제품 연결 미흡
- ❌ 성분 간 시너지 표현 불가
---
## 3. 기술 아키텍처
### 3.1 시스템 구조
```
┌─────────────────────────────────────┐
│ 웹앱 (Flask) + 관리자 대시보드 │
└───────────────┬─────────────────────┘
↓ REST API
┌───────────────────────────────────────┐
│ Flask Backend (Python) │
│ - GraphRAG Service (Cypher 쿼리) │
│ - OpenAI (카테고리 태깅) │
│ - PubMed (Biopython) │
└───────────────┬───────────────────────┘
┌───────────────────────────────────────┐
│ PostgreSQL 15 + Apache AGE │
├───────────────────────────────────────┤
│ SQL 테이블: │
│ - products (제품 마스터) │
│ - categories (카테고리) │
│ - evidence (PubMed 논문) │
├───────────────────────────────────────┤
│ 그래프 (Cypher): │
│ 노드: Product, Ingredient, │
│ Symptom, Disease, Evidence │
│ 엣지: CONTAINS, TREATS, CAUSES, │
│ PREVENTS, SYNERGY_WITH │
└───────────────────────────────────────┘
```
### 3.2 기술 스택
| 레이어 | 기술 |
|--------|------|
| **DB** | PostgreSQL 15 + Apache AGE 확장 |
| **Backend** | Python 3.11 + Flask |
| **그래프 쿼리** | Cypher (Apache AGE) |
| **AI** | OpenAI GPT-4o (카테고리 태깅, 추천 설명) |
| **PubMed** | Biopython (논문 검색 및 근거 수집) |
| **캐싱** | Redis (추천 결과 캐싱) |
| **라이브러리** | psycopg2, apache-age-python |
---
## 4. 데이터 모델 설계
### 4.1 그래프 노드 타입
#### Product (제품)
```cypher
(:Product {
barcode: '8806436016712',
name: '탁센캡슐',
manufacturer: '동아제약',
price: 8000
})
```
#### Ingredient (성분)
```cypher
(:Ingredient {
id: 'naproxen',
name: '나프록센',
category: 'NSAID'
})
```
#### Symptom (증상)
```cypher
(:Symptom {
id: 'headache',
name: '두통',
severity: 'moderate'
})
```
#### Disease (질병)
```cypher
(:Disease {
icd_code: 'K30',
name: '소화불량',
category: '소화기질환'
})
```
#### Evidence (PubMed 논문)
```cypher
(:Evidence {
pmid: '27959716',
title: 'CV Safety of Naproxen',
journal: 'NEJM',
year: 2016,
reliability: 0.99
})
```
### 4.2 그래프 관계 타입
| 관계 | From → To | 속성 | 의미 |
|------|-----------|------|------|
| **CONTAINS** | Product → Ingredient | amount, role | 제품이 성분 포함 |
| **TREATS** | Ingredient → Symptom/Disease | efficacy, evidence_pmid | 성분이 증상 치료 |
| **CAUSES** | Ingredient → Symptom | probability, severity | 성분이 부작용 유발 |
| **PREVENTS** | Ingredient → Symptom | efficacy, dosage | 성분이 부작용 예방 |
| **SYNERGY_WITH** | Ingredient ↔ Ingredient | synergy_score, reason | 성분 간 시너지 |
| **SAFER_THAN** | Product → Product | aspect, confidence | 제품 안전성 비교 |
| **BELONGS_TO** | Product → Category | relevance_score | 제품-카테고리 매핑 |
### 4.3 PostgreSQL 테이블
```sql
-- 제품 마스터
CREATE TABLE products (
barcode TEXT PRIMARY KEY,
product_name TEXT NOT NULL,
manufacturer TEXT,
price INTEGER,
stock INTEGER,
ingredients_json JSONB,
search_vector tsvector
);
-- 카테고리 (계층 구조)
CREATE TABLE categories (
category_id SERIAL PRIMARY KEY,
category_name TEXT UNIQUE NOT NULL,
parent_id INTEGER REFERENCES categories(category_id),
level INTEGER DEFAULT 1, -- 1: 기본 23개, 2-3: 서브
description TEXT
);
-- PubMed 논문
CREATE TABLE evidence (
pmid TEXT PRIMARY KEY,
title TEXT NOT NULL,
journal TEXT,
year INTEGER,
study_type TEXT,
abstract TEXT,
reliability REAL
);
```
---
## 5. 핵심 기능
### 5.1 근거 기반 제품 추천
**입력**:
- 증상: ["두통", "피로"]
- 환자 프로필: 65세, 고혈압, Statin 복용 중
- 예산: 20,000원
**Cypher 쿼리**:
```cypher
MATCH (p:Product)-[:CONTAINS]->(i:Ingredient)-[t:TREATS]->(s:Symptom)
WHERE s.name IN ['두통', '피로']
AND p.price <= 20000
OPTIONAL MATCH (e:Evidence {pmid: t.evidence_pmid})
WHERE e.reliability > 0.8
RETURN p.name, p.price,
COLLECT(s.name) AS symptoms,
e.pmid, e.title, e.reliability
ORDER BY e.reliability DESC, COUNT(DISTINCT s) DESC
LIMIT 5
```
**출력**:
```json
{
"recommendations": [
{
"name": "비맥스제트",
"price": 15000,
"symptoms_covered": ["피로", "소화불량"],
"evidence": {
"pmid": "12345678",
"title": "Vitamin B Complex for Fatigue",
"reliability": 0.85
},
"reasoning": "비타민 B복합체가 피로 회복에 효과적입니다. (PMID:12345678, 신뢰도: 85%)"
}
]
}
```
### 5.2 복합 증상 매칭 + 시너지
**Cypher 쿼리**:
```cypher
-- 피로 + 근육통 + 스트레스를 동시에 치료하면서 시너지 있는 제품
MATCH (p:Product)-[:CONTAINS]->(i1:Ingredient)-[:TREATS]->(s:Symptom)
WHERE s.name IN ['피로', '근육통', '스트레스']
WITH p, COUNT(DISTINCT s) AS coverage
WHERE coverage >= 2
MATCH (p)-[:CONTAINS]->(i1:Ingredient)-[:TREATS]->(:Symptom {name: '피로'})
MATCH (p)-[:CONTAINS]->(i2:Ingredient)-[:TREATS]->(:Symptom {name: '근육통'})
OPTIONAL MATCH (i1)-[syn:SYNERGY_WITH]->(i2)
RETURN p.name, coverage,
i1.name + ' + ' + i2.name AS combo,
syn.synergy_score AS synergy,
p.price
ORDER BY coverage DESC, synergy DESC
```
**예시 결과**: 비맥스제트 (비타민B1 + 마그네슘, 시너지 0.9)
### 5.3 추론 경로 시각화
**쿼리**: Statin → 근육약화 → CoQ10 추천 경로
```cypher
MATCH path = (drug:Ingredient {id: 'statin'})
-[:CAUSES]->(side:Symptom {name: 'muscle_weakness'})
<-[:PREVENTS]-(supplement:Ingredient {id: 'coq10'})
RETURN [node IN nodes(path) | node.name] AS reasoning_path,
[rel IN relationships(path) | type(rel)] AS relationships
```
**결과**:
```json
{
"reasoning_path": ["Statin", "근육약화", "CoQ10"],
"relationships": ["CAUSES", "PREVENTS"],
"explanation": "Statin은 근육약화를 유발할 수 있으며, CoQ10이 이를 예방합니다."
}
```
### 5.4 AI 카테고리 자동 태깅
**프로세스**:
1. 제품명 + 성분 정보 → OpenAI GPT-4o
2. 기존 23개 카테고리에서 1~3개 선택
3. relevance_score (0.0~1.0) 자동 계산
4. 그래프에 BELONGS_TO 관계 생성
**예시**:
```python
# 입력
product = {
"name": "탁센캡슐",
"ingredients": ["나프록센 250mg"]
}
# AI 응답
{
"categories": [
{"name": "진통소염제", "score": 1.0, "reason": "주성분이 NSAID"},
{"name": "진통제", "score": 0.9, "reason": "진통 효과"}
]
}
# 그래프 저장
CREATE (p:Product {barcode: '8806436016712'})
-[:BELONGS_TO {relevance_score: 1.0, tagged_by: 'AI'}]
->(c:Category {name: '진통소염제'})
```
---
## 6. 카테고리 관리 전략
### 6.1 3단계 계층 구조
```
Level 1 (고정 23개 - 기본 카테고리)
├─ 진통소염제
│ ├─ Level 2 (서브 카테고리)
│ │ ├─ NSAID
│ │ └─ 아세트아미노펜
│ └─ Level 3 (세분화)
│ └─ 심혈관 안전 NSAID
├─ 소화제
│ ├─ 위장약
│ └─ 정장제
└─ 복합비타민
├─ B복합체
└─ 종합비타민
```
### 6.2 신규 카테고리 추가 규칙
**원칙**:
- Level 1 (23개) = **절대 불변**
- Level 2-3 = 약사/AI 제안 → 검토 후 승인
- 월 최대 2개 신규 허용
- 최소 10개 제품 예상 시에만 추가
**워크플로우**:
1. 약사/AI가 신규 카테고리 제안
2. AI 검증 (필요성, 중복 여부)
3. 영향도 분석 (기존 제품 재분류 필요성)
4. 승인 시 → 기존 전체 제품 재검토 (AI 일괄 태깅)
---
## 7. 마이그레이션 계획
### Phase 1: 환경 설정 (1주)
```bash
# PostgreSQL + AGE 설치
sudo apt install postgresql-15 postgresql-15-age
# 그래프 생성
CREATE EXTENSION age;
SELECT create_graph('pharmacy_graph');
# Python 라이브러리
pip install psycopg2-binary apache-age-python biopython
```
### Phase 2: 데이터 마이그레이션 (2주)
**Step 1**: SQLite → PostgreSQL (SQL 테이블)
- products, categories, evidence
**Step 2**: 그래프 노드 생성
- Product, Ingredient, Symptom, Disease 노드
**Step 3**: 관계 생성
- CONTAINS, TREATS, BELONGS_TO 엣지
**Step 4**: PubMed 근거 통합
- 주요 약물-증상 쌍 100개 논문 수집
- Evidence 노드 + TREATS 관계에 pmid 연결
### Phase 3: 검증 및 테스트 (1주)
- 노드/엣지 개수 검증
- Cypher 쿼리 성능 테스트
- SQLite vs PostgreSQL+AGE 병렬 운영
### Phase 4: API 개발 (2주)
- `/api/recommend` - GraphRAG 추천
- `/api/graph/path` - 추론 경로
- `/api/categories/tag` - AI 자동 태깅
---
## 8. API 설계
### 8.1 POST `/api/recommend`
**Request**:
```json
{
"symptoms": ["두통", "피로"],
"patient_profile": {
"age": 65,
"conditions": ["HTN"],
"medications": ["Atorvastatin 10mg"]
},
"budget": 20000
}
```
**Response**:
```json
{
"recommendations": [
{
"barcode": "8806436016712",
"name": "탁센캡슐",
"price": 8000,
"score": 0.95,
"reasoning": {
"path": ["Naproxen", "TREATS", "두통"],
"evidence": {
"pmid": "27959716",
"title": "CV Safety of Naproxen",
"reliability": 0.99
}
}
}
]
}
```
### 8.2 GET `/api/products/<barcode>/graph`
제품의 전체 관계 그래프 반환 (성분, 증상, 근거 논문)
### 8.3 POST `/api/categories/tag-batch`
AI 일괄 카테고리 태깅
---
## 9. 성능 최적화
### 인덱스
```sql
CREATE INDEX idx_products_barcode ON products(barcode);
CREATE INDEX idx_products_search ON products USING GIN(search_vector);
CREATE INDEX idx_evidence_reliability ON evidence(reliability DESC);
```
### 캐싱 (Redis)
- 추천 결과: TTL 1시간
- 그래프 경로: TTL 24시간
- 카테고리 목록: TTL 7일
### Cypher 최적화
- 증상부터 역방향 탐색 (인덱스 활용)
- OPTIONAL MATCH 최소화
- WITH 절로 중간 필터링
---
## 10. 구현 우선순위
### 우선순위 1 (필수, 2주)
- ✅ PostgreSQL + AGE 설치
- ✅ 기본 스키마 생성
- ✅ SQLite 데이터 마이그레이션
- ✅ Product, Ingredient 노드 생성
- ✅ CONTAINS, TREATS 관계
### 우선순위 2 (핵심, 2주)
-`/api/recommend` API
- ✅ PubMed 근거 통합 (100개 논문)
- ✅ 복합 증상 매칭 Cypher 쿼리
- ✅ 추론 경로 생성
### 우선순위 3 (AI, 1주)
- ✅ AI 카테고리 자동 태깅
- ✅ 신규 카테고리 제안 워크플로우
- ✅ 카테고리 계층 관리
### 우선순위 4 (최적화, 1주)
- ✅ 인덱스 최적화
- ✅ Redis 캐싱
- ✅ 성능 벤치마크
---
## 11. 핵심 파일 구조
```
backend/
├─ migration/
│ ├─ migrate_to_postgres.py # SQLite → PostgreSQL
│ ├─ build_graph.py # 그래프 노드 생성
│ └─ integrate_pubmed.py # PubMed 근거 통합
├─ services/
│ ├─ graphrag_service.py # GraphRAG 추천 로직
│ ├─ ai_tagging.py # AI 카테고리 태깅
│ └─ category_service.py # 카테고리 관리
├─ api/
│ ├─ recommend.py # 추천 API
│ └─ categories.py # 카테고리 API
├─ db/
│ ├─ age_connector.py # Apache AGE 연결
│ └─ schema.sql # PostgreSQL 스키마
└─ pubmed_search.py # PubMed 검색 (재사용)
```
---
## 12. 예상 효과
### 비즈니스 가치
- **업셀링 증가**: 복합제 추천으로 객단가 +50%
- **고객 신뢰**: 논문 근거 제시로 재방문율 +30%
- **전문성 강화**: 약국 브랜드 이미지 향상
### 기술적 이점
- **확장성**: 수만 개 제품 처리 가능
- **유연성**: 새 관계 타입 쉽게 추가
- **추론 가능**: 다단계 복합 쿼리
### 차별화
- 타 약국 대비 **과학적 근거 기반 추천**
- AI + GraphRAG 결합한 **최초 약국 시스템**
---
## 13. 리스크 및 대응
| 리스크 | 대응 방안 |
|--------|----------|
| PostgreSQL 학습 곡선 | 단계적 마이그레이션, SQLite 병렬 운영 |
| Apache AGE 초기 버전 | 핵심 기능만 사용, SQL Fallback |
| PubMed API 제한 | API 키 발급, 캐싱, 배치 처리 |
| AI 비용 | GPT-4o-mini 사용, 결과 캐싱 |
---
## 14. 다음 단계
### 즉시 시작 (이번 주)
1. PostgreSQL 15 + AGE 설치 테스트
2. 샘플 그래프 생성 (10개 제품)
3. 기본 Cypher 쿼리 실습
### 다음 주
1. SQLite → PostgreSQL 마이그레이션 스크립트
2. PubMed 100개 논문 수집
3. `/api/recommend` 프로토타입
### 다음 달
1. 전체 시스템 통합
2. 웹앱 UI 추가
3. 성능 최적화
---
**작성자**: Claude Sonnet 4.5
**검토 필요 사항**:
- PostgreSQL 서버 사양 확인
- PubMed API 키 발급
- 카테고리 계층 최종 승인