Jena Ontology API 예제소스 (1)

     

일단 소스코드는 소스포지에서 다운받습니다.


http://sourceforge.net/projects/jena/files/Jena/


소스코드라기보다는 Jena API를 통채로 받습니다. 그 안에 예제 온톨로지와 소스코드가 들어있습니다. 


최신버전을 받고 압축을 푼다음 src-examples/jena/examples/ontology에 가면 3가지 예제가 있습니다. 하나씩 파보면서 jena API에 사용법을 몸에 적응시켜 보겠습니다. ㅎㅎ


첫번째로 볼 소스는 ClassHierarchy입니다. 실행을 한번 시켜봤는데 온톨로지를 읽어들여서 클래스로 나열시켜주는 간단한 기능인것 같습니다. 두개의 java파일로 만들어져 있는데 일단 Main.java를 보도록 하겠습니다.


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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/*****************************************************************************
 * Source code information
 * -----------------------
 * Original author    Ian Dickinson, HP Labs Bristol
 * Author email       ian_dickinson@users.sourceforge.net
 * Package            Jena 2
 * Web                http://sourceforge.net/projects/jena/
 * Created            22-Aug-2003
 * Filename           $RCSfile: Main.java,v $
 * Revision           $Revision: 1.3 $
 * Release status     $State: Exp $
 *
 * Last modified on   $Date: 2009/10/06 13:04:43 $
 *               by   $Author: ian_dickinson $
 *
 * (c) Copyright 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
 * (see footer for full conditions)
 *****************************************************************************/
 
// Package
///////////////
 
 
// Imports
///////////////
import com.hp.hpl.jena.ontology.*;
import com.hp.hpl.jena.rdf.model.ModelFactory;
 
 
/**
 * <p>
 * Execution wrapper for class hierarchy example
 * </p>
 *
 * @author Ian Dickinson, HP Labs
 *         (<a  href="mailto:ian_dickinson@users.sourceforge.net" >email</a>)
 * @version CVS $Id: Main.java,v 1.3 2009/10/06 13:04:43 ian_dickinson Exp $
 */
public class Main {
    // Constants
    //////////////////////////////////
 
    // Static variables
    //////////////////////////////////
 
    // Instance variables
    //////////////////////////////////
 
    // Constructors
    //////////////////////////////////
 
    // External signature methods
    //////////////////////////////////
 
    public static void main( String[] args ) {
        OntModel m = ModelFactory.createOntologyModel( OntModelSpec.OWL_MEM, null );
 
        // we have a local copy of the wine ontology
        m.getDocumentManager().addAltEntry( "http://www.w3.org/2001/sw/WebOnt/guide-src/wine",
                                            "file:c:/testing/reasoners/bugs/wine.owl" );
        m.getDocumentManager().addAltEntry( "http://www.w3.org/2001/sw/WebOnt/guide-src/wine.owl",
                                            "file:c:/testing/reasoners/bugs/wine.owl" );
        m.getDocumentManager().addAltEntry( "http://www.w3.org/2001/sw/WebOnt/guide-src/food",
                                            "file:c:/testing/reasoners/bugs/food.owl" );
        m.getDocumentManager().addAltEntry( "http://www.w3.org/2001/sw/WebOnt/guide-src/food.owl",
                                            "file:c:/testing/reasoners/bugs/food.owl" );
 
        m.read( "http://www.w3.org/2001/sw/WebOnt/guide-src/wine" );
 
        new ClassHierarchy().showHierarchy( System.out, m );
    }
 
 
    // Internal implementation methods
    //////////////////////////////////
 
