스크림트 정리
This commit is contained in:
@@ -16,6 +16,9 @@ RUN apt-get update && apt-get install -y gosu && rm -rf /var/lib/apt/lists/*
|
||||
RUN groupadd -g ${GID} user && \
|
||||
useradd -u ${UID} -g ${GID} -m -s /bin/bash user
|
||||
|
||||
RUN mkdir /data
|
||||
RUN chown user:user /data
|
||||
|
||||
# Copy the entrypoint script and make it executable
|
||||
COPY scripts/entrypoint.sh /usr/local/bin/
|
||||
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||
|
||||
96
GEMINI.md
Normal file
96
GEMINI.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# Memgraph 데이터 모델 설계
|
||||
|
||||
## 1. 프로젝트 목표
|
||||
|
||||
본 프로젝트의 최종 목표는 Job 실행 순서를 최적화하여 전체 공정의 **소요 시간(Duration)**과 **비용(Cost)**을 최소화하는 최적의 **시나리오(Scenario)**를 찾는 것입니다. 이를 위해 Memgraph 데이터베이스에 공정 데이터를 모델링하고, 다양한 분석 쿼리를 실행할 수 있는 기반을 마련합니다.
|
||||
|
||||
## 2. 데이터 모델 (Graph Schema)
|
||||
|
||||
### 2.1. 노드 (Nodes)
|
||||
|
||||
| 노드 레이블 | 설명 | 주요 속성 (Properties) |
|
||||
| ---------------- | -------------------------------------------------------------------- | ---------------------------------------------------- |
|
||||
| `Job` | 실행되어야 할 개별 작업 단위. `JobType`의 인스턴스. | `id`, `name`, `description`, `duration`, `cost` |
|
||||
| `JobType` | `Job`의 유형을 정의하는 템플릿. (예: '용접', '조립', '검사') | `type_id`, `name` |
|
||||
| `Object` | `Job` 수행에 사용되거나 `Job`의 결과로 나오는 객체. `ObjectType`의 인스턴스. | `id`, `name`, `unit_price`, `quantity` |
|
||||
| `ObjectType` | `Object`의 유형을 정의하는 템플릿. (예: '부품A', '반제품B') | `type_id`, `name` |
|
||||
| `Activity` | `Job`과 `Object` 간의 n:m 관계를 연결하는 중간 노드. | `id`, `name`, `description` |
|
||||
| `Status` | `Job`, `Object`, `Activity`의 현재 상태. (예: '대기', '진행중', '완료') | `status_id`, `name` |
|
||||
| `Scenario` | 특정 순서로 배열된 `Job`들의 집합. 다른 `Scenario`로부터 파생될 수 있음. | `id`, `name`, `description`, `total_duration`, `total_cost` |
|
||||
|
||||
### 2.2. 관계 (Relationships)
|
||||
|
||||
| 관계 타입 | 시작 노드 | 끝 노드 | 설명 |
|
||||
| -------------- | ---------------- | ---------------- | ----------------------------------------------------------------- |
|
||||
| `IS_A` | `Job` | `JobType` | `Job`이 어떤 `JobType`에 속하는지 정의 (상속) |
|
||||
| `IS_A` | `Object` | `ObjectType` | `Object`가 어떤 `ObjectType`에 속하는지 정의 (상속) |
|
||||
| `PRECEDES` | `Job` (선행) | `Job` (후행) | `Job` 실행의 선후 관계 정의 (A -[:PRECEDES]-> B: A가 B보다 먼저) |
|
||||
| `INCLUDES` | `Scenario` | `Job` | `Scenario`에 어떤 `Job`들이 포함되는지 정의 |
|
||||
| `PERFORMS` | `Job` | `Activity` | `Job`이 어떤 `Activity`를 수행하는지 연결 |
|
||||
| `ACTS_ON` | `Activity` | `Object` | `Activity`가 어떤 `Object`에 영향을 주는지 연결 |
|
||||
| `HAS_STATUS` | `Job`, `Object`, `Activity` | `Status` | 각 노드의 현재 상태를 나타냄 |
|
||||
| `DELTA_FROM` | `Scenario` (파생) | `Scenario` (기반) | `Scenario`가 어떤 기반 `Scenario`로부터의 증분으로 정의되는지 표시 |
|
||||
|
||||
### 3. 스키마 다이어그램 (Mermaid)
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "Core Entities"
|
||||
J1(Job 1)
|
||||
J2(Job 2)
|
||||
A1(Activity)
|
||||
O1(Object)
|
||||
end
|
||||
|
||||
subgraph "Types & Status"
|
||||
JT(JobType)
|
||||
OT(ObjectType)
|
||||
ST(Status)
|
||||
end
|
||||
|
||||
subgraph "Scenario"
|
||||
S1(Scenario Base)
|
||||
S2(Scenario Delta)
|
||||
end
|
||||
|
||||
J1 -- IS_A --> JT
|
||||
J1 -- PRECEDES --> J2
|
||||
O1 -- IS_A --> OT
|
||||
|
||||
J1 -- PERFORMS --> A1
|
||||
A1 -- ACTS_ON --> O1
|
||||
|
||||
J1 -- HAS_STATUS --> ST
|
||||
O1 -- HAS_STATUS --> ST
|
||||
A1 -- HAS_STATUS --> ST
|
||||
|
||||
S2 -- INCLUDES --> J1
|
||||
S2 -- INCLUDES --> J2
|
||||
S2 -- DELTA_FROM --> S1
|
||||
```
|
||||
|
||||
### 4. 주요 Cypher 쿼리 예시
|
||||
|
||||
- **특정 Job의 모든 선행 Job 찾기:**
|
||||
```cypher
|
||||
MATCH (j:Job {id: 'target_job_id'})<-[:PRECEDES*]-(predecessor)
|
||||
RETURN predecessor;
|
||||
```
|
||||
|
||||
- **특정 시나리오의 총 예상 소요 시간 및 비용 계산:**
|
||||
```cypher
|
||||
MATCH (s:Scenario {id: 'scenario_id'})-[:INCLUDES]->(j:Job)
|
||||
RETURN s.name, sum(j.duration) AS total_duration, sum(j.cost) AS total_cost;
|
||||
```
|
||||
|
||||
- **Critical Path 찾기 (가장 오래 걸리는 Job 경로):**
|
||||
```cypher
|
||||
MATCH path = (start:Job)-[:PRECEDES*]->(end:Job)
|
||||
WHERE NOT EXISTS ((start)<-[:PRECEDES]-()) AND NOT EXISTS ((end)-[:PRECEDES]->())
|
||||
WITH nodes(path) AS jobs_in_path
|
||||
UNWIND jobs_in_path AS job
|
||||
WITH path, sum(job.duration) AS path_duration
|
||||
RETURN path, path_duration
|
||||
ORDER BY path_duration DESC
|
||||
LIMIT 1;
|
||||
```
|
||||
42
README.md
Normal file
42
README.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Memgraph 기반 공정 최적화 PoC
|
||||
|
||||
## 1. 프로젝트 개요
|
||||
|
||||
본 프로젝트는 Memgraph 그래프 데이터베이스를 활용하여 복잡한 공정(Job)들의 실행 순서를 최적화하는 방안을 탐색하기 위한 기술 검증(Proof of Concept) 프로젝트입니다.
|
||||
|
||||
Job, Object, Activity, Scenario 등의 핵심 요소를 그래프 모델로 설계하고, 각 요소 간의 관계를 정의하여 전체 공정의 소요 시간과 비용을 최소화하는 최적의 시나리오를 찾는 것을 목표로 합니다.
|
||||
|
||||
## 2. 데이터 모델
|
||||
|
||||
프로젝트에서 사용하는 데이터 모델의 상세한 노드, 관계, 속성 정의는 아래 설계 문서를 참고하십시오.
|
||||
|
||||
- **[상세 데이터 모델 설계](./GEMINI.md)**
|
||||
|
||||
## 3. 시작하기
|
||||
|
||||
### 요구사항
|
||||
|
||||
- Docker
|
||||
- Docker Compose
|
||||
|
||||
### 실행
|
||||
|
||||
1. **Docker 컨테이너 실행:**
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
2. **Memgraph Lab 접속:**
|
||||
- 웹 브라우저에서 `http://172.16.10.191:3000/` 에 접속하여 Memgraph Lab을 통해 데이터를 시각화하고 쿼리를 실행할 수 있습니다.
|
||||
|
||||
3. **데이터 임포트:**
|
||||
- `cypher_scripts/import_generated_data.cypher` 등의 스크립트를 사용하여 `data/` 디렉토리의 CSV 파일들을 Memgraph로 임포트할 수 있습니다.
|
||||
- memgraph-lab의 import 메뉴 http://172.16.10.191:3000/lab/query?component=import 를 통해 업로드할 수 있습니다.
|
||||
|
||||
## 4. 디렉토리 구조
|
||||
|
||||
- `conf/`: Memgraph 설정 파일
|
||||
- `cypher_scripts/`: 데이터 임포트 및 분석을 위한 Cypher 쿼리 스크립트
|
||||
- `data/`: CSV 형태의 샘플 데이터
|
||||
- `docs/`: 프로젝트 관련 문서
|
||||
- `scripts/`: Docker entrypoint 등 쉘 스크립트
|
||||
50
cypher_scripts/create_scenario_SCN04.cypher
Normal file
50
cypher_scripts/create_scenario_SCN04.cypher
Normal file
@@ -0,0 +1,50 @@
|
||||
// 새로운 시나리오 'SCN04' 생성 및 순서 변경
|
||||
|
||||
// 1. 새로운 시나리오 'SCN04' 노드 생성 (SCN01 기반)
|
||||
CREATE (s4:Scenario {id: 'SCN04', name: 'SCN01 순서 변경 시나리오', description: 'SCN01에서 Job 2와 Job 1의 순서를 변경'});
|
||||
|
||||
// 2. SCN01에 포함된 Job들을 SCN04에도 INCLUDES 관계로 연결합니다.
|
||||
MATCH (s1:Scenario {id: 'SCN01'})-[r:INCLUDES]->(j:Job)
|
||||
WITH s1, j
|
||||
MATCH (s4:Scenario {id: 'SCN04'})
|
||||
CREATE (s4)-[:INCLUDES]->(j);
|
||||
|
||||
// 3. SCN01의 순서를 기반으로 SCN04의 초기 순서를 복제합니다.
|
||||
// - STARTS_WITH 관계 복제
|
||||
MATCH (s1:Scenario {id: 'SCN01'})-[sw:STARTS_WITH]->(start_job:Job)
|
||||
WITH s1, start_job
|
||||
MATCH (s4:Scenario {id: 'SCN04'})
|
||||
CREATE (s4)-[:STARTS_WITH]->(start_job);
|
||||
|
||||
// - NEXT 관계망 복제 (SCN04 시나리오에 종속된 NEXT 관계 생성)
|
||||
MATCH (s1:Scenario {id: 'SCN01'})-[:STARTS_WITH]->(start_job:Job)
|
||||
MATCH path = (start_job)-[:NEXT*]->(end_job:Job)
|
||||
WHERE NOT (end_job)-[:NEXT]->()
|
||||
WITH nodes(path) AS jobs
|
||||
UNWIND range(0, size(jobs)-2) AS i
|
||||
WITH jobs[i] AS from_job, jobs[i+1] AS to_job
|
||||
MATCH (s4:Scenario {id: 'SCN04'})
|
||||
// MERGE를 사용하여 SCN04의 Job들을 가져와서 NEXT 관계 생성
|
||||
MERGE (j1:Job {id: from_job.id})
|
||||
MERGE (j2:Job {id: to_job.id})
|
||||
CREATE (j1)-[:NEXT {scenario: 'SCN04'}]->(j2);
|
||||
|
||||
|
||||
// 4. SCN04에서 Job 1과 Job 2의 순서를 변경합니다. (기존 1->2->3 ... 을 2->1->3 ... 으로)
|
||||
// - 기존 관계 삭제: (s4)-[sw:STARTS_WITH]->(j1), (j1)-[n1:NEXT {scenario: 'SCN04'}]->(j2)
|
||||
MATCH (s4:Scenario {id: 'SCN04'})-[sw:STARTS_WITH]->(j1:Job {id: '1'})
|
||||
DELETE sw;
|
||||
|
||||
MATCH (j1:Job {id: '1'})-[n1:NEXT {scenario: 'SCN04'}]->(j2:Job {id: '2'})
|
||||
DELETE n1;
|
||||
|
||||
MATCH (j2:Job {id: '2'})-[n2:NEXT {scenario: 'SCN04'}]->(j3:Job {id: '3'})
|
||||
DELETE n2;
|
||||
|
||||
// - 새로운 관계 생성: (s4)-[:STARTS_WITH]->(j2), (j2)-[:NEXT]->(j1), (j1)-[:NEXT]->(j3)
|
||||
MATCH (s4:Scenario {id: 'SCN04'}), (j1:Job {id: '1'}), (j2:Job {id: '2'}), (j3:Job {id: '3'})
|
||||
CREATE (s4)-[:STARTS_WITH]->(j2),
|
||||
(j2)-[:NEXT {scenario: 'SCN04'}]->(j1),
|
||||
(j1)-[:NEXT {scenario: 'SCN04'}]->(j3);
|
||||
|
||||
RETURN "SCN04가 성공적으로 생성되었습니다.";
|
||||
13
cypher_scripts/create_schema.cypher
Normal file
13
cypher_scripts/create_schema.cypher
Normal file
@@ -0,0 +1,13 @@
|
||||
// Memgraph 데이터 모델 스키마 정의 (인덱스 및 제약 조건)
|
||||
// 이 스크립트는 데이터를 로드하지 않고, 노드 타입별로 고유 키 제약 조건만 설정합니다.
|
||||
// UNIQUE 제약 조건은 자동으로 인덱스를 생성합니다.
|
||||
|
||||
CREATE CONSTRAINT ON (j:Job) ASSERT j.id IS UNIQUE;
|
||||
CREATE CONSTRAINT ON (jt:JobType) ASSERT jt.type_id IS UNIQUE;
|
||||
CREATE CONSTRAINT ON (o:Object) ASSERT o.id IS UNIQUE;
|
||||
CREATE CONSTRAINT ON (ot:ObjectType) ASSERT ot.type_id IS UNIQUE;
|
||||
CREATE CONSTRAINT ON (s:Status) ASSERT s.status_id IS UNIQUE;
|
||||
CREATE CONSTRAINT ON (a:Activity) ASSERT a.id IS UNIQUE;
|
||||
CREATE CONSTRAINT ON (s:Scenario) ASSERT s.id IS UNIQUE;
|
||||
|
||||
RETURN "Schema constraints and indexes created successfully.";
|
||||
58
cypher_scripts/create_schema_only.cypher
Normal file
58
cypher_scripts/create_schema_only.cypher
Normal file
@@ -0,0 +1,58 @@
|
||||
// 1. 인덱스 및 제약 조건 설정
|
||||
CREATE INDEX ON :Job(id);
|
||||
CREATE INDEX ON :JobType(id);
|
||||
CREATE INDEX ON :Object(id);
|
||||
CREATE INDEX ON :ObjectType(id);
|
||||
CREATE INDEX ON :Status(id);
|
||||
CREATE INDEX ON :Activity(id);
|
||||
CREATE INDEX ON :Scenario(id);
|
||||
|
||||
// 2. 노드 레이블 및 관계 타입 정의 (최소한의 샘플 생성)
|
||||
|
||||
// JobType 노드 생성
|
||||
CREATE (:JobType {type_id: 'SAMPLE_JT', name: 'Sample JobType'});
|
||||
|
||||
// Job 노드 생성
|
||||
CREATE (:Job {id: 'SAMPLE_JOB', name: 'Sample Job', duration: 0, cost: 0});
|
||||
|
||||
// ObjectType 노드 생성
|
||||
CREATE (:ObjectType {type_id: 'SAMPLE_OT', name: 'Sample ObjectType'});
|
||||
|
||||
// Object 노드 생성
|
||||
CREATE (:Object {id: 'SAMPLE_OBJ', name: 'Sample Object'});
|
||||
|
||||
// Status 노드 생성
|
||||
CREATE (:Status {status_id: 'SAMPLE_STATUS', name: 'Sample Status'});
|
||||
|
||||
// Activity 노드 생성
|
||||
CREATE (:Activity {id: 'SAMPLE_ACT', name: 'Sample Activity', description: 'Sample Description'});
|
||||
|
||||
// Scenario 노드 생성
|
||||
CREATE (:Scenario {id: 'SAMPLE_SCN', name: 'Sample Scenario', description: 'Sample Description'});
|
||||
|
||||
// 관계 생성 (샘플 노드들을 연결)
|
||||
MATCH (j:Job {id: 'SAMPLE_JOB'}), (jt:JobType {type_id: 'SAMPLE_JT'})
|
||||
CREATE (j)-[:IS_A]->(jt);
|
||||
|
||||
MATCH (o:Object {id: 'SAMPLE_OBJ'}), (ot:ObjectType {type_id: 'SAMPLE_OT'})
|
||||
CREATE (o)-[:IS_A]->(ot);
|
||||
|
||||
MATCH (j1:Job {id: 'SAMPLE_JOB'}), (j2:Job {id: 'SAMPLE_JOB'})
|
||||
CREATE (j1)-[:PRECEDES]->(j2);
|
||||
|
||||
MATCH (j:Job {id: 'SAMPLE_JOB'}), (s:Status {status_id: 'SAMPLE_STATUS'})
|
||||
CREATE (j)-[:HAS_STATUS]->(s);
|
||||
|
||||
MATCH (s:Scenario {id: 'SAMPLE_SCN'}), (j:Job {id: 'SAMPLE_JOB'})
|
||||
CREATE (s)-[:INCLUDES]->(j);
|
||||
|
||||
MATCH (s1:Scenario {id: 'SAMPLE_SCN'}), (s2:Scenario {id: 'SAMPLE_SCN'})
|
||||
CREATE (s1)-[:DELTA_FROM]->(s2);
|
||||
|
||||
MATCH (j:Job {id: 'SAMPLE_JOB'}), (a:Activity {id: 'SAMPLE_ACT'})
|
||||
CREATE (j)-[:PERFORMS]->(a);
|
||||
|
||||
MATCH (a:Activity {id: 'SAMPLE_ACT'}), (o:Object {id: 'SAMPLE_OBJ'})
|
||||
CREATE (a)-[:ACTS_ON]->(o);
|
||||
|
||||
RETURN "Schema creation successful!";
|
||||
31
cypher_scripts/debug_scenario_SCN04.cypher
Normal file
31
cypher_scripts/debug_scenario_SCN04.cypher
Normal file
@@ -0,0 +1,31 @@
|
||||
// --- SCN04 시나리오 디버깅 쿼리 ---
|
||||
// 아래 쿼리들을 위에서부터 하나씩 **따로따로** 복사하여 Memgraph Lab에서 실행해 보세요.
|
||||
// 각 쿼리가 어떤 결과를 반환하는지 확인하면 문제의 원인을 찾을 수 있습니다.
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 쿼리 1: SCN04 시나리오 노드가 존재하는지 확인합니다.
|
||||
// 예상 결과: SCN04 노드 1개가 보여야 합니다.
|
||||
// -----------------------------------------------------------------------------
|
||||
MATCH (s:Scenario {id: 'SCN04'})
|
||||
RETURN s;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 쿼리 2: SCN04에 포함된 Job들이 있는지 확인합니다.
|
||||
// 예상 결과: SCN04 노드와 :INCLUDES 관계로 연결된 5개의 Job 노드가 보여야 합니다.
|
||||
// -----------------------------------------------------------------------------
|
||||
MATCH p = (s:Scenario {id: 'SCN04'})-[:INCLUDES]->(j:Job)
|
||||
RETURN p;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 쿼리 3: SCN04의 시작 Job이 정의되어 있는지 확인합니다.
|
||||
// 예상 결과: SCN04에서 :STARTS_WITH 관계로 Job '2' 노드가 연결되어 보여야 합니다.
|
||||
// -----------------------------------------------------------------------------
|
||||
MATCH p = (s:Scenario {id: 'SCN04'})-[:STARTS_WITH]->(j:Job)
|
||||
RETURN p;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 쿼리 4: SCN04의 전체 작업 순서 경로를 확인합니다.
|
||||
// 예상 결과: Job '2' -> Job '1' -> Job '3' -> ... 순서로 :NEXT 관계가 연결되어 보여야 합니다.
|
||||
// -----------------------------------------------------------------------------
|
||||
MATCH p = (s:Scenario {id: 'SCN04'})-[:STARTS_WITH]->(start_job:Job)-[:NEXT* {scenario: 'SCN04'}]->(end_job:Job)
|
||||
RETURN p;
|
||||
38
cypher_scripts/import_new_model.cypher
Normal file
38
cypher_scripts/import_new_model.cypher
Normal file
@@ -0,0 +1,38 @@
|
||||
// 1. 기존 스키마 제약 조건 모두 삭제
|
||||
DROP CONSTRAINT ON (j:Job) ASSERT j.id IS UNIQUE;
|
||||
DROP CONSTRAINT ON (jt:JobType) ASSERT jt.type_id IS UNIQUE;
|
||||
DROP CONSTRAINT ON (o:Object) ASSERT o.id IS UNIQUE;
|
||||
DROP CONSTRAINT ON (ot:ObjectType) ASSERT ot.type_id IS UNIQUE;
|
||||
DROP CONSTRAINT ON (s:Status) ASSERT s.status_id IS UNIQUE;
|
||||
DROP CONSTRAINT ON (a:Activity) ASSERT a.id IS UNIQUE;
|
||||
DROP CONSTRAINT ON (s:Scenario) ASSERT s.id IS UNIQUE;
|
||||
|
||||
// 2. 인덱스 생성
|
||||
CREATE INDEX ON :Job(id);
|
||||
CREATE INDEX ON :JobType(id);
|
||||
CREATE INDEX ON :Object(id);
|
||||
CREATE INDEX ON :ObjectType(id);
|
||||
CREATE INDEX ON :Status(id);
|
||||
CREATE INDEX ON :Activity(id);
|
||||
CREATE INDEX ON :Scenario(id);
|
||||
|
||||
// 3. 노드 데이터 로드
|
||||
LOAD CSV FROM "/data/job_types.csv" WITH HEADER AS row CREATE (n:JobType {type_id: row.id, name: row.name});
|
||||
LOAD CSV FROM "/data/jobs.csv" WITH HEADER AS row CREATE (n:Job {id: row.id, name: row.name, duration: toInteger(row.duration), cost: toInteger(row.cost)});
|
||||
LOAD CSV FROM "/data/object_types.csv" WITH HEADER AS row CREATE (n:ObjectType {type_id: row.id, name: row.name});
|
||||
LOAD CSV FROM "/data/objects.csv" WITH HEADER AS row CREATE (n:Object {id: row.id, name: row.name});
|
||||
LOAD CSV FROM "/data/mgmt_status.csv" WITH HEADER AS row CREATE (n:Status {status_id: row.id, name: row.status});
|
||||
LOAD CSV FROM "/data/activities.csv" WITH HEADER AS row CREATE (n:Activity {id: row.id, name: row.name, description: row.description});
|
||||
LOAD CSV FROM "/data/scenarios.csv" WITH HEADER AS row CREATE (n:Scenario {id: row.id, name: row.name, description: row.description});
|
||||
|
||||
// 4. 관계 데이터 로드
|
||||
LOAD CSV FROM "/data/relations.csv" WITH HEADER AS row WHERE row.type = 'IS_A' AND row.from_id STARTS WITH 'J' MATCH (from:Job {id: row.from_id}), (to:JobType {type_id: row.to_id}) CREATE (from)-[:IS_A]->(to);
|
||||
LOAD CSV FROM "/data/relations.csv" WITH HEADER AS row WHERE row.type = 'IS_A' AND row.from_id STARTS WITH 'O' MATCH (from:Object {id: row.from_id}), (to:ObjectType {type_id: row.to_id}) CREATE (from)-[:IS_A]->(to);
|
||||
LOAD CSV FROM "/data/relations.csv" WITH HEADER AS row WHERE row.type = 'PRECEDES' MATCH (from:Job {id: row.from_id}), (to:Job {id: row.to_id}) CREATE (from)-[:PRECEDES]->(to);
|
||||
LOAD CSV FROM "/data/relations.csv" WITH HEADER AS row WHERE row.type = 'HAS_STATUS' MATCH (from:Job {id: row.from_id}), (to:Status {status_id: row.to_id}) CREATE (from)-[:HAS_STATUS]->(to);
|
||||
LOAD CSV FROM "/data/relations_new.csv" WITH HEADER AS row WHERE row.type = 'INCLUDES' MATCH (from:Scenario {id: row.from_id}), (to:Job {id: row.to_id}) CREATE (from)-[:INCLUDES]->(to);
|
||||
LOAD CSV FROM "/data/relations_new.csv" WITH HEADER AS row WHERE row.type = 'DELTA_FROM' MATCH (from:Scenario {id: row.from_id}), (to:Scenario {id: row.to_id}) CREATE (from)-[:DELTA_FROM]->(to);
|
||||
LOAD CSV FROM "/data/relations_new.csv" WITH HEADER AS row WHERE row.type = 'PERFORMS' MATCH (from:Job {id: row.from_id}), (to:Activity {id: row.to_id}) CREATE (from)-[:PERFORMS]->(to);
|
||||
LOAD CSV FROM "/data/relations_new.csv" WITH HEADER AS row WHERE row.type = 'ACTS_ON' MATCH (from:Activity {id: row.from_id}), (to:Object {id: row.to_id}) CREATE (from)-[:ACTS_ON]->(to);
|
||||
|
||||
RETURN "Import successful!";
|
||||
198
cypher_scripts/import_with_embedded_data.cypher
Normal file
198
cypher_scripts/import_with_embedded_data.cypher
Normal file
@@ -0,0 +1,198 @@
|
||||
// 0. 데이터베이스 초기화
|
||||
MATCH (n) DETACH DELETE n;
|
||||
|
||||
// 1. 노드 생성
|
||||
|
||||
// JobType 노드
|
||||
CREATE (:JobType {type_id: 'JT01', name: '터널 입구 굴착'});
|
||||
CREATE (:JobType {type_id: 'JT02', name: '숏크리트 타설'});
|
||||
CREATE (:JobType {type_id: 'JT03', name: '강지보 설치'});
|
||||
CREATE (:JobType {type_id: 'JT04', name: '방수 및 배수시설 설치'});
|
||||
CREATE (:JobType {type_id: 'JT05', name: '철근 조립'});
|
||||
CREATE (:JobType {type_id: 'JT06', name: '내부 라이닝 콘크리트 타설'});
|
||||
CREATE (:JobType {type_id: 'JT07', name: '조명 및 환기시설 설치'});
|
||||
CREATE (:JobType {type_id: 'JT08', name: '안전시설물 설치'});
|
||||
CREATE (:JobType {type_id: 'JT09', name: '포장 및 차선 도색'});
|
||||
CREATE (:JobType {type_id: 'JT10', name: 'TBM 준비'});
|
||||
CREATE (:JobType {type_id: 'JT11', name: 'TBM 굴진'});
|
||||
CREATE (:JobType {type_id: 'JT12', name: '세그먼트 조립'});
|
||||
CREATE (:JobType {type_id: 'JT13', name: '그라우팅'});
|
||||
CREATE (:JobType {type_id: 'JT14', name: 'TBM 해체 및 반출'});
|
||||
CREATE (:JobType {type_id: 'JT15', name: '전기/통신 케이블 설치'});
|
||||
CREATE (:JobType {type_id: 'JT16', name: 'CCTV 및 VMS 설치'});
|
||||
CREATE (:JobType {type_id: 'JT17', name: '소방시설 설치'});
|
||||
CREATE (:JobType {type_id: 'JT18', name: '최종 점검'});
|
||||
CREATE (:JobType {type_id: 'JT19', name: '개통 준비'});
|
||||
|
||||
// Job 노드
|
||||
CREATE (:Job {id: '1', name: '터널 입구 굴착', duration: 10, cost: 150});
|
||||
CREATE (:Job {id: '2', name: '1차 숏크리트 타설', duration: 5, cost: 80});
|
||||
CREATE (:Job {id: '3', name: '강지보 설치', duration: 7, cost: 120});
|
||||
CREATE (:Job {id: '4', name: '2차 숏크리트 타설', duration: 5, cost: 80});
|
||||
CREATE (:Job {id: '5', name: '방수 및 배수시설 설치', duration: 8, cost: 100});
|
||||
CREATE (:Job {id: '6', name: '철근 조립', duration: 6, cost: 90});
|
||||
CREATE (:Job {id: '7', name: '내부 라이닝 콘크리트 타설', duration: 12, cost: 200});
|
||||
CREATE (:Job {id: '8', name: '조명 및 환기시설 설치', duration: 9, cost: 110});
|
||||
CREATE (:Job {id: '9', name: '안전시설물 설치', duration: 4, cost: 60});
|
||||
CREATE (:Job {id: '10', name: '포장 및 차선 도색', duration: 7, cost: 95});
|
||||
CREATE (:Job {id: '11', name: 'TBM 준비', duration: 15, cost: 500});
|
||||
CREATE (:Job {id: '12', name: 'TBM 굴진', duration: 30, cost: 1200});
|
||||
CREATE (:Job {id: '13', name: '세그먼트 조립', duration: 25, cost: 800});
|
||||
CREATE (:Job {id: '14', name: '그라우팅', duration: 10, cost: 150});
|
||||
CREATE (:Job {id: '15', name: 'TBM 해체 및 반출', duration: 12, cost: 300});
|
||||
CREATE (:Job {id: '16', name: '전기/통신 케이블 설치', duration: 8, cost: 130});
|
||||
CREATE (:Job {id: '17', name: 'CCTV 및 VMS 설치', duration: 5, cost: 70});
|
||||
CREATE (:Job {id: '18', name: '소방시설 설치', duration: 6, cost: 85});
|
||||
CREATE (:Job {id: '19', name: '최종 점검', duration: 3, cost: 50});
|
||||
CREATE (:Job {id: '20', name: '개통 준비', duration: 2, cost: 30});
|
||||
|
||||
// ObjectType 노드
|
||||
CREATE (:ObjectType {type_id: 'OT01', name: '굴착기'});
|
||||
CREATE (:ObjectType {type_id: 'OT02', name: '숏크리트 펌프'});
|
||||
CREATE (:ObjectType {type_id: 'OT03', name: '강지보재'});
|
||||
CREATE (:ObjectType {type_id: 'OT04', name: '방수시트'});
|
||||
CREATE (:ObjectType {type_id: 'OT05', name: '콘크리트 믹서'});
|
||||
CREATE (:ObjectType {type_id: 'OT06', name: '철근'});
|
||||
CREATE (:ObjectType {type_id: 'OT07', name: '조명등'});
|
||||
CREATE (:ObjectType {type_id: 'OT08', name: '환풍기'});
|
||||
CREATE (:ObjectType {type_id: 'OT09', name: 'TBM'});
|
||||
CREATE (:ObjectType {type_id: 'OT10', name: '세그먼트'});
|
||||
CREATE (:ObjectType {type_id: 'OT11', name: '그라우트 믹서'});
|
||||
CREATE (:ObjectType {type_id: 'OT12', name: '케이블'});
|
||||
CREATE (:ObjectType {type_id: 'OT13', name: 'CCTV'});
|
||||
CREATE (:ObjectType {type_id: 'OT14', name: '소화기'});
|
||||
CREATE (:ObjectType {type_id: 'OT15', name: '차선도색기'});
|
||||
CREATE (:ObjectType {type_id: 'OT16', name: '숏크리트'});
|
||||
|
||||
// Object 노드
|
||||
CREATE (:Object {id: 'OBJ01', name: '굴착기-A01'});
|
||||
CREATE (:Object {id: 'OBJ02', name: '숏크리트 펌프-A'});
|
||||
CREATE (:Object {id: 'OBJ03', name: '강지보재-L100'});
|
||||
CREATE (:Object {id: 'OBJ04', name: '방수시트-S20'});
|
||||
CREATE (:Object {id: 'OBJ05', name: '콘크리트 믹서-T1'});
|
||||
CREATE (:Object {id: 'OBJ06', name: '철근-D16'});
|
||||
CREATE (:Object {id: 'OBJ07', name: '조명등-LED-1'});
|
||||
CREATE (:Object {id: 'OBJ08', name: '환풍기-F1'});
|
||||
CREATE (:Object {id: 'OBJ09', name: 'TBM-Shield-1'});
|
||||
CREATE (:Object {id: 'OBJ10', name: '세그먼트-A타입'});
|
||||
CREATE (:Object {id: 'OBJ11', name: '그라우트 믹서-G1'});
|
||||
CREATE (:Object {id: 'OBJ12', name: '전원 케이블-HV-1'});
|
||||
CREATE (:Object {id: 'OBJ13', name: 'CCTV-001'});
|
||||
CREATE (:Object {id: 'OBJ14', name: '소화기-P1'});
|
||||
CREATE (:Object {id: 'OBJ15', name: '차선도색기-Y1'});
|
||||
CREATE (:Object {id: 'OBJ16', name: '숏크리트-Batch1'});
|
||||
CREATE (:Object {id: 'OBJ17', name: '숏크리트-Batch2'});
|
||||
|
||||
// Status 노드
|
||||
CREATE (:Status {status_id: 'CS_APP', name: 'APPROVED'});
|
||||
CREATE (:Status {status_id: 'CS_CON', name: 'CONFIRMED'});
|
||||
CREATE (:Status {status_id: 'CS_PLN', name: 'PLANNING'});
|
||||
CREATE (:Status {status_id: 'PS_EXE', name: 'EXECUTING'});
|
||||
CREATE (:Status {status_id: 'PS_PLN', name: 'PLANNING'});
|
||||
CREATE (:Status {status_id: 'PM_PAID', name: 'PAID'});
|
||||
CREATE (:Status {status_id: 'PM_APL', name: 'APPLIED'});
|
||||
CREATE (:Status {status_id: 'PM_NON', name: 'NONE'});
|
||||
CREATE (:Status {status_id: 'QS_APP', name: 'APPROVED'});
|
||||
CREATE (:Status {status_id: 'QS_CON', name: 'CONFIRMED'});
|
||||
CREATE (:Status {status_id: 'QS_PLN', name: 'PLANNING'});
|
||||
CREATE (:Status {status_id: 'SS_APP', name: 'APPROVED'});
|
||||
CREATE (:Status {status_id: 'SS_CON', name: 'CONFIRMED'});
|
||||
CREATE (:Status {status_id: 'SS_PLN', name: 'PLANNING'});
|
||||
|
||||
// Activity 노드
|
||||
CREATE (:Activity {id: 'ACT01', name: '굴착 작업', description: '터널 입구 지반 굴착'});
|
||||
CREATE (:Activity {id: 'ACT02', name: '숏크리트 타설 작업', description: '굴착면에 숏크리트 타설하여 안정화'});
|
||||
CREATE (:Activity {id: 'ACT03', name: '강지보 설치 작업', description: '강재 지보를 설치하여 터널 구조 강화'});
|
||||
CREATE (:Activity {id: 'ACT04', name: '방수/배수 작업', description: '방수시트 및 배수시설 설치'});
|
||||
CREATE (:Activity {id: 'ACT05', name: '철근 조립 작업', description: '내부 라이닝을 위한 철근 조립'});
|
||||
|
||||
// Scenario 노드
|
||||
CREATE (:Scenario {id: 'SCN01', name: '기본 시나리오', description: '가장 기본적인 순서의 작업 흐름'});
|
||||
CREATE (:Scenario {id: 'SCN02', name: 'TBM 공법 적용 시나리오', description: 'TBM 장비를 활용한 대체 작업 흐름'});
|
||||
CREATE (:Scenario {id: 'SCN03', name: 'SCN02 증분 시나리오', description: 'SCN02 시나리오에서 일부 작업 순서 변경'});
|
||||
|
||||
// 2. 관계 생성
|
||||
|
||||
// Job IS_A JobType
|
||||
MATCH (j:Job {id: '1'}), (jt:JobType {type_id: 'JT01'}) CREATE (j)-[:IS_A]->(jt);
|
||||
MATCH (j:Job {id: '2'}), (jt:JobType {type_id: 'JT02'}) CREATE (j)-[:IS_A]->(jt);
|
||||
MATCH (j:Job {id: '3'}), (jt:JobType {type_id: 'JT03'}) CREATE (j)-[:IS_A]->(jt);
|
||||
MATCH (j:Job {id: '4'}), (jt:JobType {type_id: 'JT02'}) CREATE (j)-[:IS_A]->(jt);
|
||||
MATCH (j:Job {id: '5'}), (jt:JobType {type_id: 'JT04'}) CREATE (j)-[:IS_A]->(jt);
|
||||
|
||||
// Object IS_A ObjectType
|
||||
MATCH (o:Object {id: 'OBJ01'}), (ot:ObjectType {type_id: 'OT01'}) CREATE (o)-[:IS_A]->(ot);
|
||||
MATCH (o:Object {id: 'OBJ02'}), (ot:ObjectType {type_id: 'OT02'}) CREATE (o)-[:IS_A]->(ot);
|
||||
MATCH (o:Object {id: 'OBJ16'}), (ot:ObjectType {type_id: 'OT16'}) CREATE (o)-[:IS_A]->(ot);
|
||||
MATCH (o:Object {id: 'OBJ17'}), (ot:ObjectType {type_id: 'OT16'}) CREATE (o)-[:IS_A]->(ot);
|
||||
|
||||
// Job PRECEDES Job
|
||||
MATCH (j1:Job {id: '1'}), (j2:Job {id: '2'}) CREATE (j1)-[:PRECEDES]->(j2);
|
||||
MATCH (j1:Job {id: '2'}), (j2:Job {id: '3'}) CREATE (j1)-[:PRECEDES]->(j2);
|
||||
MATCH (j1:Job {id: '3'}), (j2:Job {id: '4'}) CREATE (j1)-[:PRECEDES]->(j2);
|
||||
MATCH (j1:Job {id: '4'}), (j2:Job {id: '5'}) CREATE (j1)-[:PRECEDES]->(j2);
|
||||
|
||||
// Job HAS_STATUS Status
|
||||
MATCH (j:Job {id: '1'}), (s:Status {status_id: 'CS_APP'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '1'}), (s:Status {status_id: 'PS_EXE'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '1'}), (s:Status {status_id: 'PM_PAID'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '1'}), (s:Status {status_id: 'QS_APP'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '1'}), (s:Status {status_id: 'SS_APP'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '2'}), (s:Status {status_id: 'CS_APP'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '2'}), (s:Status {status_id: 'PS_EXE'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '2'}), (s:Status {status_id: 'PM_PAID'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '2'}), (s:Status {status_id: 'QS_APP'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '2'}), (s:Status {status_id: 'SS_APP'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '3'}), (s:Status {status_id: 'CS_CON'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '3'}), (s:Status {status_id: 'PS_EXE'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '3'}), (s:Status {status_id: 'PM_APL'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '3'}), (s:Status {status_id: 'QS_CON'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '3'}), (s:Status {status_id: 'SS_CON'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '4'}), (s:Status {status_id: 'CS_PLN'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '4'}), (s:Status {status_id: 'PS_PLN'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '4'}), (s:Status {status_id: 'PM_NON'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '4'}), (s:Status {status_id: 'QS_PLN'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '4'}), (s:Status {status_id: 'SS_PLN'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '5'}), (s:Status {status_id: 'CS_PLN'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '5'}), (s:Status {status_id: 'PS_PLN'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '5'}), (s:Status {status_id: 'PM_NON'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '5'}), (s:Status {status_id: 'QS_PLN'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
MATCH (j:Job {id: '5'}), (s:Status {status_id: 'SS_PLN'}) CREATE (j)-[:HAS_STATUS]->(s);
|
||||
|
||||
// Scenario INCLUDES Job
|
||||
MATCH (s:Scenario {id: 'SCN01'}), (j:Job {id: '1'}) CREATE (s)-[:INCLUDES]->(j);
|
||||
MATCH (s:Scenario {id: 'SCN01'}), (j:Job {id: '2'}) CREATE (s)-[:INCLUDES]->(j);
|
||||
MATCH (s:Scenario {id: 'SCN01'}), (j:Job {id: '3'}) CREATE (s)-[:INCLUDES]->(j);
|
||||
MATCH (s:Scenario {id: 'SCN01'}), (j:Job {id: '4'}) CREATE (s)-[:INCLUDES]->(j);
|
||||
MATCH (s:Scenario {id: 'SCN01'}), (j:Job {id: '5'}) CREATE (s)-[:INCLUDES]->(j);
|
||||
MATCH (s:Scenario {id: 'SCN02'}), (j:Job {id: '11'}) CREATE (s)-[:INCLUDES]->(j);
|
||||
MATCH (s:Scenario {id: 'SCN02'}), (j:Job {id: '12'}) CREATE (s)-[:INCLUDES]->(j);
|
||||
MATCH (s:Scenario {id: 'SCN02'}), (j:Job {id: '13'}) CREATE (s)-[:INCLUDES]->(j);
|
||||
MATCH (s:Scenario {id: 'SCN02'}), (j:Job {id: '14'}) CREATE (s)-[:INCLUDES]->(j);
|
||||
MATCH (s:Scenario {id: 'SCN02'}), (j:Job {id: '15'}) CREATE (s)-[:INCLUDES]->(j);
|
||||
MATCH (s:Scenario {id: 'SCN03'}), (j:Job {id: '11'}) CREATE (s)-[:INCLUDES]->(j);
|
||||
MATCH (s:Scenario {id: 'SCN03'}), (j:Job {id: '13'}) CREATE (s)-[:INCLUDES]->(j);
|
||||
MATCH (s:Scenario {id: 'SCN03'}), (j:Job {id: '12'}) CREATE (s)-[:INCLUDES]->(j);
|
||||
MATCH (s:Scenario {id: 'SCN03'}), (j:Job {id: '14'}) CREATE (s)-[:INCLUDES]->(j);
|
||||
MATCH (s:Scenario {id: 'SCN03'}), (j:Job {id: '15'}) CREATE (s)-[:INCLUDES]->(j);
|
||||
|
||||
// Scenario DELTA_FROM Scenario
|
||||
MATCH (s1:Scenario {id: 'SCN03'}), (s2:Scenario {id: 'SCN02'}) CREATE (s1)-[:DELTA_FROM]->(s2);
|
||||
|
||||
// Job PERFORMS Activity
|
||||
MATCH (j:Job {id: '1'}), (a:Activity {id: 'ACT01'}) CREATE (j)-[:PERFORMS]->(a);
|
||||
MATCH (j:Job {id: '2'}), (a:Activity {id: 'ACT02'}) CREATE (j)-[:PERFORMS]->(a);
|
||||
MATCH (j:Job {id: '3'}), (a:Activity {id: 'ACT03'}) CREATE (j)-[:PERFORMS]->(a);
|
||||
MATCH (j:Job {id: '4'}), (a:Activity {id: 'ACT02'}) CREATE (j)-[:PERFORMS]->(a);
|
||||
MATCH (j:Job {id: '5'}), (a:Activity {id: 'ACT04'}) CREATE (j)-[:PERFORMS]->(a);
|
||||
MATCH (j:Job {id: '6'}), (a:Activity {id: 'ACT05'}) CREATE (j)-[:PERFORMS]->(a);
|
||||
|
||||
// Activity ACTS_ON Object
|
||||
MATCH (a:Activity {id: 'ACT01'}), (o:Object {id: 'OBJ01'}) CREATE (a)-[:ACTS_ON]->(o);
|
||||
MATCH (a:Activity {id: 'ACT02'}), (o:Object {id: 'OBJ02'}) CREATE (a)-[:ACTS_ON]->(o);
|
||||
MATCH (a:Activity {id: 'ACT02'}), (o:Object {id: 'OBJ16'}) CREATE (a)-[:ACTS_ON]->(o);
|
||||
MATCH (a:Activity {id: 'ACT03'}), (o:Object {id: 'OBJ03'}) CREATE (a)-[:ACTS_ON]->(o);
|
||||
MATCH (a:Activity {id: 'ACT04'}), (o:Object {id: 'OBJ04'}) CREATE (a)-[:ACTS_ON]->(o);
|
||||
MATCH (a:Activity {id: 'ACT05'}), (o:Object {id: 'OBJ06'}) CREATE (a)-[:ACTS_ON]->(o);
|
||||
|
||||
RETURN "All data imported successfully!";
|
||||
52
cypher_scripts/recreate_scenario_SCN04_final_fix.cypher
Normal file
52
cypher_scripts/recreate_scenario_SCN04_final_fix.cypher
Normal file
@@ -0,0 +1,52 @@
|
||||
// --- SCN04 시나리오 재생성 (최종 수정 쿼리) ---
|
||||
|
||||
// 0. 기존에 잘못 생성되었을 수 있는 SCN04 관련 데이터를 모두 삭제합니다.
|
||||
MATCH (s:Scenario {id: 'SCN04'})
|
||||
DETACH DELETE s;
|
||||
|
||||
// 1. 새로운 시나리오 'SCN04' 노드를 생성하고, WITH 절로 s4 변수를 바로 다음 쿼리로 전달합니다.
|
||||
CREATE (s4:Scenario {id: 'SCN04', name: 'SCN01 순서 변경 시나리오', description: 'SCN01에서 Job 2와 Job 1의 순서를 변경'})
|
||||
WITH s4;
|
||||
|
||||
// 2. SCN01에 포함된 Job들을 찾아 SCN04에 :INCLUDES 관계로 연결합니다.
|
||||
MATCH (s1:Scenario {id: 'SCN01'})-[:INCLUDES]->(j:Job)
|
||||
WITH s4, j // 이전 단계의 s4와 현재 찾은 j를 함께 전달합니다.
|
||||
CREATE (s4)-[:INCLUDES]->(j);
|
||||
|
||||
// 3. SCN01의 순서를 기반으로 SCN04의 초기 순서를 복제합니다.
|
||||
// - STARTS_WITH 관계 복제
|
||||
MATCH (s4:Scenario {id: 'SCN04'})
|
||||
MATCH (s1:Scenario {id: 'SCN01'})-[sw:STARTS_WITH]->(start_job:Job)
|
||||
CREATE (s4)-[:STARTS_WITH]->(start_job);
|
||||
|
||||
// - NEXT 관계망 복제 (SCN04 시나리오에 종속된 NEXT 관계 생성)
|
||||
MATCH (s1:Scenario {id: 'SCN01'})-[:STARTS_WITH]->(start_job:Job)
|
||||
MATCH path = (start_job)-[:NEXT*]->(end_job:Job)
|
||||
WHERE NOT (end_job)-[:NEXT]->()
|
||||
WITH nodes(path) AS jobs
|
||||
UNWIND range(0, size(jobs)-2) AS i
|
||||
WITH jobs[i] AS from_job, jobs[i+1] AS to_job
|
||||
MATCH (s4:Scenario {id: 'SCN04'})
|
||||
MERGE (j1:Job {id: from_job.id})
|
||||
MERGE (j2:Job {id: to_job.id})
|
||||
CREATE (j1)-[:NEXT {scenario: 'SCN04'}]->(j2);
|
||||
|
||||
|
||||
// 4. SCN04에서 Job 1과 Job 2의 순서를 변경합니다. (기존 1->2->3 ... 을 2->1->3 ... 으로)
|
||||
// - 기존 관계 삭제
|
||||
MATCH (s4:Scenario {id: 'SCN04'})-[sw:STARTS_WITH]->(j1:Job {id: '1'})
|
||||
DELETE sw;
|
||||
|
||||
MATCH (j1:Job {id: '1'})-[n1:NEXT {scenario: 'SCN04'}]->(j2:Job {id: '2'})
|
||||
DELETE n1;
|
||||
|
||||
MATCH (j2:Job {id: '2'})-[n2:NEXT {scenario: 'SCN04'}]->(j3:Job {id: '3'})
|
||||
DELETE n2;
|
||||
|
||||
// - 새로운 관계 생성
|
||||
MATCH (s4:Scenario {id: 'SCN04'}), (j1:Job {id: '1'}), (j2:Job {id: '2'}), (j3:Job {id: '3'})
|
||||
CREATE (s4)-[:STARTS_WITH]->(j2),
|
||||
(j2)-[:NEXT {scenario: 'SCN04'}]->(j1),
|
||||
(j1)-[:NEXT {scenario: 'SCN04'}]->(j3);
|
||||
|
||||
RETURN "SCN04가 성공적으로 재생성되었습니다.";
|
||||
52
cypher_scripts/recreate_scenario_SCN04_fix.cypher
Normal file
52
cypher_scripts/recreate_scenario_SCN04_fix.cypher
Normal file
@@ -0,0 +1,52 @@
|
||||
// --- SCN04 시나리오 재생성 (수정된 쿼리) ---
|
||||
|
||||
// 0. 기존에 잘못 생성되었을 수 있는 SCN04 관련 데이터를 모두 삭제합니다.
|
||||
MATCH (s:Scenario {id: 'SCN04'})
|
||||
DETACH DELETE s;
|
||||
|
||||
// 1. 새로운 시나리오 'SCN04' 노드를 다시 생성합니다.
|
||||
CREATE (s4:Scenario {id: 'SCN04', name: 'SCN01 순서 변경 시나리오', description: 'SCN01에서 Job 2와 Job 1의 순서를 변경'});
|
||||
|
||||
// 2. SCN01에 포함된 Job들을 찾아 SCN04에 :INCLUDES 관계로 연결합니다. (수정된 부분)
|
||||
// WITH 절을 사용하여 s4를 명시적으로 전달합니다.
|
||||
WITH s4
|
||||
MATCH (s1:Scenario {id: 'SCN01'})-[:INCLUDES]->(j:Job)
|
||||
CREATE (s4)-[:INCLUDES]->(j);
|
||||
|
||||
// 3. SCN01의 순서를 기반으로 SCN04의 초기 순서를 복제합니다.
|
||||
// - STARTS_WITH 관계 복제
|
||||
WITH s4
|
||||
MATCH (s1:Scenario {id: 'SCN01'})-[sw:STARTS_WITH]->(start_job:Job)
|
||||
CREATE (s4)-[:STARTS_WITH]->(start_job);
|
||||
|
||||
// - NEXT 관계망 복제 (SCN04 시나리오에 종속된 NEXT 관계 생성)
|
||||
MATCH (s1:Scenario {id: 'SCN01'})-[:STARTS_WITH]->(start_job:Job)
|
||||
MATCH path = (start_job)-[:NEXT*]->(end_job:Job)
|
||||
WHERE NOT (end_job)-[:NEXT]->()
|
||||
WITH nodes(path) AS jobs
|
||||
UNWIND range(0, size(jobs)-2) AS i
|
||||
WITH jobs[i] AS from_job, jobs[i+1] AS to_job
|
||||
MATCH (s4:Scenario {id: 'SCN04'})
|
||||
MERGE (j1:Job {id: from_job.id})
|
||||
MERGE (j2:Job {id: to_job.id})
|
||||
CREATE (j1)-[:NEXT {scenario: 'SCN04'}]->(j2);
|
||||
|
||||
|
||||
// 4. SCN04에서 Job 1과 Job 2의 순서를 변경합니다. (기존 1->2->3 ... 을 2->1->3 ... 으로)
|
||||
// - 기존 관계 삭제
|
||||
MATCH (s4:Scenario {id: 'SCN04'})-[sw:STARTS_WITH]->(j1:Job {id: '1'})
|
||||
DELETE sw;
|
||||
|
||||
MATCH (j1:Job {id: '1'})-[n1:NEXT {scenario: 'SCN04'}]->(j2:Job {id: '2'})
|
||||
DELETE n1;
|
||||
|
||||
MATCH (j2:Job {id: '2'})-[n2:NEXT {scenario: 'SCN04'}]->(j3:Job {id: '3'})
|
||||
DELETE n2;
|
||||
|
||||
// - 새로운 관계 생성
|
||||
MATCH (s4:Scenario {id: 'SCN04'}), (j1:Job {id: '1'}), (j2:Job {id: '2'}), (j3:Job {id: '3'})
|
||||
CREATE (s4)-[:STARTS_WITH]->(j2),
|
||||
(j2)-[:NEXT {scenario: 'SCN04'}]->(j1),
|
||||
(j1)-[:NEXT {scenario: 'SCN04'}]->(j3);
|
||||
|
||||
RETURN "SCN04가 성공적으로 재생성되었습니다.";
|
||||
12
cypher_scripts/visualize_scenario_SCN04.cypher
Normal file
12
cypher_scripts/visualize_scenario_SCN04.cypher
Normal file
@@ -0,0 +1,12 @@
|
||||
// SCN04 시나리오의 전체 구조를 시각화하는 쿼리
|
||||
// 시나리오 노드, 포함된 모든 Job, 그리고 작업 실행 순서(STARTS_WITH, NEXT)를 함께 조회합니다.
|
||||
|
||||
// p1 경로는 SCN04에 포함된(:INCLUDES) 모든 Job을 찾습니다.
|
||||
MATCH p1 = (s:Scenario {id: 'SCN04'})-[:INCLUDES]->(job:Job)
|
||||
|
||||
// p2 경로는 SCN04의 시작(:STARTS_WITH)부터 NEXT 관계로 이어진 작업 순서 전체를 찾습니다.
|
||||
// 이 경로는 SCN04에만 해당하는 NEXT 관계({scenario: 'SCN04'})를 따라갑니다.
|
||||
MATCH p2 = (s)-[:STARTS_WITH]->(start_job:Job)-[:NEXT* {scenario: 'SCN04'}]->(end_job:Job)
|
||||
|
||||
// 두 경로(p1, p2)를 모두 반환하여 시나리오의 전체 구조를 시각화합니다.
|
||||
RETURN p1, p2;
|
||||
6
data/activities.csv
Normal file
6
data/activities.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
id,name,description
|
||||
ACT01,굴착 작업,터널 입구 지반 굴착
|
||||
ACT02,숏크리트 타설 작업,굴착면에 숏크리트 타설하여 안정화
|
||||
ACT03,강지보 설치 작업,강재 지보를 설치하여 터널 구조 강화
|
||||
ACT04,방수/배수 작업,방수시트 및 배수시설 설치
|
||||
ACT05,철근 조립 작업,내부 라이닝을 위한 철근 조립
|
||||
|
33
data/relations_new.csv
Normal file
33
data/relations_new.csv
Normal file
@@ -0,0 +1,33 @@
|
||||
from_id,to_id,type
|
||||
# Scenario INCLUDES Job
|
||||
SCN01,1,INCLUDES
|
||||
SCN01,2,INCLUDES
|
||||
SCN01,3,INCLUDES
|
||||
SCN01,4,INCLUDES
|
||||
SCN01,5,INCLUDES
|
||||
SCN02,11,INCLUDES
|
||||
SCN02,12,INCLUDES
|
||||
SCN02,13,INCLUDES
|
||||
SCN02,14,INCLUDES
|
||||
SCN02,15,INCLUDES
|
||||
SCN03,11,INCLUDES
|
||||
SCN03,13,INCLUDES # 12, 13 순서 변경
|
||||
SCN03,12,INCLUDES
|
||||
SCN03,14,INCLUDES
|
||||
SCN03,15,INCLUDES
|
||||
# Scenario DELTA_FROM Scenario
|
||||
SCN03,SCN02,DELTA_FROM
|
||||
# Job PERFORMS Activity
|
||||
1,ACT01,PERFORMS
|
||||
2,ACT02,PERFORMS
|
||||
3,ACT03,PERFORMS
|
||||
4,ACT02,PERFORMS
|
||||
5,ACT04,PERFORMS
|
||||
6,ACT05,PERFORMS
|
||||
# Activity ACTS_ON Object
|
||||
ACT01,OBJ01,ACTS_ON
|
||||
ACT02,OBJ02,ACTS_ON
|
||||
ACT02,OBJ16,ACTS_ON
|
||||
ACT03,OBJ03,ACTS_ON
|
||||
ACT04,OBJ04,ACTS_ON
|
||||
ACT05,OBJ06,ACTS_ON
|
||||
|
4
data/scenarios.csv
Normal file
4
data/scenarios.csv
Normal file
@@ -0,0 +1,4 @@
|
||||
id,name,description
|
||||
SCN01,기본 시나리오,가장 기본적인 순서의 작업 흐름
|
||||
SCN02,TBM 공법 적용 시나리오,TBM 장비를 활용한 대체 작업 흐름
|
||||
SCN03,SCN02 증분 시나리오,SCN02 시나리오에서 일부 작업 순서 변경
|
||||
|
@@ -10,6 +10,7 @@ services:
|
||||
pull_policy: always
|
||||
environment:
|
||||
- storage-properties-on-edges=true
|
||||
- storage-mode=true=IN_MEMORY_TRANSACTIONAL
|
||||
ulimits:
|
||||
stack:
|
||||
soft: 33554432
|
||||
@@ -20,6 +21,7 @@ services:
|
||||
volumes:
|
||||
- ./memgraph-data:/var/lib/memgraph
|
||||
- ./conf/memgraph.conf:/etc/memgraph/memgraph.conf
|
||||
- ./data:/data
|
||||
|
||||
lab:
|
||||
image: memgraph/lab:latest
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
### 1. 개요 (Overview)
|
||||
|
||||
본 문서는 터널 시공 과정에서 발생하는 복잡한 작업(Job)과 객체(Object) 간의 관계를 그래프 데이터베이스인 Memgraph를 활용하여 모델링하고, 이를 통해 프로젝트의 Critical Path를 분석하여 효율적인 공정 관리를 지원하는 의사결정 프레임워크 PoC(Proof of Concept)의 요구사항을 정의합니다.
|
||||
본 문서는 터널 시공 과정에서 발생하는 복잡한 작업(Job)과 객체(Object) 간의 관계를 그래프 데이터베이스인 Memgraph를 활용하여 모델링하고, 모든 job을 완료 상태로 만들 수 있는 시나리오들을 비교해 프로젝트의 Critical Path를 분석하여 효율적인 공정 관리를 지원하는 의사결정 프레임워크 PoC(Proof of Concept)의 요구사항을 정의합니다.
|
||||
|
||||
**1.1. 문제 정의 (Problem Statement)**
|
||||
|
||||
|
||||
Reference in New Issue
Block a user