pharmacy-pos-qr-system/docs/opensource-graph-db-comparison.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

658 lines
20 KiB
Markdown

# 오픈소스 그래프 DB 비교 및 추천
> Neo4j 대신 사용할 수 있는 오픈소스 그래프 데이터베이스 옵션
**작성일**: 2026-01-24
**대상 프로젝트**: 약국 POS QR 시스템 (PubMed GraphRAG)
---
## 🎯 평가 기준
우리 프로젝트에 필요한 조건:
```
✅ 완전한 오픈소스 (상업적 제약 없음)
✅ Cypher 또는 유사 쿼리 언어 지원
✅ Python 통합 용이
✅ 배포 간편 (별도 서버 최소화)
✅ SQLite/PostgreSQL 같은 익숙한 DB와 통합
✅ 중소 규모 그래프 최적화 (1,000~10,000 노드)
```
---
## 📊 오픈소스 그래프 DB 비교
### 1. **Apache AGE** ⭐⭐⭐⭐⭐ 최고 추천!
```
┌─────────────────────────────────────────────────────────┐
│ PostgreSQL + 그래프 = Apache AGE │
│ "기존 PostgreSQL에 그래프 기능 추가" │
└─────────────────────────────────────────────────────────┘
```
#### 🌟 핵심 특징
- **PostgreSQL 확장** (익숙한 DB + 그래프 기능)
- **Cypher 쿼리 완벽 지원** (Neo4j와 동일)
- **SQL + Cypher 혼합 사용 가능**
- **Apache 2.0 라이선스** (완전 오픈소스)
- **기존 PostgreSQL 데이터와 그래프 결합 가능**
#### ✅ 장점
```python
# SQL과 Cypher를 함께 사용!
# 기존 테이블 (users, products)
SELECT * FROM users WHERE age > 30;
# 그래프 쿼리 (관계 탐색)
SELECT * FROM cypher('graph_name', $$
MATCH (u:User)-[:PURCHASED]->(p:Product)
WHERE u.age > 30
RETURN u.name, p.name
$$) AS (user_name text, product_name text);
```
#### ⚠️ 단점
- PostgreSQL 필요 (SQLite보다 무거움)
- 비교적 신생 프로젝트 (2020년 시작)
#### 📦 설치 (Ubuntu/Debian 예시)
```bash
# PostgreSQL 설치
sudo apt-get install postgresql-14
# Apache AGE 설치
sudo apt-get install postgresql-14-age
# 확장 활성화
CREATE EXTENSION age;
```
#### 🐍 Python 사용
```python
import psycopg2
from age import Age
conn = psycopg2.connect(
host="localhost",
database="pharmacy_db",
user="postgres"
)
cursor = conn.cursor()
# 그래프 생성
cursor.execute("""
SELECT create_graph('pharmacy_graph');
""")
# Cypher 쿼리
cursor.execute("""
SELECT * FROM cypher('pharmacy_graph', $$
CREATE (n:Drug {name: 'Naproxen', type: 'NSAID'})
RETURN n
$$) AS (drug agtype);
""")
# 경로 탐색
cursor.execute("""
SELECT * FROM cypher('pharmacy_graph', $$
MATCH path = (d:Drug {name: 'Statin'})-[*1..3]->(s:Symptom)
RETURN path
$$) AS (path agtype);
""")
```
#### 🎯 우리 프로젝트 적용
```
현재: SQLite (mileage.db)
마이그레이션: PostgreSQL + Apache AGE
장점:
- 기존 users, transactions 테이블 유지 (SQL)
- 약물-증상 관계는 그래프 (Cypher)
- 한 DB에서 모두 처리 ✨
```
---
### 2. **Memgraph** ⭐⭐⭐⭐
```
┌─────────────────────────────────────────────────────────┐
│ 빠른 인메모리 그래프 DB │
│ "Neo4j와 호환되는 Cypher 지원" │
└─────────────────────────────────────────────────────────┘
```
#### 🌟 핵심 특징
- **완전한 Cypher 지원** (Neo4j 호환)
- **인메모리 처리** (매우 빠름)
- **스트림 처리 지원** (Kafka 통합)
- **BSL 라이선스** (Community Edition 무료)
#### ✅ 장점
- Neo4j보다 빠름 (인메모리)
- 완전한 Cypher 지원 (학습 곡선 낮음)
- Python 라이브러리 우수
#### ⚠️ 단점
- 별도 서버 필요
- 인메모리 → 메모리 많이 필요
- 데이터 영속성 설정 필요
#### 🐍 Python 사용
```python
from gqlalchemy import Memgraph
memgraph = Memgraph(host='127.0.0.1', port=7687)
# Cypher 쿼리 (Neo4j와 동일)
results = memgraph.execute_and_fetch("""
MATCH (d:Drug {name: 'Naproxen'})-[:SAFER_THAN]->(other:Drug)
RETURN d.name, other.name
""")
for result in results:
print(result['d.name'], result['other.name'])
```
---
### 3. **ArangoDB** ⭐⭐⭐⭐
```
┌─────────────────────────────────────────────────────────┐
│ 멀티모델 DB (문서 + 그래프 + 키-밸류) │
│ "하나의 DB로 모든 데이터 모델 지원" │
└─────────────────────────────────────────────────────────┘
```
#### 🌟 핵심 특징
- **멀티모델**: 문서(JSON) + 그래프 + 키-밸류
- **AQL 쿼리 언어** (Cypher와 유사, 더 강력)
- **완전 오픈소스** (Apache 2.0)
- **Python, JavaScript 등 다양한 드라이버**
#### ✅ 장점
- 유연함 (그래프 + JSON 문서 모두 저장)
- 성능 우수
- 웹 UI 기본 제공
#### ⚠️ 단점
- Cypher 아님 (AQL 학습 필요)
- 별도 서버 필요
- 설정 복잡할 수 있음
#### 🐍 Python 사용
```python
from arango import ArangoClient
client = ArangoClient(hosts='http://localhost:8529')
db = client.db('pharmacy_db', username='root', password='password')
# 그래프 생성
graph = db.create_graph('pharmacy_graph')
# 문서 + 그래프 혼합 (강력!)
result = db.aql.execute("""
FOR drug IN drugs
FILTER drug.type == 'NSAID'
FOR vertex, edge, path IN 1..3 OUTBOUND drug GRAPH 'pharmacy_graph'
FILTER vertex._id == 'symptoms/pain'
RETURN path
""")
```
---
### 4. **Dgraph** ⭐⭐⭐
```
┌─────────────────────────────────────────────────────────┐
│ GraphQL 네이티브 그래프 DB │
│ "GraphQL로 그래프 쿼리" │
└─────────────────────────────────────────────────────────┘
```
#### 🌟 핵심 특징
- **GraphQL 쿼리 언어** (Cypher 대신)
- **Go로 작성** (빠르고 가벼움)
- **분산 처리 지원**
- **Apache 2.0 라이선스**
#### ✅ 장점
- GraphQL 사용 시 최적
- 성능 우수
- 분산 확장 용이
#### ⚠️ 단점
- Cypher 미지원 (GraphQL 학습 필요)
- 별도 서버 필요
- 커뮤니티 Neo4j보다 작음
---
### 5. **JanusGraph** ⭐⭐⭐
```
┌─────────────────────────────────────────────────────────┐
│ Apache 재단 대규모 그래프 DB │
│ "수억 개 노드 지원" │
└─────────────────────────────────────────────────────────┘
```
#### 🌟 핵심 특징
- **Apache 재단 공식 프로젝트**
- **대규모 그래프 최적화** (수십억 엣지)
- **Gremlin 쿼리 언어** (Cypher 아님)
- **다양한 백엔드 지원** (Cassandra, HBase 등)
#### ✅ 장점
- 대규모 그래프에 최적
- Apache 재단 신뢰성
- 엔터프라이즈급 기능
#### ⚠️ 단점
- **우리 프로젝트에 과함** (중소 규모용 아님)
- 설정 매우 복잡
- Gremlin 학습 곡선 높음
---
### 6. **Nebula Graph** ⭐⭐⭐
```
┌─────────────────────────────────────────────────────────┐
│ 분산 그래프 DB │
│ "중국발 오픈소스, 빠른 성능" │
└─────────────────────────────────────────────────────────┘
```
#### 🌟 핵심 특징
- **nGQL** (Cypher와 유사)
- **분산 아키텍처**
- **Apache 2.0 라이선스**
#### ⚠️ 단점
- 별도 서버 (Meta, Graph, Storage)
- 설정 복잡
- 커뮤니티 주로 중국어
---
## 🏆 종합 비교표
```
┌─────────────┬──────────┬──────────┬──────────┬──────────┬──────────┐
│ 항목 │ AGE │ Memgraph │ ArangoDB │ Dgraph │ JanusGrph│
├─────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ 쿼리 언어 │ Cypher │ Cypher │ AQL │ GraphQL │ Gremlin │
├─────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ 배포 난이도 │ ⭐⭐ │ ⭐⭐⭐ │ ⭐⭐⭐ │ ⭐⭐⭐ │ ⭐⭐⭐⭐⭐│
├─────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ 학습 곡선 │ ⭐ │ ⭐ │ ⭐⭐ │ ⭐⭐ │ ⭐⭐⭐⭐ │
├─────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ 성능 │ ⭐⭐⭐⭐ │ ⭐⭐⭐⭐⭐│ ⭐⭐⭐⭐ │ ⭐⭐⭐⭐ │ ⭐⭐⭐⭐⭐│
├─────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ SQL 통합 │ ✅ │ ❌ │ ❌ │ ❌ │ ❌ │
├─────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ 중소규모 적합│ ✅ │ ✅ │ ✅ │ ⭐⭐ │ ❌ │
├─────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ 라이선스 │ Apache │ BSL │ Apache │ Apache │ Apache │
├─────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ 우리적합도 │⭐⭐⭐⭐⭐│ ⭐⭐⭐⭐ │ ⭐⭐⭐ │ ⭐⭐ │ ⭐ │
└─────────────┴──────────┴──────────┴──────────┴──────────┴──────────┘
⭐ 적음/쉬움/낮음 = 좋음
⭐⭐⭐⭐⭐ 많음/어려움/높음 = 나쁨 (배포, 학습 곡선)
⭐⭐⭐⭐⭐ 많음 = 좋음 (성능, 적합도)
```
---
## 🎯 우리 프로젝트 최적 선택
### 🥇 1순위: **Apache AGE**
#### 선택 이유
```
✅ PostgreSQL 확장 (익숙한 환경)
✅ SQL + Cypher 혼합 사용 (마이그레이션 쉬움)
✅ 기존 데이터 + 그래프 한 DB에서 관리
✅ 완전 오픈소스 (Apache 2.0)
✅ 배포 간단 (PostgreSQL만 있으면 됨)
```
#### 마이그레이션 경로
```
현재: SQLite
1단계: PostgreSQL + 기본 테이블 마이그레이션
2단계: Apache AGE 확장 설치
3단계: 그래프 노드/엣지 생성
결과: SQL (users, transactions) + Cypher (약물 관계)
```
---
### 🥈 2순위: **Memgraph**
#### 선택 이유
```
✅ 완전한 Cypher 지원 (Neo4j 호환)
✅ 매우 빠름 (인메모리)
✅ Python 라이브러리 우수
```
#### 적합한 경우
```
- 실시간 추천이 매우 중요
- 메모리 충분히 있음
- 별도 서버 운영 가능
```
---
### 🥉 3순위: **ArangoDB**
#### 선택 이유
```
✅ 멀티모델 (유연함)
✅ 성능 우수
✅ 웹 UI 좋음
```
#### 적합한 경우
```
- JSON 문서 + 그래프 모두 필요
- AQL 학습 가능
- 다양한 데이터 모델 실험
```
---
## 🛠️ Apache AGE 실전 적용 가이드
### 1. 설치 (Docker 사용)
```bash
# Docker Compose 설정
# docker-compose.yml
version: '3.8'
services:
postgres-age:
image: apache/age:latest
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: pharmacy_db
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
```
```bash
# 실행
docker-compose up -d
```
### 2. Python 통합
```python
"""
Apache AGE + Python 예시
"""
import psycopg2
from age import Age
# 연결
conn = psycopg2.connect(
host="localhost",
database="pharmacy_db",
user="postgres",
password="password"
)
age = Age(conn)
cursor = conn.cursor()
# 1. 그래프 생성
age.setGraph('pharmacy_graph')
cursor.execute("SELECT create_graph('pharmacy_graph');")
# 2. 노드 생성 (Cypher)
cursor.execute("""
SELECT * FROM cypher('pharmacy_graph', $$
CREATE (statin:Drug {name: 'Statin', type: 'HMG-CoA inhibitor'}),
(coq10:Drug {name: 'CoQ10', type: 'Supplement'}),
(myopathy:Condition {name: 'Myopathy'}),
(evidence:Evidence {pmid: '30371340', reliability: 0.95})
RETURN statin, coq10, myopathy, evidence
$$) AS (statin agtype, coq10 agtype, myopathy agtype, evidence agtype);
""")
# 3. 관계 생성
cursor.execute("""
SELECT * FROM cypher('pharmacy_graph', $$
MATCH (statin:Drug {name: 'Statin'}),
(coq10:Drug {name: 'CoQ10'}),
(myopathy:Condition {name: 'Myopathy'}),
(evidence:Evidence {pmid: '30371340'})
CREATE (statin)-[:INHIBITS {mechanism: 'HMG-CoA pathway'}]->(coq10),
(coq10)-[:REDUCES {effect_size: -1.60, p_value: 0.001}]->(myopathy),
(evidence)-[:SUPPORTS]->(coq10)-[:REDUCES]->(myopathy)
RETURN statin, coq10, myopathy
$$) AS (statin agtype, coq10 agtype, myopathy agtype);
""")
# 4. 경로 탐색 (GraphRAG!)
cursor.execute("""
SELECT * FROM cypher('pharmacy_graph', $$
MATCH path = (statin:Drug {name: 'Statin'})-[*1..3]->(myopathy:Condition {name: 'Myopathy'})
RETURN path
$$) AS (path agtype);
""")
results = cursor.fetchall()
for row in results:
print(row[0])
# 5. SQL + Cypher 혼합!
cursor.execute("""
-- SQL: 사용자 조회
WITH high_risk_users AS (
SELECT id, name, age
FROM users
WHERE age > 60 AND has_hypertension = true
)
-- Cypher: 안전한 약물 추천
SELECT u.name, drug_name
FROM high_risk_users u,
LATERAL (
SELECT * FROM cypher('pharmacy_graph', $$
MATCH (drug:Drug)-[:SAFE_FOR]->(profile:PatientProfile {name: 'Elderly_HTN'})
RETURN drug.name
$$) AS (drug_name agtype)
);
""")
conn.commit()
conn.close()
```
### 3. 실제 추천 시스템 예시
```python
"""
Apache AGE 기반 약물 추천 시스템
"""
class DrugRecommender:
def __init__(self, conn):
self.conn = conn
self.cursor = conn.cursor()
def recommend(self, patient_id, symptom):
"""
환자 프로필 + 증상 → 약물 추천 (근거 포함)
"""
# 1. SQL: 환자 정보 조회
self.cursor.execute("""
SELECT age, hypertension, diabetes
FROM users
WHERE id = %s
""", (patient_id,))
patient = self.cursor.fetchone()
age, has_htn, has_dm = patient
# 2. 환자 프로필 결정
if has_htn and has_dm:
profile = 'Patient_HTN_DM'
elif has_htn:
profile = 'Patient_HTN'
elif age > 65:
profile = 'Elderly'
else:
profile = 'General'
# 3. Cypher: 그래프 기반 추천
self.cursor.execute(f"""
SELECT * FROM cypher('pharmacy_graph', $$
MATCH (drug:Drug)-[treats:TREATS]->(condition:Condition {{name: '{symptom}'}})
WHERE NOT (drug)-[:CONTRAINDICATED_IN]->(:PatientProfile {{name: '{profile}'}})
MATCH (evidence:Evidence)-[:SUPPORTS]->(treats)
RETURN
drug.name AS drug,
treats.effect_size AS effect,
evidence.pmid AS pmid,
evidence.reliability AS reliability
ORDER BY evidence.reliability DESC, treats.effect_size DESC
LIMIT 1
$$) AS (drug agtype, effect agtype, pmid agtype, reliability agtype);
""")
result = self.cursor.fetchone()
if result:
return {
'drug': result[0],
'effect_size': result[1],
'evidence_pmid': result[2],
'reliability': result[3],
'patient_profile': profile
}
else:
return None
# 사용 예시
recommender = DrugRecommender(conn)
# 환자 ID 123, 증상 "Pain"
recommendation = recommender.recommend(patient_id=123, symptom='Pain')
print(recommendation)
# {
# 'drug': 'Naproxen',
# 'effect_size': -1.8,
# 'evidence_pmid': '27959716',
# 'reliability': 0.99,
# 'patient_profile': 'Patient_HTN_DM'
# }
```
---
## 📊 마이그레이션 로드맵
### Phase 1: SQLite → PostgreSQL (1주)
```sql
-- 기존 SQLite 테이블 PostgreSQL로 이동
-- users, transactions, mileage_ledger 등
```
### Phase 2: Apache AGE 설치 (1일)
```bash
CREATE EXTENSION age;
SELECT create_graph('pharmacy_graph');
```
### Phase 3: 그래프 데이터 생성 (1주)
```python
# PubMed 논문 → 그래프 트리플
# Cypher CREATE 문으로 노드/엣지 생성
```
### Phase 4: 추천 시스템 업그레이드 (1주)
```python
# SQL + Cypher 혼합 쿼리
# GraphRAG 추론 경로 자동 생성
```
---
## 🎯 최종 권장사항
### ✅ **즉시 도입 가능: Apache AGE**
**선택 이유**:
1. PostgreSQL 확장 (익숙함)
2. SQL + Cypher 모두 사용 가능
3. 기존 데이터 + 그래프 한 DB
4. 완전 오픈소스
5. 마이그레이션 쉬움
**시작 단계**:
```bash
# 1. Docker로 테스트
docker run -p 5432:5432 apache/age
# 2. Python 라이브러리 설치
pip install psycopg2-binary age
# 3. 간단한 그래프 생성 테스트
python test_age.py
```
---
### 🔮 **대안: Memgraph** (성능 최우선 시)
**조건**:
- 별도 서버 운영 가능
- 메모리 충분 (8GB+)
- 실시간 추천 필수
---
## 📚 참고 링크
- **Apache AGE**: https://age.apache.org/
- GitHub: https://github.com/apache/age
- 문서: https://age.apache.org/age-manual/master/index.html
- **Memgraph**: https://memgraph.com/
- 문서: https://memgraph.com/docs
- **ArangoDB**: https://www.arangodb.com/
- 문서: https://www.arangodb.com/docs/
- **Dgraph**: https://dgraph.io/
- GitHub: https://github.com/dgraph-io/dgraph
---
**작성**: 2026-01-24
**추천**: Apache AGE ⭐⭐⭐⭐⭐