    //==============================================================================
    // Inner class definitions
    //==============================================================================
 
}
 
 
/*
    (c) Copyright 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:
 
    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
 
    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.
 
    3. The name of the author may not be used to endorse or promote products
       derived from this software without specific prior written permission.
 
    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
 


기본적으로 영어주석이 달려있어서 코드가 길어졌네요 ^^; 실제적인 코드는 10~20줄 밖에 안됩니다. Main 부분에서는 단지 모델을 생성한다음 온톨로지를 읽어오는 부분만 있습니다.


 OntModel m = ModelFactory.createOntologyModel( OntModelSpec.OWL_MEM, null ); 



모델 생성부분은 RDF와 동일합니다. 단지 OntModle로 선언하는 부분만 다릅니다. ModelFactory의 createOntologyModel 메소드를 사용해서 온톨로지 모델을 생성하는데 사용하는 초기 세팅은 OntModelSpec.OWL_MEM입니다. OWL_MEM에 대해서는 지난 포스팅 표를 참조하시면 됩니다. 제 기억에는 OWL FULL버전을 사용하고 in-memory 저장 구조를 가지고 있던 셋팅인 것 같습니다.



        m.getDocumentManager().addAltEntry( "http://www.w3.org/2001/sw/WebOnt/guide-src/wine",
                                            "file:c:/testing/reasoners/bugs/wine.owl" );
        m.getDocumentManager().addAltEntry( "http://www.w3.org/2001/sw/WebOnt/guide-src/wine.owl",
                                            "file:c:/testing/reasoners/bugs/wine.owl" );
        m.getDocumentManager().addAltEntry( "http://www.w3.org/2001/sw/WebOnt/guide-src/food",
                                            "file:c:/testing/reasoners/bugs/food.owl" );
        m.getDocumentManager().addAltEntry( "http://www.w3.org/2001/sw/WebOnt/guide-src/food.owl",
                                            "file:c:/testing/reasoners/bugs/food.owl" );


그 다음엔 온톨로지를 읽어들여올 URI와 로컬 폴더를 지정하는 메소드입니다. m.getDocumentManager().addAltEntry()를 통해 URI와 로컬주소를 매칭시키는 코드입니다. 



         m.read( "http://www.w3.org/2001/sw/WebOnt/guide-src/wine" );


다음은 read함수를 통해 온톨로지를 읽어오는 부분입니다. 인자값으로 웹 URI를 적었지만 이전에 URI와 로컬주소를 매칭시켰기때문에 구지 웹에 접속하지않고 로컬에서 파일을 읽어드립니다. 이 때 파일읽기를 실패 할 수 있는데, 여러분이 압축푼 폴더의 경로로 바꿔주셔야 됩니다. 저는 경로를 c드라이브로 사용해서 위와같이 설정했습니다.



         new ClassHierarchy().showHierarchy( System.out, m );


메인의 마지막 코드입니다. ClassHierarchy()클래스의 showHierarchy메소드를 실행시킵니다. 인자값으로는 첫번째로 output, 두번째로는 모델이 들어가는 것 같습니다. 여기서는 System.out과 모델 m을 사용했습니다.


메인의 코드를 보면 일단 모델을 만든다음 읽을 온톨로지의 경로설정, read 메소드를 통한 읽기, 마지막으로 전체적인 클래스를 나열하는 ClassHierarchy()함수 사용 순으로 되어있습니다. ClassHierarchy()함수만 보지 않는다면 참 간단한 코드입니다. ClassHierarchy() 함수를 보기전에 코드를 실행해 봅니다. 다음과 같은 결과가 나옵니다.

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
Class :Winery 
Class :Region 
Class :DryRedWine 
Class :WineDescriptor 
  Class :WineColor 
  Class :WineTaste 
    Class :WineBody 
    Class :WineFlavor 
    Class :WineSugar 
Class :FullBodiedWine 
Class :Bordeaux 
  Class :Sauterne 
Class :RedTableWine 
Class :RedWine 
  Class :Port 
Class :Gamay 
Class :WhiteTableWine 
Class :WhiteNonSweetWine 
Class :TableWine 
Class :CaliforniaWine 
Class :RoseWine 
Class :AmericanWine 
Class :DryWine 
Class :GermanWine 
Class :SweetWine 
Class :TexasWine 
Class :AlsatianWine 
Class :SauvignonBlanc 
Class :VintageYear 
Class :Loire 
Class :DryWhiteWine 
Class :Semillon 
Class :FrenchWine 
Class :ItalianWine 
  Class :Chianti 
Class :WhiteWine 
Class food:ConsumableThing 
  Class food:Meal 
  Class food:MealCourse 
  Class food:PotableLiquid 
    Class :Wine 
      Class :LateHarvest 
        Class :Sauterne 
      Class :EarlyHarvest 
      Class :DessertWine 
        Class :SweetRiesling 
    Class food:Juice 
  Class food:EdibleThing 
    Class food:OtherTomatoBasedFood 
    Class food:Fowl 
      Class food:DarkMeatFowl 
      Class food:LightMeatFowl 
    Class food:NonSweetFruit 
    Class food:Meat 
      Class food:RedMeat 
        Class food:SpicyRedMeat 
        Class food:NonSpicyRedMeat 
      Class food:NonRedMeat 
    Class food:Seafood 
      Class food:Shellfish 
        Class food:NonOysterShellfish 
        Class food:OysterShellfish 
      Class food:Fish 
        Class food:BlandFish 
        Class food:NonBlandFish 
    Class food:SweetFruit 
      Class food:Grape 
        Class :WineGrape 
        Class food:EatingGrape 
    Class food:Pasta 
      Class food:PastaWithRedSauce 
        Class food:PastaWithNonSpicyRedSauce 
        Class food:PastaWithSpicyRedSauce 
      Class food:PastaWithWhiteSauce 
        Class food:PastaWithHeavyCreamSauce 
        Class food:PastaWithLightCreamSauce 
    Class food:Dessert 
      Class food:CheeseNutsDessert 
      Class food:SweetDessert 
Class food:Wine 
Class food:NonConsumableThing 
Class food:Fruit 
 


클래스가 쭈르륵 나열되어있습니다. 여기서 한가지 궁금한점은 우리가 read한 파일은 wine온톨로지인데 아래쪽에 food라는 클래스가 출력된 것을 볼 수 있습니다. 이것은 wine온톨로지에서 food 온톨로지를 import했기 때문에 출력되는 것으로 알 수있습니다. base 온톨로지가 wine이고 import 온톨로지가 food라고 생각하시면 됩니다. 


이제 Classhierarchy 코드를 살펴보겠습니다.


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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/*****************************************************************************
 * Source code information
 * -----------------------
 * Original author    Ian Dickinson, HP Labs Bristol
 * Author email       ian_dickinson@users.sourceforge.net
 * Package            Jena 2
 * Web                http://sourceforge.net/projects/jena/
 * Created            27-Mar-2003
 * Filename           $RCSfile: ClassHierarchy.java,v $
 * Revision           $Revision: 1.5 $
 * Release status     $State: Exp $
 *
 * Last modified on   $Date: 2009/10/06 13:04:43 $
 *               by   $Author: ian_dickinson $
 *
 * (c) Copyright 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
 * (see footer for full conditions)
 *****************************************************************************/
 
