지식그래프에서 스키마는
지식그래프의 구조와 의미를 정의하는 역할을 합니다.
스키마에는 다음과 같은 정보가 포함됩니다.
엔티티: 지식그래프에서 표현하는 개체를 나타냅니다.
속성: 엔티티가 가지고 있는 특성을 나타냅니다.
관계: 엔티티 간의 관계를 나타냅니다.
스키마는 지식그래프의 데이터를 이해하고 처리하는 데 필수적입니다.
스키마가 없으면 지식그래프에 저장된 데이터의 의미를 파악하기 어렵습니다.
또한, 스키마를 통해 지식그래프의 구조를 정리하고 효율적으로 관리할 수 있습니다.
스키마의 주요 역할
- 지식그래프의 구조와 의미를 정의: 스키마는 지식그래프에 포함된 엔티티, 속성, 관계의 종류와 의미를 정의합니다.
이를 통해 지식그래프의 데이터를 이해하고 처리할 수 있습니다. - 지식그래프의 데이터를 정리: 스키마를 통해 지식그래프의 데이터를 체계적으로 정리할 수 있습니다.
이를 통해 데이터의 중복을 제거하고, 데이터를 효율적으로 관리할 수 있습니다. - 지식그래프의 확장과 발전을 지원: 스키마를 통해 지식그래프를 확장하고 발전시킬 수 있습니다.
새로운 엔티티, 속성, 관계를 추가하거나 기존의 엔티티, 속성, 관계의 의미를 변경할 수 있습니다.
스키마 예시
영화 지식그래프
영화 지식그래프는 영화, 배우, 감독, 장르와 같은 엔티티와 그 간의 관계를 표현하는 지식그래프 입니다.
엔티티
* 영화
* 배우
* 감독
* 장르
속성
* 영화: 제목, 장르, 개봉일, 평점
* 배우: 이름, 나이, 국적
* 감독: 이름, 출생년도, 출생지
* 장르: 이름, 설명
관계
* 영화 - 감독: 감독이 연출한 영화
* 영화 - 배우: 배우가 출연한 영화
* 영화 - 장르: 영화의 장르
스키마를 작성하려면 RDF표현하는 방식에 대해서 알아야 합니다.
RDF를 표현하는 방식에는 여러가지가 있습니다.
N-Triples, Turtle, RDF/XML, json-ld 등이 있으며 그 중 Turtle에 대해서 알아보도록 하겠습니다.
Turtle?
약자 : Terse RDF Triple Language → TTL인데 발음을 티티엘 → 티틀 → 터틀로 진화한거 같습니다..ㅋㅋ
특징 : RDF데이터 모델에서 데이터를 표현하기 위한 구문 및 파일형식 입니다.
Turtle syntax는 SPARQL과 유사 합니다.
RDF 데이터를 저장하기 위한 일반적인 데이터 형식입니다.
파일 확장자는 .ttl
ex) 영화 엔티티를 가지고 예제를 보겠습니다.
movie.ttl
# 영화
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://example.com/movie/1> a rdf:Resource ;
rdfs:label "서울의 봄" ;
rdf:type <http://example.com/type/movie> ;
<http://example.com/property/year> "2023"^^xsd:integer .
@prefix는 RDF Schema를 선언하는 키워드 입니다.
rdf는 RDF 데이터를 표현하는데 사용되는 URI 입니다.
rdfs는 RDF 스키마를 확장하는데 사용되는 URI 입니다.
xsd는 XML 스키마를 확장하는데 사용되는 URI 입니다.
팁.
웹표준은 RDF를 기반으로 데이터 웹을 위한 풍부한 모델링 기능을 제공하는데, 여기에는 2가지 핵심 아이디어가 있다.
추론(inference) : 이미 알고 있는 데이터를 기반으로 결론을 도출한다. 추론은 기존데이터에서 new데이터를 만드는 방법이다.
가장 간단한 RDF의 확장인 RDFS(RDF Schema)는 설계자가 추론을 관리할 수 있다.
기대(Expectation) : 아직 본 적 없는 데이터에 대한 예측을 생성한다.
기대는 사용자로부터 데이터를 추출하거나 새로운 데이터 정보원에서 데이터를 검증할 때 유용하다.
SHACL(Shapes Constraint Language)은 설계자가 기대치를 관리할 수 있게 하는 RDFS 확장이다.
시맨틱 웹에서 추론의 대상은 평범하고 일관성있는 데이터로, 자연세계 추론관점으로 보면 사소해 보일 수 있다.
추론은 검색엔진과 같은 시나리오에 필수적이다.
ref. 온톨로지 책
문법은 RDF이니 S(subject), P(predicate), O(object) 순서로 나열하고 마지막에 마침표를 찍어서 트리플을 표현 합니다.
또한 세미콜론( ; )을 사용하여 동일한 주어를 가진 또 다른 트리플이 뒤따른다는것을 나타냅니다.
위 에제에서는
<http://example.com/movie/1>가 주어이며
a rdf에서 a는 rdf:type을 의미 합니다.
많이 사용되는 약어 입니다.
아래는 turtle 예제 입니다.
actor.ttl
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
# 배우
<http://example.com/actor/1> a rdf:Resource ;
rdfs:label "황정민" ;
rdf:type <http://example.com/type/actor> .
<http://example.com/actor/2> a rdf:Resource ;
rdfs:label "정우성" ;
rdf:type <http://example.com/type/actor> .
test.ttl
# 영화에 출연한 배우
<http://example.com/movie/1> <http://example.com/property/actor/1> _:bnode1 .
_:bnode1 <http://example.com/property/roleName> "주연" .
_:bnode1 <http://example.com/property/characterName> "전두광" .
<http://example.com/movie/1> <http://example.com/property/actor/2> _:bnode2 .
_:bnode2 <http://example.com/property/roleName> "주연" .
_:bnode2 <http://example.com/property/characterName> "이태신" .
영화 / 배우 / 영화에 출연한 배우정보를 fuseki에 넣습니다.
2024.01.18 - [OpenSource/Apache Jena] - 2. About Apache Fuseki
아래와 같이 s p o 형태로 들어가게 됩니다.
Fuseki에서 SPARQL Query를 통해 캐릭터명만 뽑아낼수 있습니다.
PREFIX property: <http://example.com/property/>
SELECT distinct ?object
WHERE {
?b0 property:characterName ?object .
}
LIMIT 25
여기서 황정민이 맡은 캐릭터이름을 뽑아내는 쿼리는 어떻게 작성할까요?
작성 전에 어떤식으로 모델링이 되어있는지 그림으로 살펴볼 필요가 있습니다.
<>는 uri이고 ""는 리터럴이라고 하고 그림을 그려보면
<characterName>과 <actor1>의 연결이 없는 상태 입니다.
어떻게 해야할까요? 이게 바로 모델링이였습니다.
어떻게 관계를 맺을지 확장을 생각하면서
아래처럼 블랭크노드(portayal)을 만들어서 actor와 actIn으로 구분하여 만들어줍니다.
기존에는 actor.ttl을 사용하지 않고 actor에 있던 "황정민", "정우성" 데이터를 블랭크 노드 밑에
캐릭터네임 즉, actIn과 동일한 depth를 가져갑니다.
# 영화
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://example.com/movie/1> a rdf:Resource ;
rdfs:label "서울의 봄" ;
rdf:type <http://example.com/type/movie> ;
<http://example.com/property/year> "2023"^^xsd:integer .
# 영화에 출연한 배우
<http://example.com/movie/1> <http://example.com/portrayal> _:bnode1 .
_:bnode1 <http://example.com/property/roleName> "주연" .
_:bnode1 <http://example.com/property/actor> "황정민" .
_:bnode1 <http://example.com/property/actIn> "전두광" .
<http://example.com/movie/1> <http://example.com/portrayal> _:bnode2 .
_:bnode2 <http://example.com/property/roleName> "주연" .
_:bnode2 <http://example.com/property/actor> "정우성" .
_:bnode2 <http://example.com/property/actIn> "이태신" .
서울의 봄에서 황정민 배우가 맡은 roleName과 actIn은?
주연과 전두광 캐릭터의 결과가 아래와 같이 나오게 됩니다.
PREFIX ksm: <http://example.com/property/>
SELECT ?roleName ?actIn
WHERE {
?s <http://example.com/portrayal> ?b0.
?b0 ksm:actor "황정민" .
?b0 ksm:actIn ?actIn .
?b0 ksm:roleName ?roleName .
}
LIMIT 25
Fuseki 결과
이렇게 데이터를 어떻게 구성하는지는 지식그래프를 데이터를 모델링하는 모델러들이 정하게 됩니다.
위와 같은 스키마는 어떻게 사용되는가??
해당 스키마를 사용하려면 먼저 parsing을 해야 합니다.
RDF 트리구조를 분석하여 스키마의 엔티티, 속성, 관계를 추출하는 과정 입니다.
<http://example.com/Person>
a owl:Class ;
rdfs:label "사람" ;
rdfs:comment "사람을 나타내는 클래스".
위의 RDF 트리의 경우,
<http://example.com/Person>은 엔티티,
a는 관계,
owl:Class는 엔티티의 종류,
rdfs:label은 엔티티의 이름,
rdfs:comment는 엔티티의 설명을 나타냅니다.
RDF를 parsing을 하면
String rdf = """
<http://example.com/Person>
a owl:Class ;
rdfs:label "사람" ;
rdfs:comment "사람을 나타내는 클래스".
""";
List<RDFNode> nodes = parseRDF(rdf);
for (RDFNode node : nodes) {
System.out.println(node.getSubject() + " " + node.getPredicate() + " " + node.getObject());
}
public static List<RDFNode> parseRDF(String rdf) {
List<RDFNode> nodes = new ArrayList<>();
String[] lines = rdf.split("\n");
for (String line : lines) {
String[] tokens = line.split(" ");
if (tokens.length == 3) {
nodes.add(new RDFNode(tokens[0], tokens[1], tokens[2]));
}
}
return nodes;
}
아래와 같이 출력이 됩니다.
<http://example.com/Person> a owl:Class
<http://example.com/Person> rdfs:label "사람"
<http://example.com/Person> rdfs:comment "사람을 나타내는 클래스"
엔티티는 <http://example.com/Person>이라고 했습니다.
이 엔티티를 추출한 후에 속성과 관계를 추출할 수 있습니다.
public class RDFParser {
private static final String RDF_TYPE = "a";
public static List<String> extractProperties(List<RDFNode> nodes) {
List<String> properties = new ArrayList<>();
for (RDFNode node : nodes) {
if (RDF_TYPE.equals(node.getPredicate())) {
properties.add(node.getObject());
}
}
return properties;
}
public static List<String> extractRelationships(List<RDFNode> nodes) {
List<String> relationships = new ArrayList<>();
for (RDFNode node : nodes) {
if (!RDF_TYPE.equals(node.getPredicate())) {
relationships.add(node.getPredicate());
}
}
return relationships;
}
public static void main(String[] args) {
String rdf = """
<http://example.com/Person>
a owl:Class ;
rdfs:label "사람" ;
rdfs:comment "사람을 나타내는 클래스".
<http://example.com/Person> rdfs:label "사람".
<http://example.com/Person> <http://example.com/friend> <http://example.com/Person>.
""";
List<RDFNode> nodes = parseRDF(rdf);
List<String> properties = extractProperties(nodes);
System.out.println("속성: " + properties);
List<String> relationships = extractRelationships(nodes);
System.out.println("관계: " + relationships);
}
}
결과로 아래와 같이 출력 됩니다.
속성: [rdfs:label]
관계: [a owl:Class rdfs:label]
다시 돌아와서 parsing을 통해 추출한 엔티티와 속성, 관계를 사용하여 지식그래프를 생성 할 수 있습니다.
또한 생성된 지식그래프를 사용하여 다음과 같은 질문에 대한 답을 할 수 있습니다.
"아이유는 누구와 친구입니까?"
SELECT ?friend
FROM <http://example.com/>
WHERE
{
<http://example.com/IU> <http://example.com/friend> ?friend .
}
위 쿼리에 대한 결과는 아래와 같습니다.
?friend
<http://example.com/BTS>
<http://example.com/Jennie>
아이유의 친구는 BTS와 Jennie
결론
RDF의 형태로 스키마를 구성하여 지식그래프의 구조와 의미를 정의하고 해당 스키마 RDF를 파싱해서 질의를 하여 답을 얻어낼수 있다.
NEXT
질의를 하는 SPARQL에 대해서 알아보자!
'역량 UP! > Knowledge Graph' 카테고리의 다른 글
4. SPARQL이란? (0) | 2024.02.29 |
---|---|
지식그래프(Knowledge Graph) 관련 정보 (0) | 2022.11.02 |
타 회사 지식그래프에 대해 알아보자 (0) | 2022.08.02 |