N_14. CONSTRUCT 를 이용한 RDF 파일 생성
SPARQL 질의문에는 SELECT 이외에도 ASK, DESCRIBE, CONSTRUCT 구문이 있다.
지난 포스팅에서 엑셀 데이터를 스프레드시트 온톨로지로 임포트하는 방법에 대해 소개하였다.
https://joyhong.tistory.com/88
이 방법으로 임포트를 하게 되면 스프레드시트 온톨로지 라는 모델에 엑셀의 셀 값 들이 들어가게 되는데
내가 원하는 모델 구조로 만들기 위해서는 CONSTRUCT 구문을 사용하여 추출하면 된다.
CONSTRUCT 구문은
CONSTRUCT { 변수명 } WHERE { 조건 }
형태로 작성하게 된다.
그럼 지난 포스팅에 의해 생성된 스프레드시트 온톨로지에 내가 원하는 구조로 추출하는 쿼리를 작성해보자.
이 작업을 위해서는 BIND, FILTER, IF, VALUES 등의 구문을 이해하고 있으면 편하게 수행할 수 있다.
VALUES 키워드는 https://joyhong.tistory.com/87
포스팅에서 설명을 한 적이 있다.
스프레드시트 온톨로지에서 데이터를 추출하기 위해서는 행 번호와 열 번호를 지정하여 원하는 값들을 가져오면 된다.
여기서는 전체 컬럼에 대해서 추출하지 않고 일부 선택적으로만 추출하고자 한다.
추출하는 쿼리는 아래와 같다.
PREFIX ex: <http://test.com/resource/> PREFIX ep: <http://test.com/property/> CONSTRUCT { ?subject ?predicate ?object } WHERE { ?s ss:column ?col. ?s ss:cellContents ?cont. BIND(replace(?cont, '"', '') as ?value) FILTER(strlen(?value)>0) ?s ss:row ?row. FILTER(?row != 0) VALUES (?col ?predicate ?tag){ (0 rdfs:label "s") (0 rdf:type "t") (1 ep:sido "" ) (2 ep:sigungu "") (3 ep:libraryType "s") (4 ep:closed "s") (5 ep:startTime "s") (6 ep:endTime "s") (11 ep:seat "i") (17 ep:address "s") (19 ep:tel "s") (22 ep:homepage "s") } BIND( IF(?tag='s', ?value, IF(?tag='i', STRDT(?value, xsd:integer), IF(?tag='t', IRI(concat(str(ex:),'Library')), IRI(concat(str(ex:),?value))))) as ?object) BIND(IRI(concat(str(ex:),'library_',str(?row))) as ?subject) } |
?s ss:column ?col. 패턴으로 컬럼 번호를 가져오고
?s ss:cellContents ?cont. 패턴으로는 실제 셀에 들어있는 데이터 값을 가져온다.
이 때 BIND와 FILTER를 통해 쌍따옴표는 제거하고 실제 데이터 값이 공백이 아닌 것들에 대해서만 가져오도록 했다.
?s ss:row ?row. 패턴으로 행 번호를 가져오는데 첫번째(0번) 행은 제목행이기 때문에 FILTER로 제외시켰다.
다음으로는 VALUES 키워드를 통해 컬럼번호에 매칭되는 predicate를 지정하였고 해당 값의 유형을 구분하기 위해 tag 값을 추가하였다.
VALUES (?col ?predicate ?tag)
여기서 predicate는 나중에 결과로 추출한 트리플의 predicate로 사용된다.
tag는 predicate에 연결되는 object값이 IRI인지 Literal인지를 구분하기 위해서 구분값을 지정한 것이고
동시에 xsd:datatype을 주기 위해서도 사용하기 위해 정의한 것이다.
(0 rdfs:label "s")는 0번 컬럼을 rdfs:label로 매핑하고 구분값으로 "s" 태그를 붙인 것이다.
(0 rdf:type "t") 는 rdf:type 을 매핑하기 위해 "t" 태그를 붙인 것이다. 여기서 컬럼 번호는 의미가 없다.
(1 ep:sido "" )는 1번 컬럼을 ep:sido로 매핑하고 구분값으로 "" 태그를 붙인 것이다.
이렇게 하나의 컬럼에 매핑하는 predicate 값들을 지정한 뒤
BIND( IF(?tag='s', ?value,
IF(?tag='i', STRDT(?value, xsd:integer),
IF(?tag='t', IRI(concat(str(ex:),'Library')), IRI(concat(str(ex:),?value))))) as ?object)
부분에서 태그가 "s"이면 Literal 값으로 ?object 변수로 바인딩, 그렇지 않으면 다시 다음 IF 구문을 통해서 분기시키게 된다.
다음 IF 구문에서 태그가 "i" 이면 Literal 값으로 만들되 데이터타입을 xsd:integer로 바인딩 시키고
그렇지 않으면 다음 IF 구문을 수행한다.
다음 IF구문에서 태그가 "t"이면 Library 라는 Resource로 바인딩하고 그렇지 않으면 IRI를 통해 실제값을 Resource로서 ?object 변수에 바인딩하도록 하였다.
마지막으로
BIND(IRI(concat(str(ex:),'library_',str(?row))) as ?subject) 를 통해 추출할 subject를 바인딩 시켰다.
SPARQL을 실행시키기 위해서는 SPARQL 입력한 부분에서 Shift+Enter를 누르거나
위 그림에서 오른쪽 부분에 Play 모양의 아이콘을 선택하면 된다.
결과는 아래의 그림과 같다.
위와 같이 결과가 오른쪽에 나오게 되는데 이 내용을 파일로 저장하기 위해서는 결과화면 위쪽에 있는 저장 아이콘을 선택한다.
파일을 저장하기 위해 적절한 디렉토리와 파일명을 입력하고 저장을 누른다.
저장을 누르면 Base URI를 무엇으로 생성할 지를 묻는 창이 나온다.
적당한 Base URI를 입력하고 OK를 누르면 전 단계에서 선택한 디렉토리에 ttl 파일이 생성되게 된다.
텍스트 편집로 파일을 확인해보면 CONSTRUCT 구문으로 지정한 predicate로 생성된 것을 확인할 수 있다.
TBC로 이 파일을 열게 되면 ex:Library이라는 것을 생성을 했지만 이것이 클래스인지와 클래스 구조를 생성하지 않았기 때문에 클래스영역에서 보이지 않는 것을 볼 수 있다.
그럴 때는 owl:Thing 클래스 하위로 ex:Library 클래스를 생성하여 명시해 주면 된다.
그러면 3193개의 Library 인스턴스가 있다는 것을 확인할 수 있다.
지금까지 엑셀의 데이터를 스프레드시트 온톨로지로 임포트하고 그 온톨로지에 들어있는 데이터를 내가 원하는 구조로 추출하여 파일로 저장하는 단계를 진행해보았다.
다음으로는 이 파일을 RDF 저장과 질의를 위한 Jena 컴포넌트 중의 하나인 TDB에 임포트 하는 방법에 대해서 살펴볼 예정이다.