// Package
///////////////
 
 
// Imports
///////////////
import com.hp.hpl.jena.ontology.*;
import com.hp.hpl.jena.rdf.model.*;
import com.hp.hpl.jena.shared.PrefixMapping;
import com.hp.hpl.jena.util.iterator.Filter;
 
import java.io.PrintStream;
import java.util.*;
 
 
/**
 * <p>
 * Simple demonstration program to show how to list a hierarchy of classes. This
 * is not a complete solution to the problem (sub-classes of restrictions, for example,
 * are not shown).  It is intended only to be illustrative of the general approach.
 * </p>
 *
 * @author Ian Dickinson, HP Labs
 *         (<a  href="mailto:ian_dickinson@users.sourceforge.net" >email</a>)
 * @version CVS $Id: ClassHierarchy.java,v 1.5 2009/10/06 13:04:43 ian_dickinson Exp $
 */
public class ClassHierarchy {
    // Constants
    //////////////////////////////////
 
    // Static variables
    //////////////////////////////////
 
    // Instance variables
    //////////////////////////////////
 
    protected OntModel m_model;
    private Map<AnonId,String> m_anonIDs = new HashMap<AnonId, String>();
    private int m_anonCount = 0;
 
 
 
    // Constructors
    //////////////////////////////////
 
    // External signature methods
    //////////////////////////////////
 
    /** Show the sub-class hierarchy encoded by the given model */
    public void showHierarchy( PrintStream out, OntModel m ) {
        // create an iterator over the root classes that are not anonymous class expressions
        Iterator<OntClass> i = m.listHierarchyRootClasses()
                      .filterDrop( new Filter<OntClass>() {
                                    @Override
                                    public boolean accept( OntClass r ) {
                                        return r.isAnon();
                                    }} );
 
        while (i.hasNext()) {
            showClass( out, i.next(), new ArrayList<OntClass>(), 0 );
        }
    }
 
 
    // Internal implementation methods
    //////////////////////////////////
 
