콘텐츠로 이동

그래프 데이터베이스

이 프로젝트는 Amazon Neptune DB Serverless를 그래프 데이터베이스로 사용합니다. 문서 분석 과정에서 추출 및 정규화된 핵심 엔티티를 지식 그래프에 저장하여, 벡터 검색만으로는 달성하기 어려운 엔티티 연결 기반 탐색을 지원합니다.

관점벡터 검색 (LanceDB)그래프 탐색 (Neptune)키워드 그래프 (LanceDB + Neptune)
검색 방식의미적 유사도엔티티 관계 탐색키워드 임베딩 유사도 + 그래프 탐색
강점”유사한 콘텐츠” 찾기검색 결과에서 “연결된 콘텐츠” 발견개념 키워드로 페이지 발견
입력사용자 질의검색 결과의 QA ID키워드 문자열
데이터content_combined + 벡터 임베딩핵심 엔티티 노드 + MENTIONED_IN 엣지그래프 키워드 (이름 + 임베딩) + Neptune 엔티티

이러한 검색 방식들은 에이전트가 Search MCP 도구를 통해 함께 사용합니다:

  • search___summarize — 문서 하이브리드 검색
  • search___graph_traverse — 검색 결과 QA ID 기반 그래프 탐색
  • search___graph_keyword — LanceDB 그래프 키워드를 통한 키워드 유사도 검색

Step Functions Workflow
→ Distributed Map (max 30 concurrency)
→ SegmentAnalyzer
→ Parallel:
+- AnalysisFinalizer (SQS → LanceDB)
+- PageDescriptionGenerator (Haiku)
'- EntityExtractor (Haiku) → S3 (graph_entities)
→ GraphBuilder Lambda:
1. Collect entities from all segments (S3)
2. Deduplicate (exact name match)
3. Normalize → Core entities (Sonnet via Strands structured output)
4. Store core entity names in LanceDB (add_graph_keywords)
5. Save work files to S3 (entities.json, analyses.json)
→ GraphBatchSender (Map) → GraphService Lambda (VPC) → Neptune

그래프 탐색 (읽기 경로 — 검색 결과 기반)

섹션 제목: “그래프 탐색 (읽기 경로 — 검색 결과 기반)”
Agent → MCP Gateway → Search MCP Lambda (graph_traverse)
→ GraphService Lambda (VPC): search_graph (entity traversal from qa_ids)
→ LanceDB Service Lambda: Segment content retrieval
→ Bedrock Claude Haiku: Result summarization

키워드 그래프 검색 (읽기 경로 — 키워드 기반)

섹션 제목: “키워드 그래프 검색 (읽기 경로 — 키워드 기반)”
Agent → MCP Gateway → Search MCP Lambda (graph_keyword)
→ LanceDB Service: search_graph_keywords (embedding similarity)
→ SHA256 hash entity names → Neptune entity ~id
→ GraphService Lambda (VPC): raw_query (find connected qa_ids)
→ LanceDB Service: get_by_qa_ids (content retrieval)
→ Bedrock Claude Haiku: Result summarization
Frontend → Backend API → GraphService Lambda (VPC)
→ get_entity_graph: Project-wide entity graph
→ get_document_graph: Document-level detailed graph

Neptune에 저장되는 노드 및 관계 구조입니다. 쿼리 언어로 openCypher를 사용합니다.

노드설명주요 속성
Document문서id, project_id, workflow_id, file_name, file_type
Segment문서 페이지/섹션id, project_id, workflow_id, document_id, segment_index
AnalysisQA 분석 결과id, project_id, workflow_id, document_id, segment_index, qa_index, question
Entity핵심 엔티티 (정규화됨)id, project_id, name
관계방향설명
BELONGS_TOSegment → Document세그먼트가 문서에 속함
BELONGS_TOAnalysis → Segment분석이 세그먼트에 속함
NEXTSegment → Segment페이지 순서 (다음 세그먼트)
MENTIONED_INEntity → Analysis엔티티가 특정 QA에서 언급됨 (confidence, context)
RELATED_TODocument → Document수동 문서 간 연결 (reason, label)

Neptune은 보조 인덱스를 지원하지 않으므로, 노드의 ~id 속성이 유일한 O(1) 직접 조회 메커니즘입니다. 각 노드 유형의 ID는 의미 있는 복합 키로 설계되어, 인덱스 없이도 빠른 조회가 가능합니다.

