Jena Ontology API (2)

     




지난 포스팅에 이어 공식 홈페이지 메뉴얼을 보도록 하겠습니다. 이번엔 코드도 함께 테스트하면서요.


http://jena.apache.org/documentation/ontology/


지난시간에 list를 만드는 내용을 했었습니다. 





위에 그림을 설명하고 이해했었습니다. 하지만 코딩은 안해봤는데 이번 포스팅은 코딩을 시작으로 진행하겠습니다. 


제가 사용한 코드는 다음과 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.util.Iterator;
 
import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Resource;
 
 
public class Main {
    
 
    public static void main( String[] args ) {
        OntModel m = ModelFactory.createOntologyModel( OntModelSpec.OWL_MEM, null );
 
        String NS = "http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#";
     
        m.read( "file:c:/test.owl" );
 
        OntModel m2 = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM_MICRO_RULE_INF, m);
        
        OntClass paper = m.getOntClass(NS+ "Display");
        Individual p1 = m.createIndividual(NS+"diplay1", paper);
        
        
        for(Iterator<Resource> i = p1.listRDFTypes(false); i.hasNext();){
            System.out.println(p1.getURI() + "is asserted in class " + i.next());
        }
        
        p1 = m2.getIndividual( NS+"diplay1");
        for(Iterator<Resource> i = p1.listRDFTypes(false); i.hasNext();){
            System.out.println(p1.getURI() + "is inferred in class " + i.next());
        }
        
       
    }
 
 
}
 
 


일단 추론기능이 있는 모델과 없는 모델로 나누어서 m과 m2 모델을 만들었습니다. 그리고 m.read를 통해 온톨로지 파일을 불러왔습니다. 제가 사용한 온톨로지는 protege4.3 으로 간단하게만든 스마트폰 분류 온톨로지입니다. 뭐 대충 클래스 15개 정도가 있습니다.


NS의 경우 자신이 만든 온톨로지의 URI를 적어줍니다. protege로 만들었더니 자동적으로 URI가 저렇게 생성되었더군요. 작년 6월에 만들었습니다. 잠깐 발표용으로 ;

아무튼 파일이름은 test.owl로 저장한다음 C드라이브에 놓고 read 메소드를 통해 불러왔습니다. 모델 m에만 불러오고 모델 m2는 모델 m 을 참조해서 모델 스펙만 바꿔서 만들었습니다. m의 스펙이 OWL_MEM이고 m2의 경우는 추론기능이 포함된 OWL_MEM_MICRO_RULE_INF입니다. 모델을 다 만들고나서 온톨로지안에 있는 임의의 클래스하나를 선택합니다. 저는 Display라는 클래스를 선택했습니다. 그리고 그 클래스의 객체인 display1이라는 객체를 만들고 이 객체에 대해 다른 클래스와 관계를 출력하도록 합니다. listRDFTypes()메소드를 사용하면 해당 객체가 어느 클래스에 속해있는지 알 수 있습니다. 위 코드의 결과는 다음과 같습니다.


1
2
3
4
5
6
http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#diplay1is asserted in class http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#Display
http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#diplay1is inferred in class http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#Display
http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#diplay1is inferred in class http://www.w3.org/2002/07/owl#Thing
http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#diplay1is inferred in class http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#Spec
http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#diplay1is inferred in class http://www.w3.org/2000/01/rdf-schema#Resource
 

결과에서 첫번째 줄은 추론기능이 없는 모델에서의 결과값입니다. diplay1이라는 객체는 단순히 display에만 포함된다고 나와있습니다. 2~5번째 줄의 결과는 추론기능이 있는 모델에서의 결과값입니다. display1 객체는 display, Thing, spec, Resource 라는 클래스에 각각 포함되어 있습니다. display라는 클래스가 spec 클래스에 포함되고 spec 클래스가 Thing 클래스에 포함되기 때문에 이런 추론 결과가 나온 것입니다. 


현재 위에서 설명한 세 가지 방법중 두 가지 방법을 실행했습니다. (추론 X, 추론 O) 세번째 방법인 direct 추론 기능을 이용하려면 listPDFTypes()의 인자값을 true로 바꿔주면 됩니다. 바꿔서 실행 할 경우 다음과 같은 결과가 출력됩니다.