    /** Present a class, then recurse down to the sub-classes.
     *  Use occurs check to prevent getting stuck in a loop
     */
    protected void showClass( PrintStream out, OntClass cls, List<OntClass> occurs, int depth ) {
        renderClassDescription( out, cls, depth );
        out.println();
 
        // recurse to the next level down
        if (cls.canAs( OntClass.class )  &&  !occurs.contains( cls )) {
            for (Iterator<OntClass> i = cls.listSubClasses( true );  i.hasNext(); ) {
                OntClass sub = i.next();
 
                // we push this expression on the occurs list before we recurse
                occurs.add( cls );
                showClass( out, sub, occurs, depth + 1 );
                occurs.remove( cls );
            }
        }
    }
 
 
    /**
     * <p>Render a description of the given class to the given output stream.</p>
     * @param out A print stream to write to
     * @param c The class to render
     */
    public void renderClassDescription( PrintStream out, OntClass c, int depth ) {
        indent( out, depth );
 
        if (c.isRestriction()) {
            renderRestriction( out, c.as( Restriction.class ) );
        }
        else {
            if (!c.isAnon()) {
                out.print( "Class " );
                renderURI( out, c.getModel(), c.getURI() );
                out.print( ' ' );
            }
            else {
                renderAnonymous( out, c, "class" );
            }
        }
    }
 
    /**
     * <p>Handle the case of rendering a restriction.</p>
     * @param out The print stream to write to
     * @param r The restriction to render
     */
    protected void renderRestriction( PrintStream out, Restriction r ) {
        if (!r.isAnon()) {
            out.print( "Restriction " );
            renderURI( out, r.getModel(), r.getURI() );
        }
        else {
            renderAnonymous( out, r, "restriction" );
        }
 
        out.print( " on property " );
        renderURI( out, r.getModel(), r.getOnProperty().getURI() );
    }
 
    /** Render a URI */
    protected void renderURI( PrintStream out, PrefixMapping prefixes, String uri ) {
        out.print( prefixes.shortForm( uri ) );
    }
 
    /** Render an anonymous class or restriction */
    protected void renderAnonymous( PrintStream out, Resource anon, String name ) {
        String anonID = m_anonIDs.get( anon.getId() );
        if (anonID == null) {
            anonID = "a-" + m_anonCount++;
            m_anonIDs.put( anon.getId(), anonID );
        }
 
        out.print( "Anonymous ");
        out.print( name );
        out.print( " with ID " );
        out.print( anonID );
    }
 
    /** Generate the indentation */
    protected void indent( PrintStream out, int depth ) {
        for (int i = 0;  i < depth; i++) {
            out.print( "  " );
        }
    }
 
 
    //==============================================================================
    // Inner class definitions
    //==============================================================================
 
}
 
 
/*
    (c) Copyright 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:
 
    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
 
    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.
 
    3. The name of the author may not be used to endorse or promote products
       derived from this software without specific prior written permission.
 
    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
 


역시 주석을 제외하면 코드는 상당히 짧습니다. 하지만 아쉽게도 공홈에 설명이 없군요..

제 나름대로 분석해 보자면 일단 결과값을 보여주는 클래스는 renderClassDescription입니다. 제일 위에 showHierarchy는 메인에서 실행된 메소드로 루트클래스로부터 서브클래스들을 탐색하게 됩니다. 탐색을 하면서 각각에 클래스에서 showClass라는 메소드를 실행합니다. showClass는 원할한 탐색을위해 중복을 제거하는 메소드입니다. (탐색하던도중 루프에 빠지지않도록) showClass 역시 클래스마다 renderClassDescription 메소드를 실행시킵니다. 마지막으로 renderClassDescription에서 클래스들을 출력하게 됩니다. showClass에서 계산된 깊이를 기반으로 서브클래스를 표시하기위해 앞에 공백을 두어 계층적으로 출력하게 됩니다.



일단 사용되는 코드는 대부분 Iterator 코드입니다. 이는 RDF API 포스팅에서 다루었기때문에 생략하겠습니다. 나머지는 출력하는 부분이라 기본적인 java메소드를 사용한 것 같습니다.






이렇게 첫번째 예제 코드를 해보았는데 아직 잘 모르겠습니다. 

다음 포스팅에서 나머지 코드를 해보고 좀더 연구해봐서 실질적인 사용법을 익혀보도록 하겠습니다.

반응형

'Study > OWL,RDF' 카테고리의 다른 글

Jena Ontology API (2)  (0) 2014.02.14
Jena Ontology API 예제소스 (2)  (1) 2014.02.12
Jena Ontology API  (0) 2014.02.10
Jena RDF api 활용하기 (3)  (0) 2014.02.05
Jena RDF api 활용하기 (2)  (1) 2014.02.05

댓글

Designed by JB FACTORY