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

356 lines
11 KiB
Markdown

# 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 쿼리 성능
```python
# 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: 복잡한 경로 쿼리가 많을 때
```cypher
-- 예시: 모든 가능한 경로 탐색
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 유지)
```python
# 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 쿼리 필요?
```
**조건 충족 시 마이그레이션**:
```python
# 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을 더 읽기 쉽게 만들기
```python
# 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월 │
└─────────────────────────────────────────────────────────┘
```
---
## 🔗 참고 링크
- **SQLite-Graph GitHub**: https://github.com/agentflare-ai/sqlite-graph
- **현재 지원 구문**: CREATE, MATCH, WHERE, RETURN
- **미지원 구문**: ORDER BY, LIMIT, 집계, OPTIONAL MATCH
---
**작성**: 2026-01-24
**재평가 예정**: 2026-07-24