1
2
3
http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#diplay1is asserted in class http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#Display
http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#diplay1is inferred in class http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#Display
 


direct 추론기능을 사용할 경우 display1의 객체는 추론기능을 사용하지 않은 것과 같은 결과값이 나왔습니다. 제가 사용한 온톨로지는 간단한 모델이라 같은 결과가 나왔지만 두 가지 경우가 항상 같은 값을 출력하는 것은 아닙니다. 사용하는 모델에 따라서 조금씩 다른 결과를 추론하므로 여러 온톨로지를 대상으로 시험해 봅시다.






OntClass를 이용하여 서브클래스 출력하기


온톨로지의 클래스를 가리키는 OntClass를 활용해 서브클래스를 출력하는 코딩을 해보도록 하겠습니다. 일단 온톨로지라는 것이 Class를 중심으로 설계되는 모델이기 때문에 프로그래밍에서도 OntClass는 자주 사용되는 클래스 입니다. OntClass의 속성으로는 다음과 같은 것이 있습니다. 


AttributeMeaning
subClassA subclass of this class, i.e. those classes that are declared subClassOf this class.
superClassA super-class of this class, i.e. a class that this class is a subClassOf.
equivalentClassA class that represents the same concept as this class. This is not just having the same class extension: the class 'British Prime Minister in 2003' contains the same individual as the class 'the husband of Cherie Blair', but they represent different concepts.
disjointWithDenotes a class with which this class has no instances in common.


서브 클래스를 출력하는 코드는 생각보다 간단하게 만들 수 있었습니다. 일단 위에 코드에서 OntClass를 선언하는 부분까지는 똑같고 Iterator를 사용하는 부분에서 ListRDFTypes() 메소드 대신 다른 메소드를 사용하면 됩니다. 제가 사용한 코드는 아래와 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.util.Iterator;
 
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.rdf.model.ModelFactory;
 
 
public class Main {
    
    public static void main(String[] args){
        String NS = "http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#";
        OntModel m =  ModelFactory.createOntologyModel( OntModelSpec.OWL_MEM, null );
        m.read("file:c:/test.owl");
        
        OntClass c = m.getOntClass(NS+"Spec");
        
        
        for(Iterator<OntClass> i = c.listSubClasses(); i.hasNext();){
            OntClass c1 = i.next();
            System.out.println(c1.getURI()+"\n");
        }
    }
}
 


이번에 사용한 온톨로지 역시 스마트폰 온톨로지입니다. 이전 코드와 다른점은 Iterator에서 OntClass.ListSubClasses()를 사용했다는 점입니다. 이 코드에서는 Spec 클래스의 서브 클래스들을 나열했습니다. 결과는 다음과 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#Storage
 
http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#Motion_recognition
 
http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#Display
 
http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#Camera
 
http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#CPU
 
http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#Bettery
 
 


제가 만든 스마트폰 온톨로지에서 "Spec"으로 다루는 것들은 저장용량, 모션인식, 디스플레이, 카메라, CPU, Bettery 였습니다. 결과값을 보면 Spec의 서브클래스로 이 값들이 출력된 것을 볼 수 있습니다. ListSubClasses()메소드 역시 인자값으로 true를 넣으면 direct기능이 추가됩니다.


그리고 또 한가지 메뉴얼에서 언급된게 있는데, 온톨로지의 경우 자신은 무조건 자신의 서브클래스, 슈퍼클래스라고 생각합니다. 하지만 이런 부분이 코딩할 때 불편하기 때문에 자기자신은 제외시켰다고 하네요.






OntClass를 이용하여 객체관리


OntClass의 몇가지 메소드를 가지고 클래스에 포함된 객체들을 관리할 수 있습니다. 