노드ID 형식예시
Document{document_id}doc_abc123
Segment{workflow_id}_{segment_index:04d}wf_abc123_0042
Analysis{workflow_id}_{segment_index:04d}_{qa_index:02d}wf_abc123_0042_00
EntitySHA256({project_id}:{name})의 앞 16자a1b2c3d4e5f6g7h8
  • Segment/Analysis: 워크플로 ID + 세그먼트 인덱스 (+ QA 인덱스)로 구성되어, ID만으로 상위 관계를 추론할 수 있음
  • Entity: 프로젝트 ID + 정규화된 이름의 해시를 사용하므로, 여러 세그먼트에서 추출된 동일 엔티티가 자연스럽게 하나의 노드로 병합(MERGE)됨
Document (report.pdf)
├── Segment (page 0) ──NEXT──→ Segment (page 1) ──NEXT──→ ...
│ └── Analysis (QA 0) ←──MENTIONED_IN── Entity ("Prototyping")
│ └── Analysis (QA 1) ←──MENTIONED_IN── Entity ("AWS")
└── Segment (page 1)
└── Analysis (QA 0) ←──MENTIONED_IN── Entity ("Prototyping")
└── Analysis (QA 0) ←──MENTIONED_IN── Entity ("Innovation Flywheel")

핵심 엔티티 “Prototyping”은 페이지 0의 “Prototype”과 페이지 1의 “AWS Prototyping”에서 정규화되었기 때문에 페이지 0과 1을 연결합니다.


항목
Cluster IDidp-v2-neptune
Engine Version1.4.1.0
Instance Classdb.serverless
Capacitymin: 1 NCU, max: 2.5 NCU
SubnetPrivate Isolated
AuthenticationIAM Auth (SigV4)
Port8182
Query LanguageopenCypher

Neptune과 직접 통신하는 게이트웨이 Lambda입니다. Neptune 엔드포인트에 접근하기 위해 VPC(Private Isolated Subnet) 내부에 배포됩니다.

항목
Function Nameidp-v2-graph-service
RuntimePython 3.14
Timeout5 min
VPCPrivate Isolated Subnet
AuthenticationIAM SigV4 (neptune-db)

지원 액션:

카테고리액션설명
Writeadd_segment_linksDocument + Segment 노드, BELONGS_TO/NEXT 관계 생성
add_analysesAnalysis 노드 생성, Segment에 대한 BELONGS_TO
add_entitiesEntity 노드 MERGE, Analysis에 대한 MENTIONED_IN
link_documentsDocument 간 양방향 RELATED_TO 생성
unlink_documentsDocument 간 RELATED_TO 삭제
delete_analysisAnalysis 노드 삭제 + 고아 Entity 정리
delete_by_workflow워크플로의 모든 그래프 데이터 삭제
Readsearch_graphQA ID 기반 그래프 탐색 (Entity → MENTIONED_IN → 관련 Segment)
raw_query임의의 openCypher 쿼리 실행 (파라미터 포함)
get_entity_graph프로젝트 전체 엔티티 그래프 조회 (시각화용)
get_document_graph문서 수준 상세 그래프 조회 (시각화용)
get_linked_documents문서 연결 관계 조회

3. EntityExtractor Lambda (Step Functions)

섹션 제목: “3. EntityExtractor Lambda (Step Functions)”

Distributed Map 내부에서 AnalysisFinalizer, PageDescriptionGenerator와 병렬로 실행됩니다.

항목
Function Nameidp-v2-entity-extractor
RuntimePython 3.14
Timeout5 min
ModelBedrock Haiku 4.5
OutputStructured (Pydantic model)
StackWorkflowStack

특징:

  • Structured output을 사용하여 AI 분석 결과에서 엔티티 추출
  • 테스트 모드 (mode: "test") 지원 — S3에 저장하지 않고 엔티티를 반환 (프롬프트 튜닝용)
  • S3 세그먼트 데이터에 graph_entities 저장

Distributed Map 완료 후, DocumentSummarizer 이전에 실행됩니다.

항목
Function Nameidp-v2-graph-builder
RuntimePython 3.14
Timeout15 min
StackWorkflowStack

