45분
Cypher 기초: 제조 데이터 생성과 조회
Neo4j & Cypher
Cypher 기초: 제조 데이터 생성과 조회
온톨로지 & Knowledge Graph > Neo4j & Cypher
학습 목표
CREATE로 설비/부품/고장 노드를 생성한다 MATCH로 패턴 기반 조회를 수행한다 WHERE, RETURN, ORDER BY를 활용한다 SET, DELETE로 데이터를 수정/삭제한다
Cypher 기초: 제조 데이터로 배우는 그래프 쿼리
Cypher = "ASCII Art 같은 쿼리 언어"
[Cypher의 핵심 아이디어]
노드: ( ) 괄호로 표현
관계: -[ ]-> 화살표로 표현
패턴: (a)-[r]->(b) 노드-관계-노드
SQL이 "테이블과 조인"을 다루듯,
Cypher는 "노드와 관계"를 다룹니다.
1. CREATE - 노드 생성
// 설비 노드 생성
CREATE (e:Equipment {
name: "CNC밀링 3호기",
model: "VMC-850",
manufacturer: "화천기계",
installDate: date("2021-06-15"),
status: "운전중",
operatingHours: 12450,
location: "A동 2라인 3번"
})
RETURN e;
// 부품 노드 생성
CREATE (p:Part {
partNumber: "BRG-6205-2RS",
name: "메인 베어링",
manufacturer: "NSK",
lifespan: 8000,
currentHours: 6500,
cost: 45000
})
RETURN p;
// 고장 노드 생성
CREATE (f:Fault {
alarmCode: "E-201",
name: "스핀들 과열",
severity: "중요",
description: "스핀들 온도가 설정값(80도) 초과",
avgDowntime: 45
})
RETURN f;
여러 노드 한번에 생성
// 루트브릭스 공장 기본 구조 생성
CREATE
// 공장
(factory:Factory {name: "루트브릭스 김포 공장", location: "경기도 김포시"}),
// 생산 라인
(lineA2:ProductionLine {name: "A동 2라인", lineNumber: "A-2", capacity: 500}),
// 설비
(mill3:Equipment {name: "CNC밀링 3호기", model: "VMC-850",
manufacturer: "화천기계", status: "운전중",
operatingHours: 12450}),
(lathe1:Equipment {name: "CNC선반 1호기", model: "LX-500",
manufacturer: "화천기계", status: "운전중",
operatingHours: 18200}),
// 구성요소
(spindleUnit:Component {name: "스핀들 유닛", componentType: "주축"}),
(feedSystem:Component {name: "이송계", componentType: "이송"}),
// 부품
(bearing:Part {name: "메인 베어링", partNumber: "BRG-6205-2RS",
manufacturer: "NSK", lifespan: 8000, currentHours: 6500}),
(spindleMotor:Part {name: "스핀들 모터", partNumber: "MOT-SP-15KW",
manufacturer: "화낙", lifespan: 20000, currentHours: 12450}),
(coolant:Part {name: "냉각 시스템", partNumber: "COOL-SYS-850",
manufacturer: "화천기계", lifespan: 15000, currentHours: 12450}),
(ballscrew:Part {name: "볼스크류(X축)", partNumber: "BS-3210-X",
manufacturer: "THK", lifespan: 12000, currentHours: 12450}),
// 고장
(alarmE201:Fault {alarmCode: "E-201", name: "스핀들 과열",
severity: "중요", avgDowntime: 45}),
(alarmE305:Fault {alarmCode: "E-305", name: "이송 축 위치 오차",
severity: "경고", avgDowntime: 30}),
// 근본 원인
(causeCoolant:RootCause {name: "냉각수 부족", category: "소모품", probability: 0.45}),
(causeBearing:RootCause {name: "베어링 마모", category: "기계적 마모", probability: 0.35}),
(causeOvercut:RootCause {name: "과절삭", category: "가공 조건", probability: 0.20}),
(causeBacklash:RootCause {name: "볼스크류 백래시", category: "기계적 마모", probability: 0.60}),
// 정비 조치
(actionRefill:MaintenanceAction {name: "냉각수 보충", difficulty: "쉬움",
estimatedTime: 15}),
(actionBearing:MaintenanceAction {name: "베어링 교체", difficulty: "어려움",
estimatedTime: 240}),
(actionCutting:MaintenanceAction {name: "절삭 조건 수정", difficulty: "보통",
estimatedTime: 30}),
(actionBallscrew:MaintenanceAction {name: "볼스크류 백래시 보정", difficulty: "어려움",
estimatedTime: 120}),
// 작업자
(workerKim:Worker {name: "김기술", employeeId: "EMP-001", experience: 15}),
(workerLee:Worker {name: "이신입", employeeId: "EMP-042", experience: 1}),
// 스킬
(skillBasic:Skill {name: "기본 정비", level: "초급"}),
(skillCNC:Skill {name: "CNC 프로그래밍", level: "중급"}),
(skillSpindle:Skill {name: "스핀들 정비", level: "고급"}),
(skillPrecision:Skill {name: "정밀 정비", level: "고급"}),
// === 관계 생성 ===
// 공장 구조
(factory)-[:HAS_LINE]->(lineA2),
(lineA2)-[:HAS_EQUIPMENT]->(mill3),
(lineA2)-[:HAS_EQUIPMENT]->(lathe1),
// 설비-구성요소-부품
(mill3)-[:HAS_COMPONENT]->(spindleUnit),
(mill3)-[:HAS_COMPONENT]->(feedSystem),
(spindleUnit)-[:HAS_PART]->(bearing),
(spindleUnit)-[:HAS_PART]->(spindleMotor),
(spindleUnit)-[:HAS_PART]->(coolant),
(feedSystem)-[:HAS_PART]->(ballscrew),
// 부품-고장 연관
(bearing)-[:CAN_CAUSE]->(alarmE201),
(coolant)-[:CAN_CAUSE]->(alarmE201),
(ballscrew)-[:CAN_CAUSE]->(alarmE305),
// 고장-원인
(alarmE201)-[:CAUSED_BY]->(causeCoolant),
(alarmE201)-[:CAUSED_BY]->(causeBearing),
(alarmE201)-[:CAUSED_BY]->(causeOvercut),
(alarmE305)-[:CAUSED_BY]->(causeBacklash),
// 원인-조치
(causeCoolant)-[:RESOLVED_BY]->(actionRefill),
(causeBearing)-[:RESOLVED_BY]->(actionBearing),
(causeOvercut)-[:RESOLVED_BY]->(actionCutting),
(causeBacklash)-[:RESOLVED_BY]->(actionBallscrew),
// 작업자-설비
(workerKim)-[:OPERATES]->(mill3),
(workerLee)-[:OPERATES]->(lathe1),
// 작업자-스킬
(workerKim)-[:HAS_SKILL]->(skillBasic),
(workerKim)-[:HAS_SKILL]->(skillCNC),
(workerKim)-[:HAS_SKILL]->(skillSpindle),
(workerLee)-[:HAS_SKILL]->(skillBasic),
// 조치-필요스킬
(actionRefill)-[:REQUIRES_SKILL]->(skillBasic),
(actionBearing)-[:REQUIRES_SKILL]->(skillSpindle),
(actionCutting)-[:REQUIRES_SKILL]->(skillCNC),
(actionBallscrew)-[:REQUIRES_SKILL]->(skillPrecision);
2. MATCH - 패턴 조회
// 모든 설비 조회
MATCH (e:Equipment)
RETURN e.name, e.model, e.status, e.operatingHours
ORDER BY e.operatingHours DESC;
// 특정 설비의 부품 목록
MATCH (e:Equipment {name: "CNC밀링 3호기"})
-[:HAS_COMPONENT]->(c:Component)
-[:HAS_PART]->(p:Part)
RETURN c.name AS 구성요소, p.name AS 부품, p.manufacturer AS 제조사,
p.currentHours + "/" + p.lifespan AS 사용시간_수명;
// 알람 E-201의 원인과 조치
MATCH (f:Fault {alarmCode: "E-201"})
-[:CAUSED_BY]->(cause:RootCause)
-[:RESOLVED_BY]->(action:MaintenanceAction)
RETURN cause.name AS 원인,
cause.probability AS 확률,
action.name AS 조치,
action.difficulty AS 난이도,
action.estimatedTime + "분" AS 예상시간
ORDER BY cause.probability DESC;
3. 고급 패턴 매칭
// 수명 80% 이상 사용된 부품 (교체 예정)
MATCH (e:Equipment)-[:HAS_COMPONENT]->()-[:HAS_PART]->(p:Part)
WHERE toFloat(p.currentHours) / p.lifespan > 0.8
RETURN e.name AS 설비, p.name AS 부품,
p.currentHours AS 현재시간, p.lifespan AS 수명,
round(toFloat(p.currentHours) / p.lifespan * 100, 1) + "%" AS 사용률
ORDER BY toFloat(p.currentHours) / p.lifespan DESC;
// 특정 작업자가 수행 가능한 정비 조치
MATCH (w:Worker {name: "이신입"})-[:HAS_SKILL]->(s:Skill)
<-[:REQUIRES_SKILL]-(a:MaintenanceAction)
RETURN a.name AS 수행가능조치, a.difficulty AS 난이도,
s.name AS 보유스킬;
// 작업자별 대응 불가능한 고장 파악
MATCH (f:Fault)-[:CAUSED_BY]->()-[:RESOLVED_BY]->(a:MaintenanceAction)
-[:REQUIRES_SKILL]->(s:Skill)
WHERE NOT EXISTS {
MATCH (w:Worker {name: "이신입"})-[:HAS_SKILL]->(s)
}
RETURN DISTINCT f.name AS 대응불가_고장, s.name AS 필요스킬;
4. SET & DELETE - 수정과 삭제
// 설비 상태 변경
MATCH (e:Equipment {name: "CNC밀링 3호기"})
SET e.status = "정비중", e.lastMaintenance = datetime()
RETURN e.name, e.status;
// 운전 시간 업데이트
MATCH (e:Equipment {name: "CNC밀링 3호기"})
SET e.operatingHours = e.operatingHours + 8
RETURN e.name, e.operatingHours;
// 관계 삭제 (노드는 유지)
MATCH (w:Worker {name: "이신입"})-[r:OPERATES]->(e:Equipment)
DELETE r;
// 노드와 관계 모두 삭제
MATCH (n:Skill {name: "임시스킬"})
DETACH DELETE n;
// ⚠️ 전체 데이터 삭제 (주의!)
// MATCH (n) DETACH DELETE n;
5. MERGE - 중복 없이 생성
// 없으면 생성, 있으면 업데이트
MERGE (e:Equipment {name: "CNC밀링 3호기"})
ON CREATE SET e.status = "신규", e.createdAt = datetime()
ON MATCH SET e.lastChecked = datetime()
RETURN e;
// 관계도 MERGE 가능
MATCH (w:Worker {name: "이신입"})
MATCH (e:Equipment {name: "CNC밀링 3호기"})
MERGE (w)-[:OPERATES]->(e);
SQL vs Cypher 비교
| 작업 | SQL | Cypher |
|---|---|---|
| 전체 조회 | SELECT * FROM equipment | MATCH (e:Equipment) RETURN e |
| 조건 조회 | WHERE status = '운전중' | WHERE e.status = "운전중" |
| 조인 (1단계) | JOIN parts ON ... | -[:HAS_PART]-> |
| 조인 (3단계) | JOIN x3 (복잡!) | -[:REL*3]-> (간단!) |
| 경로 탐색 | 불가능 (재귀 CTE 필요) | -[:REL*1..5]-> |
| 생성 | INSERT INTO | CREATE/MERGE |
| 수정 | UPDATE ... SET | SET |
| 삭제 | DELETE FROM | DELETE/DETACH DELETE |
🚀 설치 없이 지금 바로 연습하기
Neo4j를 아직 안 깔았어도 괜찮습니다. AX Academy 내장 Cypher 샌드박스가 있어요.
- 가입·설치 0 — 브라우저에서 바로
MATCH/CREATE/MERGE실행 - 제조 도메인 샘플 그래프(Equipment·Worker·Process) 프리로드 → 위 쿼리를 그대로 복붙해 결과를 그래프로 확인
- 위 5개 절(CREATE/MATCH/SET·DELETE/MERGE)을 손에 익히는 용도
단, 내장 샌드박스는 학습용 간이 엔진입니다. 인덱스·대용량·Python 연동 등 본 프로젝트 작업은 실제 Neo4j(Docker/Aura) 로 진행하세요.
AI로 학습하기 — 꿀팁
🧪설비-부품-고장 Cypher 패턴 심화AI 학습 팁
CREATE와 MATCH의 기초 패턴을 제조 설비-부품-고장 관계에 적용한 실습 쿼리를 AI에게 요청하세요.
Neo4j Cypher로 제조 데이터를 다루는 연습 문제 5개를 만들어줘. 조건: (1) Equipment→HAS_PART→Component→CAUSED→Failure 구조, (2) CREATE로 설비/부품/고장 노드 생성, (3) MATCH+WHERE로 특정 설비의 고장 이력 조회, (4) 각 문제에 정답 Cypher와 예상 결과도 포함.
이 팁이 도움이 됐나요?
핵심 포인트
- • Cypher 기본: (노드)-[:관계]->(노드) 패턴으로 조회
- • CREATE로 노드/관계 생성, MATCH로 패턴 조회
- • 가변 길이 관계 탐색(*1..5)이 SQL 대비 압도적으로 간편
- • MERGE는 중복 생성 방지에 유용