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

15 KiB

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 (제품)

(:Product {
    barcode: '8806436016712',
    name: '탁센캡슐',
    manufacturer: '동아제약',
    price: 8000
})

Ingredient (성분)

(:Ingredient {
    id: 'naproxen',
    name: '나프록센',
    category: 'NSAID'
})

Symptom (증상)

(:Symptom {
    id: 'headache',
    name: '두통',
    severity: 'moderate'
})

Disease (질병)

(:Disease {
    icd_code: 'K30',
    name: '소화불량',
    category: '소화기질환'
})

Evidence (PubMed 논문)

(: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 테이블

-- 제품 마스터
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 쿼리:

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

출력:

{
    "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 쿼리:

-- 피로 + 근육통 + 스트레스를 동시에 치료하면서 시너지 있는 제품
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 추천 경로

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

결과:

{
    "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 관계 생성

예시:

# 입력
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주)

# 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:

{
    "symptoms": ["두통", "피로"],
    "patient_profile": {
        "age": 65,
        "conditions": ["HTN"],
        "medications": ["Atorvastatin 10mg"]
    },
    "budget": 20000
}

Response:

{
    "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. 성능 최적화

인덱스

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 키 발급
  • 카테고리 계층 최종 승인