처리 흐름:

  1. Document + Segment 구조 생성 — Neptune에 문서/세그먼트 노드와 BELONGS_TO, NEXT 관계 생성
  2. S3에서 세그먼트 분석 결과 로드 — 모든 세그먼트의 분석 데이터 수집
  3. Analysis 노드 생성 — QA 쌍별로 Analysis 노드 일괄 생성
  4. 엔티티 수집 — EntityExtractor가 세그먼트별로 이미 추출한 graph_entities 수집
  5. 중복 제거 — 이름이 동일한 엔티티 병합 (대소문자 무시)
  6. 정규화 → 핵심 엔티티 — LLM이 관련 엔티티를 느슨하게 그룹화 (표기 변형, 형태소 변형, 개념적 포함 관계). 하나의 엔티티가 여러 핵심 엔티티 그룹에 속할 수 있음. 핵심 엔티티는 멤버의 mentioned_in 목록을 흡수
  7. LanceDB에 핵심 엔티티 이름 저장 — 문서 간 키워드 검색을 위한 add_graph_keywords
  8. S3에 작업 파일 저장 — GraphBatchSender를 위한 entities.jsonanalyses.json

AI 에이전트가 사용하는 그래프 검색 도구로, Search MCP Lambda에 통합되어 있습니다.

항목
StackMcpStack
RuntimeNode.js 22.x (ARM64)
Timeout5 min

도구:

MCP 도구설명
graph_traverse검색 결과 QA ID를 시작점으로 그래프를 탐색하여 관련 페이지 발견
graph_keywordLanceDB에서 키워드 유사도로 핵심 엔티티를 검색한 후, Neptune을 통해 연결된 페이지 탐색

graph_traverse 흐름:

1. Receive qa_ids from search___summarize results
2. QA ID → Analysis node → MENTIONED_IN ← Entity node (all entities, no limit)
3. Entity → MENTIONED_IN → Other Analysis → Segment (single UNWIND query)
4. Exclude source segments, filter by document_id
5. Fetch segment content from LanceDB (get_by_segment_ids)
6. Summarize with Bedrock Claude Haiku
7. Filter sources to only Haiku-cited segments

graph_keyword 흐름:

1. Receive keyword query
2. Search LanceDB graph_keywords by embedding similarity (top 3)
3. Hash matched entity names → Neptune entity ~id (SHA256)
4. Query Neptune: Entity → MENTIONED_IN → Analysis (get qa_ids)
5. Fetch content from LanceDB (get_by_qa_ids)
6. Summarize with Bedrock Claude Haiku

엔티티 추출은 EntityExtractor Lambda에서 실행되며, AnalysisFinalizer 및 PageDescriptionGenerator와 함께 세그먼트별로 병렬 처리됩니다. Step Functions의 Distributed Map 내부에서 실행되므로, 최대 30개 세그먼트가 동시에 엔티티를 추출합니다.

안정적인 JSON 응답을 위해 Strands Agent와 Pydantic structured output을 사용합니다.

항목
ModelBedrock Haiku 4.5
FrameworkStrands SDK (Agent + structured_output_model)
Input세그먼트 AI 분석 결과 + 페이지 설명
Outputentities[] (Pydantic EntityExtractionResult)

모든 세그먼트 처리 완료 후, GraphBuilder가 LLM을 사용하여 엔티티를 정규화합니다:

항목
ModelBedrock Sonnet 4.6 (1M context)
FrameworkStrands SDK (Agent + structured_output_model)
Input모든 중복 제거된 엔티티 (컨텍스트 포함) + 기존 LanceDB 키워드
Output핵심 엔티티 그룹 (NormalizationResult)

정규화 규칙:

  • 느슨하게 그룹화 — 연결을 놓치는 것보다 과연결이 나음
  • 표기 변형 (띄어쓰기, 구두점, 약어)
  • 형태소 변형 (단수/복수, 동사/명사 형태)
  • 개념적 포함 (특정 용어가 더 넓은 개념을 포함)
  • 다국어 변형
  • 하나의 엔티티가 여러 핵심 그룹에 속할 수 있음
  • 핵심 엔티티 이름은 멤버 이름 또는 널리 알려진 표준 용어 사용
{
"entities": [
{
"name": "AWS Prototyping",
"mentioned_in": [
{
"segment_index": 1,
"qa_index": 0,
"context": "AWS prototyping program and methodology"
}
]
}
]
}
Input entities: Prototype (page 0), AWS Prototyping (page 1), AWS (page 0), Amazon Web Services (page 1)
Core entities:
- "Prototyping" → [Prototype, AWS Prototyping] → connected to pages 0, 1
- "AWS" → [AWS, Amazon Web Services, AWS Prototyping] → connected to pages 0, 1