MethodMeaning
listInstances()
listInstances(boolean direct)
Returns an iterator over those instances that include this class among their rdf:type values. The direct flag can be used to select individuals that are direct members of the class, rather than indirectly through the class hierarchy. Thus if p1 has rdf:type :Paper, it will appear in the iterator returned by listInstances on :Artefact, but not in the iterator returned by listInstances(false) on :Artefact.
createIndividual()
createIndividual(String uri)
Adds a resource to the model, whose asserted rdf:type is this ontology class. If no URI is given, the individual is an anonymous resource.
dropIndividual(Resource individual)Removes the association between the given individual and this ontology class. Effectively, this removes the rdf:type link between this class and the resource. Note that this is not the same as removing the individual altogether, unless the only thing that is known about the resource is that it is a member of the class. To delete an OntResource, including classes and individuals, use the remove() method.


표의 기능중에 ListInstance() 메소드를 이전에 했던 코드에 끼워 넣어서 실행해 보았습니다. Spec 클래스에 마땅히 객체가 없었기 때문에 Display 클래스로 실험했습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.Iterator;
 
import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.rdf.model.ModelFactory;
 
 
public class Main {
    
    public static void main(String[] args){
        String NS = "http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#";
        OntModel m =  ModelFactory.createOntologyModel( OntModelSpec.OWL_MEM, null );
        m.read("file:c:/test.owl");
        
        OntClass c = m.getOntClass(NS+"Display");
        
        
        for(Iterator<Individual> i = (Iterator<Individual>) c.listInstances() ; i.hasNext();){
            Individual c1 = i.next();
            System.out.println(c1.getURI()+"\n");
 
 
        }
    }
}
 


ListInstances() 메소드가 어떤 값을 반환하는지 설명이 부족해서 고생하다가 객체값을 반환하기 때문에 Individual을 사용했는데, 추가로 캐스팅을 해주지 않으면 오류가 났습니다. 메소드 앞에 (Iterator<Individual>)을 사용하여 캐스팅 했습니다.


1
2
3
4
5
http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#Retina
 
http://www.semanticweb.org/cho/ontologies/2013/6/SmartPhone#LCD
 
 


나온 결과값입니다. Display클래스 안에는 Retina 와 LCD 객체가 있었군요. 지금 생각해보면 이게 객체로 만들어야 했는지 클래스로 만들어야 했는지 약간 고민(?)입니다. 다시 만든다면 아마 클래스로 만들었을 것 같네요.






Ontology properties


다시 홈페이지 메뉴얼로 넘어가서 온톨로지의 속성 부분입니다. 속성(property)이란 리소스와 리소스의 관계를 설명해주는 것으로 온톨로지 모델에서 화살표에 해당하는 부분입니다. 논리표현모델에서는 "술어" 역할을 하는 부분이구요. 


jena API에서는 OntProperty라는 클래스를 사용하고 역시나 마찬가지로 add,set,get,list 등의 메소드를 사용해서 관리할 수 있습니다. OntProperty로 접근할 수 있는 속성은 다음과 같습니다.


Attribute | Meaning subProperty | A sub property of this property; i.e. a property which is declared to be a subPropertyOf this property. If p is a sub property of q, and we know thatA p B is true, we can infer that A q B is also true. superProperty | A super property of this property, i.e. a property that this property is a subPropertyOf domain | Denotes the class or classes that form the domain of this property. Multiple domain values are interpreted as a conjunction. The domain denotes the class of value the property maps from. range | Denotes the class or classes that form the range of this property. Multiple range values are interpreted as a conjunction. The range denotes the class of values the property maps to. equivalentProperty | Denotes a property that is the same as this property. inverse | Denotes a property that is the inverse of this property. Thus if q is the inverse of p, and we know that A q B, then we can infer that B p A.


살펴보면 접근 가능한 것들은 하위속성, 상위속성, 속성의 영역이 되는 클래스, 속성의 대상이되는 클래스, 동일한 속성, 반대속성 등이 있습니다.


홈페이지 메뉴얼에서는 예제 온톨로지를 가지고 설명했군요. 저도 여기서 예제 온톨로지를 사용해 보도록 하겠습니다. 다른 포스팅 가서 받기 불편하니 다시 올려드릴께요.


eswc-2006-09-21.rdf


그리고 아마 rdf파일을 읽어도 전체적인 구조가 한눈에 안들어 옵니다. protege툴을 이용해 그래픽적으로 볼 수 있으나 귀찮으니 전체적인 구조그림파일도 올리겠습니다.




