시간이 흐르면 사실도 변한다: RDF Reification으로 맥락 기록하기
by Justin Kim
1. 김철수의 이직 기록
Knowledge Graph를 구축하다 보면, 시간의 흐름에 따라 변하는 사실을 기록해야 하는 순간이 반드시 찾아옵니다. 간단한 예를 들어보겠습니다.
김철수는 2020년부터 2022년까지 삼성전자에서 근무했고, 2023년부터 현재까지 네이버에서 근무하고 있다.
사람이 읽으면 명확합니다. 하지만 이것을 RDF 트리플로 표현하면 어떻게 될까요?
ex:김철수 ex:worksAt ex:삼성전자 .
ex:김철수 ex:worksAt ex:네이버 .
이 두 트리플만 보면 다음과 같은 질문에 답할 수 없습니다.
- 김철수는 지금 어디에서 일하는가?
- 삼성전자에는 언제부터 언제까지 다녔는가?
- 두 회사에 동시에 다닌 것인가, 순서대로 다닌 것인가?
이 문제의 핵심은, RDF 트리플이 주어(Subject) – 술어(Predicate) – 목적어(Object)의 세 요소만으로 구성되어 있어 “언제”, “누가 말했는지”, “확실한가” 같은 맥락(Context)을 붙일 자리가 없다는 점입니다.
2. 우회로는 왜 안 되는가?
Reification을 알기 전에, 흔히 시도하는 우회 방법들이 왜 실패하는지 먼저 살펴봅시다.
2.1 술어에 시간을 녹이기
ex:김철수 ex:worksAt_2020_2022 ex:삼성전자 .
ex:김철수 ex:worksAt_2023_now ex:네이버 .
연도를 술어(Predicate) 이름에 포함시키면 되지 않을까요? 기술적으로는 동작하지만, SPARQL로 질의할 수가 없습니다. “김철수가 근무한 모든 회사”를 찾으려면 ex:worksAt로 시작하는 술어를 전부 패턴 매칭해야 하는데, 이는 표준 SPARQL이 지원하지 않는 방식입니다. 술어의 이름 자체가 데이터가 되어 버리면, 온톨로지의 스키마와 인스턴스가 뒤섞여 관리가 불가능해집니다.
2.2 리터럴에 날짜 병기
ex:김철수 ex:worksAt "삼성전자 (2020-2022)" .
목적어를 URI 대신 문자열 리터럴로 바꾸고, 날짜를 같이 넣는 방법입니다. 이렇게 하면 ex:삼성전자라는 자원과의 연결이 끊어집니다. “삼성전자에 근무하는 모든 사람”을 찾으려면 문자열 파싱을 해야 하고, 삼성전자라는 개체에 연결된 다른 정보(위치, 업종 등)에 접근할 수 없게 됩니다. 의미(Semantics)가 문자열 안에 갇혀 버리는 것입니다.
2.3 중간 노드 만들기 (N-ary Relation)
ex:김철수 ex:hasEmployment ex:Employment_1 .
ex:Employment_1 ex:company ex:삼성전자 ;
ex:startDate "2020-01-01"^^xsd:date ;
ex:endDate "2022-12-31"^^xsd:date .
이 방법은 실무에서 자주 사용되며, 실제로 잘 동작합니다. 하지만 원래의 worksAt라는 직관적인 관계가 사라지고, hasEmployment → company라는 2-hop 경로로 대체됩니다. 이는 기존 온톨로지와의 호환성을 깨뜨리고, “김철수가 근무하는 회사”라는 단순한 질문에도 중간 노드를 경유하는 복잡한 쿼리가 필요해집니다.
세 가지 시도 모두 한계를 가지는 이유는 근본적으로 같습니다. 트리플 자체에 대한 메타데이터를 트리플 구조 안에서 표현하려 하기 때문입니다. 여기서 Reification이 등장합니다.
| 우회 방법 | 문제점 |
|---|---|
| 술어에 시간 포함 | SPARQL 질의 불가, 스키마/인스턴스 혼재 |
| 리터럴에 날짜 병기 | 자원 연결 단절, 의미 소실 |
| 중간 노드 (N-ary) | 원래 관계 소실, 쿼리 복잡화 |
3. Reification: 트리플에 대해 말하기
Reification(구체화)은 하나의 트리플을 그 자체로 하나의 자원(Resource)으로 만드는 기법입니다. 쉽게 말해, “김철수가 삼성전자에서 근무한다”라는 진술(Statement) 자체에 이름을 붙여, 그 진술에 대해 추가적인 설명을 할 수 있게 하는 것입니다.
RDF[1]에서는 이를 위해 네 가지 어휘를 제공합니다.
| 어휘 | 역할 |
|---|---|
rdf:Statement |
“이것은 하나의 진술이다”라는 타입 선언 |
rdf:subject |
원래 트리플의 주어를 가리킴 |
rdf:predicate |
원래 트리플의 술어를 가리킴 |
rdf:object |
원래 트리플의 목적어를 가리킴 |
즉, 원래 트리플 ex:김철수 ex:worksAt ex:삼성전자를 다음과 같이 “풀어서” 표현합니다.
ex:stmt1 a rdf:Statement ;
rdf:subject ex:김철수 ;
rdf:predicate ex:worksAt ;
rdf:object ex:삼성전자 .
이제 ex:stmt1은 하나의 자원이므로, 여기에 시간 정보를 자유롭게 붙일 수 있습니다.
ex:stmt1 ex:startDate "2020-01-01"^^xsd:date ;
ex:endDate "2022-12-31"^^xsd:date ;
ex:source ex:HR_Database .
핵심을 정리하면 이렇습니다. 기본 트리플은 사실을 진술합니다. Reification은 그 진술 자체를 자원으로 만들어, 진술에 대한 진술을 가능하게 합니다. 이것이 “트리플에 대해 말하기”의 본질입니다.
4. 김철수의 이직 기록: Reification 적용
이제 처음의 문제를 Reification으로 완전히 해결해 보겠습니다.
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix ex: <http://example.org/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
# ── 개체 정의 ──
ex:김철수 a ex:Person ;
ex:name "김철수" .
ex:삼성전자 a ex:Company ;
ex:name "삼성전자" .
ex:네이버 a ex:Company ;
ex:name "네이버" .
# ── 진술 1: 삼성전자 근무 (2020–2022) ──
ex:stmt1 a rdf:Statement ;
rdf:subject ex:김철수 ;
rdf:predicate ex:worksAt ;
rdf:object ex:삼성전자 ;
ex:startDate "2020-01-01"^^xsd:date ;
ex:endDate "2022-12-31"^^xsd:date ;
ex:source ex:HR_Database ;
ex:status "과거" .
# ── 진술 2: 네이버 근무 (2023–현재) ──
ex:stmt2 a rdf:Statement ;
rdf:subject ex:김철수 ;
rdf:predicate ex:worksAt ;
rdf:object ex:네이버 ;
ex:startDate "2023-03-01"^^xsd:date ;
ex:source ex:HR_Database ;
ex:status "현재" .
이제 처음의 세 가지 질문에 모두 답할 수 있습니다.
| 질문 | SPARQL 조건 | 답변 |
|---|---|---|
| 지금 어디에서 일하는가? | ?s ex:status "현재" 필터 |
네이버 |
| 삼성전자에는 언제까지? | stmt1의 ex:endDate 조회 |
2022-12-31 |
| 동시 근무인가? | startDate/endDate 비교 |
순차 근무 (기간 겹침 없음) |
5. 시각화: Reification이 만드는 구조
아래 다이어그램은 Reification이 적용된 김철수의 이직 기록을 시각화한 것입니다. 각 진술(Statement)이 하나의 자원으로 존재하며, 원래 트리플의 주어·술어·목적어를 가리키는 동시에 시간 정보를 품고 있는 구조를 보여줍니다.
진술 1(stmt1)과 진술 2(stmt2)가 각각 독립된 자원으로 존재하면서, rdf:subject, rdf:predicate, rdf:object로 원래 트리플의 구성 요소를 가리킵니다. 그리고 각 진술에 startDate, endDate, status 같은 시간 메타데이터가 자연스럽게 달려 있습니다.
6. SPARQL로 질의하기
Reification된 데이터는 표준 SPARQL로 자연스럽게 질의할 수 있습니다. 예를 들어 “김철수가 현재 근무하는 회사”를 찾으려면 다음과 같이 작성합니다.
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX ex: <http://example.org/>
SELECT ?company WHERE {
?stmt a rdf:Statement ;
rdf:subject ex:김철수 ;
rdf:predicate ex:worksAt ;
rdf:object ?company ;
ex:status "현재" .
}
결과는 ex:네이버입니다. 중간 노드 방식(2.3절)에서 필요했던 2-hop 경로와 달리, 원래 트리플의 의미(worksAt)가 rdf:predicate로 명시적으로 보존되어 있으므로 온톨로지의 의미 구조가 유지됩니다.
“2021년 기준으로 김철수가 재직 중이던 회사”처럼 시간 범위 질의도 가능합니다.
SELECT ?company WHERE {
?stmt a rdf:Statement ;
rdf:subject ex:김철수 ;
rdf:predicate ex:worksAt ;
rdf:object ?company ;
ex:startDate ?start ;
ex:endDate ?end .
FILTER (?start <= "2021-06-01"^^xsd:date && ?end >= "2021-06-01"^^xsd:date)
}
7. Reification의 비용과 현대적 대안
7.1 트리플 폭발 문제
Reification은 강력하지만, 하나의 트리플을 표현하기 위해 최소 4개의 트리플(rdf:type, rdf:subject, rdf:predicate, rdf:object)이 필요합니다. 시간 정보까지 더하면 6~7개가 됩니다. 원본 트리플 1개 당 7배의 저장 공간을 소비하는 셈입니다.
| 표현 방식 | 트리플 수 (진술 1개당) |
|---|---|
| 기본 트리플 | 1 |
| Reification (구조만) | 4 |
| Reification + 시간 메타데이터 | 6–7 |
대규모 Knowledge Graph에서 모든 트리플을 Reify하면 저장 공간과 쿼리 성능에 부담을 줄 수 있습니다. 따라서 시간에 따라 변하거나 출처 추적이 필요한 트리플만 선택적으로 Reify하는 것이 실무적인 접근입니다.
7.2 RDF-star: 간결한 대안
이러한 트리플 폭발 문제를 해결하기 위해 RDF-star[2]가 제안되었습니다. RDF-star에서는 트리플을 중첩(Nesting)하여 직접 메타데이터를 붙일 수 있습니다.
<< ex:김철수 ex:worksAt ex:삼성전자 >>
ex:startDate "2020-01-01"^^xsd:date ;
ex:endDate "2022-12-31"^^xsd:date .
<< ... >> 안에 원래 트리플을 넣고, 바로 그 트리플에 대한 속성을 추가합니다. 내부적으로는 Reification과 동일한 의미를 가지지만, 문법이 훨씬 간결하고 트리플 수도 줄어듭니다. RDF-star는 W3C의 RDF 1.2 표준에 반영되어, 기존 Reification의 실질적인 후속 기법으로 자리 잡아가고 있습니다.
8. 마치며
RDF 트리플은 “무엇이 어떻다”라는 사실을 간결하게 표현하는 데 최적화되어 있습니다. 하지만 현실 세계의 사실은 항상 맥락을 동반합니다. 언제 그랬는지, 누가 그렇게 말했는지, 얼마나 확실한지. Reification은 이 맥락을 RDF의 틀 안에서 표현하는 표준적인 방법입니다.
시간에 따라 변하는 데이터를 다룰 때, 기본 트리플의 한계에 부딪혔다면 Reification을 떠올려 보세요. 트리플 하나하나가 “자원”이 되는 순간, Knowledge Graph는 비로소 시간의 흐름을 기록할 수 있게 됩니다.
관련 글
참고 문헌
- R. Cyganiak, D. Wood, and M. Lanthaler, “RDF 1.1 Concepts and Abstract Syntax,” W3C, W3C Recommendation, Feb. 2014. Available at: https://www.w3.org/TR/rdf11-concepts/</span>
- R. Cyganiak, D. Wood, M. Lanthaler, O. Hartig, and P.-A. Champin, “RDF 1.2 Concepts and Abstract Syntax,” W3C, W3C Working Draft, 2024. Available at: https://www.w3.org/TR/rdf12-concepts/</span>
Subscribe via RSS
Comments