pharmacy-pos-qr-system/docs/sqlite-graph-evaluation.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

11 KiB

SQLite-Graph 도입 평가

현재 시점(2026-01-24)에서 SQLite-Graph를 우리 프로젝트에 도입해야 하는가?


🎯 결론: 아직은 기존 SQL 유지 권장

이유

  1. 아직 초기 버전 (Cypher 구문 부분 지원)
  2. 핵심 기능 미지원 (ORDER BY, LIMIT, 집계 함수)
  3. 프로덕션 안정성 불확실
  4. 기존 SQL도 충분히 작동 중

현재 상황 분석

우리 프로젝트의 그래프 복잡도

현재 그래프 규모:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- 노드: ~50개 (약물, 증상, 환자 프로필)
- 엣지: ~200개 (약물-증상, 약물-부작용 관계)
- 최대 경로 깊이: 2-3 hop

→ 이 정도 규모에서는 SQL JOIN도 충분히 빠름!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

기존 SQL 쿼리 성능

# 2-hop 경로 탐색 (Statin → CoQ10 → Myopathy)
# 현재 SQL 쿼리 시간: ~10ms ✅

SELECT
    e1.name, r1.predicate, e2.name, r2.predicate, e3.name
FROM relationships r1
JOIN entities e1 ON r1.subject_id = e1.id
JOIN entities e2 ON r1.object_id = e2.id
JOIN relationships r2 ON r2.subject_id = e2.id
JOIN entities e3 ON r2.object_id = e3.id
WHERE e1.name = 'Statin' AND e3.name = 'Myopathy';

-- 실행 시간: 8-12ms (50 노드, 200 엣지 기준)
-- 충분히 빠름! 🚀

🔬 SQLite-Graph가 필요한 경우

시나리오 1: 그래프 규모가 클 때

대규모 그래프:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- 노드: 10,000개 이상
- 엣지: 100,000개 이상
- 최대 경로 깊이: 5-10 hop

→ 이 경우 SQL JOIN 성능 저하 (재귀 CTE 느림)
→ SQLite-Graph의 그래프 최적화 필요
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

시나리오 2: 복잡한 경로 쿼리가 많을 때

-- 예시: 모든 가능한 경로 탐색
MATCH path = (drug)-[*1..5]->(symptom)
WHERE drug.type = 'NSAID'
RETURN path;

-- SQL로 구현: 재귀 CTE 사용, 매우 복잡
WITH RECURSIVE paths AS (
    SELECT id, name, 1 AS depth, CAST(name AS TEXT) AS path
    FROM entities
    WHERE type = 'Drug'
    UNION ALL
    SELECT e.id, e.name, p.depth + 1, p.path || ' -> ' || e.name
    FROM paths p
    JOIN relationships r ON p.id = r.subject_id
    JOIN entities e ON r.object_id = e.id
    WHERE p.depth < 5
)
SELECT * FROM paths WHERE name = 'symptom';

-- 복잡도: ⭐⭐⭐⭐⭐ (이해하기 어려움)
-- vs Cypher: ⭐ (매우 간단)

📊 비교표: 우리 프로젝트 기준

┌─────────────────────────┬─────────────────┬─────────────────┐
│      평가 항목          │  기존 SQL       │ SQLite-Graph    │
├─────────────────────────┼─────────────────┼─────────────────┤
│ 현재 그래프 규모        │  ✅ 충분        │  ✅ 충분        │
│ 성능 (50 노드, 200 엣지)│  ✅ ~10ms       │  ✅ ~5-10ms     │
│ 배포 난이도             │  ✅ 매우 쉬움   │  ⚠️ 확장 필요   │
│ 안정성                  │  ✅ 검증됨      │  ⚠️ 초기 버전   │
│ 팀원 학습 곡선          │  ✅ SQL 익숙    │  ⚠️ Cypher 학습 │
│ 쿼리 가독성 (2-hop)     │  ⭐⭐          │  ⭐⭐⭐⭐⭐     │
│ 쿼리 가독성 (N-hop)     │  ⭐             │  ⭐⭐⭐⭐⭐     │
│ ORDER BY / LIMIT        │  ✅ 지원        │  ❌ 미지원 가능 │
│ 집계 함수               │  ✅ 지원        │  ❌ 미지원 가능 │
│ 그래프 알고리즘         │  ❌ 수동 구현   │  ✅ 내장        │
└─────────────────────────┴─────────────────┴─────────────────┘

【종합 점수】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
기존 SQL:         ★★★★☆ (4.0/5.0)
SQLite-Graph:     ★★★☆☆ (3.0/5.0)  ← 아직 초기 버전

【결론】
현재 시점에서는 기존 SQL 유지 권장
6개월~1년 후 SQLite-Graph 성숙도 재평가

🎯 권장 전략: 하이브리드 접근

1단계: 현재 (기존 SQL 유지)

# backend/graph_query.py
class GraphQuery:
    """기존 SQL 기반 그래프 쿼리"""

    def find_path(self, start, end, max_depth=3):
        """2-3 hop 경로 탐색"""
        # SQL로 구현 (현재 코드 유지)
        pass

    def recommend_drug(self, patient_profile, symptom):
        """약물 추천"""
        # SQL로 구현 (현재 코드 유지)
        pass

장점:

  • 안정적
  • 배포 쉬움
  • 충분한 성능

2단계: 6개월 후 (SQLite-Graph 재평가)