대충 이런 구조입니다... 음....; 넘 많아서 잘 안보이네요 ㅋㅋ


아무튼 여기서 우리가 시험할 속성은 "has programme"입니다. 이 속성은 domain 으로 OrganizedEvent를 갖고 range로는 Programme를 갖습니다. 이 과정을 코드상에서 나타내는 방법은 다음과 같습니다. 


OntModel m = ModelFactory.createOntologyModel( OntModelSpec.OWL_MEM );
OntClass programme = m.createClass( NS + "Programme" );
OntClass orgEvent = m.createClass( NS + "OrganizedEvent" );

ObjectProperty hasProgramme = m.createObjectProperty( NS + "hasProgramme" );

hasProgramme.addDomain( orgEvent );
body.addRange( programme );
body.addLabel( "has programme", "en" );


다음으로는 존재한느 온톨로지에서 속성을 추가하는 방법입니다. 


OntModel m = ModelFactory.createOntologyModel( OntModelSpec.OWL_MEM );
m.read( "http://www.eswc2006.org/technologies/ontology" );

DatatypeProperty subDeadline = m.getDatatypeProperty( NS + "hasSubmissionDeadline" );
DatatypeProperty notifyDeadline = m.getDatatypeProperty( NS + "hasNotificationDeadline" );
DatatypeProperty cameraDeadline = m.getDatatypeProperty( NS + "hasCameraReadyDeadline" );

DatatypeProperty deadline = m.createDatatypeProperty( NS + "deadline" );
deadline.addDomain( m.getOntClass( NS + "Call" ) );
deadline.addRange( XSD.dateTime );

deadline.addSubProperty( subDeadline );
deadline.addSubProperty( notifyDeadline );
deadline.addSubProperty( cameraDeadline );


여기서는 상위속성을 추가했기때문에 마지말에 하위속성을 정의하는 코드가 추가되어 있습니다.





Object and Datatype properties


위 예제에서 datatype속성을 사용하였는데 속성은 크게 두가지입니다. Object와 Datatype으로 나뉘는데 Range값으로 오는 값에 따라 구분됩니다. Object속성의 경우 Range로 객체(클래스)가 오게 되지만,  Datatype의 경우 실질적인 값이 오게 됩니다.(String이나 Int 등) 





Functional properties , Other property type


속성에는 6가지 정도의 설정이 있습니다. Functional, Transitive, Stmmetric, 등등이 있는데 이는 온톨로지에 대해 공부하면 다 아는 내용이라고 생각하고 생략하겠습니다. 단지 코드상에서 이런 기능을 넣기 위해서는 다음과 같이 바꾸는 메소드를 사용하면 됩니다.


public TransitiveProperty asTransitiveProperty();
public FunctionalProperty asFunctionalProperty();
public SymmetricProperty asSymmetricPropery();
public InverseFunctionalProperty asInverseFunctionalProperty();



public TransitiveProperty convertToTransitiveProperty();
public FunctionalProperty convertToFunctionalProperty();
public SymmetricProperty convertToSymmetricPropery();
public InverseFunctionalProperty convertToInverseFunctionalProperty();


두가지가 있는데 데이터 타입에 따라 위에 코드가 오류가 날 경우 아래 코드를 사용합니다.





More complex class expressions


RDF에서는 사용되지 않지만 OWL에서 추가적으로 사용되는 클래스 정의 기법을 설명합니다. 두 가지가 있는데 첫번째는 제약조건을 활용한 표현입니다.


제약조건(Restriction)을 활용한 표현이란 클래스가 가지고 있는 속성을 참고하여 클래스를 정의하는 방법입니다. 예를 들어 새라는 클래스가 있고 날개라는 클래스가 있습니다. 이 것을 참고로 날개를 가지고 있으면 새라고 생각할 수 있도록 정의를 하는 것입니다. 즉. 어떤 미지의 객체 X가 날개라는 클래스를 가지고 있다면 객체 X는 새로 분류할 수 있습니다.


제약 조건들을 코드로 명시하는 부분은 부족하게 나와서 따로 찾아 봐야 할 것 같습니다.



반응형

댓글

Designed by JB FACTORY