// Neptune DB Serverless Cluster
const cluster = new neptune.CfnDBCluster(this, 'NeptuneCluster', {
dbClusterIdentifier: 'idp-v2-neptune',
engineVersion: '1.4.1.0',
iamAuthEnabled: true,
serverlessScalingConfiguration: {
minCapacity: 1,
maxCapacity: 2.5,
},
});
// Serverless Instance
const instance = new neptune.CfnDBInstance(this, 'NeptuneInstance', {
dbInstanceClass: 'db.serverless',
dbClusterIdentifier: cluster.dbClusterIdentifier!,
});
VPC (10.0.0.0/16)
└─ Private Isolated Subnet
├─ Neptune DB Serverless (port 8182)
└─ GraphService Lambda (SG: VPC CIDR → 8182 allowed)

GraphService Lambda만 VPC 내부에 배포됩니다. GraphBuilder Lambda와 Search MCP Lambda는 VPC 외부에서 Lambda invoke를 통해 GraphService를 호출합니다.

설명
/idp-v2/neptune/cluster-endpointNeptune 클러스터 엔드포인트
/idp-v2/neptune/cluster-portNeptune 클러스터 포트
/idp-v2/neptune/cluster-resource-idNeptune 클러스터 리소스 ID
/idp-v2/neptune/security-group-idNeptune 보안 그룹 ID
/idp-v2/graph-service/function-arnGraphService Lambda 함수 ARN

graph TB
    subgraph Build["Graph Build (Step Functions)"]
        EE["EntityExtractor<br/>(Entity Extraction)"]
        GB["GraphBuilder<br/>(Normalization + Core Entities)"]
    end

    subgraph Search["Graph Search (Agent)"]
        GT["graph_traverse<br/>(Search MCP)"]
        GK["graph_keyword<br/>(Search MCP)"]
    end

    subgraph Viz["Graph Visualization (Frontend)"]
        BE["Backend API"]
    end

    subgraph Core["Core Service (VPC)"]
        GS["GraphService Lambda"]
    end

    subgraph Storage["Storage Layer"]
        Neptune["Neptune DB Serverless"]
        LanceDB["LanceDB (graph_keywords)"]
    end

    EE -->|"S3<br/>(graph_entities)"| GB
    GB -->|"invoke<br/>(add_entities)"| GS
    GB -->|"invoke<br/>(add_graph_keywords)"| LanceDB
    GT -->|"invoke<br/>(search_graph)"| GS
    GK -->|"invoke<br/>(search_graph_keywords)"| LanceDB
    GK -->|"invoke<br/>(raw_query)"| GS
    BE -->|"invoke<br/>(get_entity_graph, get_document_graph)"| GS

    GS -->|"openCypher<br/>(IAM SigV4)"| Neptune

    style Storage fill:#fff3e0,stroke:#ff9900
    style Core fill:#e8f5e9,stroke:#2ea043
    style Build fill:#fce4ec,stroke:#e91e63
    style Search fill:#e3f2fd,stroke:#1976d2
    style Viz fill:#f3e5f5,stroke:#7b1fa2
컴포넌트Stack접근 유형설명
GraphServiceWorkflowStackRead/Write핵심 Neptune 게이트웨이 (VPC 내부)
EntityExtractorWorkflowStackWrite (S3)세그먼트별 엔티티 추출 (병렬)
GraphBuilderWorkflowStackWrite (GraphService + LanceDB 경유)핵심 엔티티 정규화 + 그래프 구축
graph_traverseMcpStackRead (GraphService + LanceDB 경유)에이전트 검색 결과 기반 그래프 탐색
graph_keywordMcpStackRead (LanceDB + GraphService 경유)에이전트 키워드 기반 그래프 검색
Backend APIApplicationStackRead (GraphService 경유)프론트엔드 그래프 시각화