평가 항목:

1. Cypher 구문 지원 확대 여부
   - ORDER BY, LIMIT 지원?
   - 집계 함수 지원?
   - OPTIONAL MATCH 지원?

2. 커뮤니티 성숙도
   - GitHub Stars 증가?
   - 이슈 해결 속도?
   - 프로덕션 사용 사례?

3. 우리 그래프 규모 증가
   - 노드 1,000개 이상?
   - 복잡한 N-hop 쿼리 필요?

조건 충족 시 마이그레이션:

# backend/graph_query_v2.py (SQLite-Graph 버전)
class GraphQueryV2:
    """Cypher 기반 그래프 쿼리"""

    def find_path_cypher(self, start, end):
        """Cypher로 경로 탐색"""
        cypher = f"""
        MATCH path = (a {{name: '{start}'}})-[*1..5]->(b {{name: '{end}'}})
        RETURN path
        ORDER BY length(path)
        LIMIT 1
        """
        # 실행...

3단계: 장기 (Neo4j 검토)

만약 그래프가 매우 커진다면 (노드 10,000개+):

SQLite-Graph도 한계 → Neo4j 전환 검토

Neo4j 장점:
- 대규모 그래프 최적화
- 완전한 Cypher 지원
- 분산 처리 가능
- Graph Data Science 라이브러리

Neo4j 단점:
- 별도 서버 필요 (배포 복잡)
- 비용 (엔터프라이즈)
- SQLite보다 무거움

🛠️ 실용적인 팁: SQL을 Cypher처럼 사용

현재 SQL을 더 읽기 쉽게 만들기

# backend/graph_utils.py

def build_path_query(start_entity, end_entity, max_hops=3):
    """
    경로 탐색 SQL을 자동 생성
    (Cypher처럼 간단하게 호출)
    """
    # 2-hop
    if max_hops == 2:
        return f"""
        SELECT
            e1.name AS start,
            r1.predicate AS rel1,
            e2.name AS middle,
            r2.predicate AS rel2,
            e3.name AS end
        FROM relationships r1
        JOIN entities e1 ON r1.subject_id = e1.id
        JOIN entities e2 ON r1.object_id = e2.id
        JOIN relationships r2 ON r2.subject_id = e2.id
        JOIN entities e3 ON r2.object_id = e3.id
        WHERE e1.name = '{start_entity}' AND e3.name = '{end_entity}'
        """

    # 3-hop (재귀 CTE)
    elif max_hops == 3:
        return f"""
        WITH RECURSIVE paths AS (
            -- 시작 노드
            SELECT
                e.id,
                e.name,
                1 AS depth,
                e.name AS path
            FROM entities e
            WHERE e.name = '{start_entity}'

            UNION ALL

            -- 재귀: 다음 노드 탐색
            SELECT
                e.id,
                e.name,
                p.depth + 1,
                p.path || ' -> ' || e.name
            FROM paths p
            JOIN relationships r ON p.id = r.subject_id
            JOIN entities e ON r.object_id = e.id
            WHERE p.depth < {max_hops}
        )
        SELECT * FROM paths WHERE name = '{end_entity}'
        """


# 사용 (Cypher처럼 간단)
query = build_path_query('Statin', 'Myopathy', max_hops=2)
results = cursor.execute(query).fetchall()

📌 최종 권장사항

지금 당장: 기존 SQL 유지

이유:

  1. 현재 그래프 규모에서 충분히 빠름 (10ms 미만)
  2. 안정적이고 검증됨
  3. 배포 간단 (확장 설치 불필요)
  4. SQLite-Graph 아직 초기 버전

개선 방안:

  • SQL 쿼리를 헬퍼 함수로 감싸서 가독성 향상
  • 자주 사용하는 쿼리 VIEW로 저장
  • 성능 병목 발생 시에만 최적화

🔮 6개월 후: SQLite-Graph 재평가

체크리스트:

□ SQLite-Graph가 ORDER BY/LIMIT 지원?
□ 집계 함수 (COUNT, AVG) 지원?
□ GitHub Stars 1,000+ (커뮤니티 활성화)?
□ 프로덕션 사용 사례 3개 이상?
□ 우리 그래프 노드 500개 이상?
□ 복잡한 N-hop 쿼리 빈번?

→ 3개 이상 ✅ → 마이그레이션 고려

📚 장기: Neo4j 검토 (선택사항)

조건:

□ 노드 10,000개 이상
□ 복잡한 그래프 알고리즘 필요 (PageRank, 커뮤니티 탐지)
□ 실시간 그래프 분석 필요
□ 분산 처리 필요

→ 모두 ✅ → Neo4j 도입

🎯 요약

┌─────────────────────────────────────────────────────────┐
│         현재 시점 (2026-01-24) 최적 선택:              │
│                                                         │
│              기존 SQL 유지 ✅                            │
│                                                         │
│  이유:                                                  │
│  - SQLite-Graph 아직 초기 버전                          │
│  - 핵심 기능 미지원 (ORDER BY, LIMIT)                   │
│  - 현재 그래프 규모에서 SQL 충분히 빠름                 │
│  - 프로덕션 안정성 중요                                 │
│                                                         │
│  재평가 시점: 2026년 7-8월                              │
└─────────────────────────────────────────────────────────┘

🔗 참고 링크


작성: 2026-01-24 재평가 예정: 2026-07-24