Jena學習筆記(一) RDF


title: Jena學習筆記(一) RDF
date: 2016/11/26 22:56:02
tags: Jena
categories: paper


官方描述:Apache Jena(或簡稱Jena)是一個用于構建語義Web和關聯(lián)數(shù)據(jù)應用程序的自由和開源的Java框架。 該框架由不同的API組成,用于處理RDF數(shù)據(jù)。

Jena是一個用于Java語義Web應用程序的API(應用程序編程接口)。它不是一個程序或工具,如果這是你正在尋找,我建議或許TopBraid Composer作為一個好的選擇。因此,Jena的主要用途是幫助您編寫處理RDF和OWL文檔和描述的Java代碼。

官方網(wǎng)站:http://jena.apache.org/index.html
RDF API教程:http://jena.apache.org/tutorials/rdf_api.html


RDF定義

資源描述框架(RDF)是最初設計為元數(shù)據(jù)數(shù)據(jù)模型的萬維網(wǎng)聯(lián)盟(W3C)規(guī)范[1]的家族。 它已經(jīng)被用作用于概念描述或者在web資源中實現(xiàn)的信息的建模的一般方法,使用各種語法符號和數(shù)據(jù)串行化格式。 它也用于知識管理應用程序中。
RDF數(shù)據(jù)模型類似于諸如實體關系或類圖的經(jīng)典概念建模方法,因為它基于以主語謂詞對象的形式對資源(特別是web資源)進行語句表。這些表達式在RDF術語中稱為三元組。主語表示資源,謂詞表示資源的特征或方面,并且表示主語和對象之間的關系。例如,在RDF中表示“天空具有藍色”的概念的一種方式是作為三元組:表示“天空”的主題,表示“具有顏色”的謂詞和表示“藍色”的對象。因此,RDF將面向對象設計中的實體 - 屬性 - 值模型的經(jīng)典符號中使用的對象交換對象;實體(天空),屬性(顏色)和值(藍色)。 RDF是具有幾種串行格式(即,文件格式)的抽象模型,因此資源或三元組被編碼的特定方式隨格式而變化。

下載Jena并從Eclipse建立工程,導入jar

建立如下RDF圖并打印

package com.hdu.rdf;

import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.rdf.model.Property;
import org.apache.jena.rdf.model.RDFNode;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.rdf.model.Statement;
import org.apache.jena.rdf.model.StmtIterator;
import org.apache.jena.vocabulary.VCARD;

public class Tutorial2AddProperty {
    public static void main(String[] args) {
        // some definitions
        String personURI = "http://somewhere/JohnSmith";
        String givenName = "John";
        String familyName = "Smith";
        String fullName = givenName + " " + familyName;

        // create an empty model
        Model model = ModelFactory.createDefaultModel();

        // create the resource
        // and add the properties cascading style
        Resource johnSmith = model.createResource(personURI).addProperty(VCARD.FN, fullName).addProperty(VCARD.N,
                model.createResource().addProperty(VCARD.Given, givenName).addProperty(VCARD.Family, familyName));
        // model.write(System.out);

        // list the statements in the graph
        StmtIterator iter = model.listStatements();
        // print out the predicate, subject and object of each statement
        while (iter.hasNext()) {
            Statement stmt = iter.nextStatement();
            Resource subject = stmt.getSubject(); // get the subject
            Property predicate = stmt.getPredicate(); // get the predicate
            RDFNode object = stmt.getObject(); // get the object

            System.out.print(subject.toString());
            System.out.print(" " + predicate.toString() + " ");
            if (object instanceof Resource) {
                System.out.print(object.toString());
            } else {
                // object is a literal
                System.out.print(" \"" + object.toString() + "\"");
            }

            System.out.println(" .");
        }
    }
}

結果

//iterator遍歷 每行包含三個字段,表示每個語句的主題,謂詞和對象
http://somewhere/JohnSmith http://www.w3.org/2001/vcard-rdf/3.0#N anon:14df86:ecc3dee17b:-7fff .
anon:14df86:ecc3dee17b:-7fff http://www.w3.org/2001/vcard-rdf/3.0#Family  "Smith" .
anon:14df86:ecc3dee17b:-7fff http://www.w3.org/2001/vcard-rdf/3.0#Given  "John" .
http://somewhere/JohnSmith http://www.w3.org/2001/vcard-rdf/3.0#FN  "John Smith" .

//write輸出  xml格式
<rdf:RDF
  xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
  xmlns:vcard='http://www.w3.org/2001/vcard-rdf/3.0#'
 >
  <rdf:Description rdf:about='http://somewhere/JohnSmith'>
    <vcard:FN>John Smith</vcard:FN>
    <vcard:N rdf:nodeID="A0"/>
  </rdf:Description>
  <rdf:Description rdf:nodeID="A0">
    <vcard:Given>John</vcard:Given>
    <vcard:Family>Smith</vcard:Family>
  </rdf:Description>
</rdf:RDF>

說明

他的RDF規(guī)范指定如何將RDF表示為XML。 RDF XML語法相當復雜。讀者參考由RDFCore WG開發(fā)的引物以進行更詳細的介紹。但是,讓我們快速看看如何解釋上面的。

RDF通常嵌入在<rdf:RDF>元素中。如果有其他方式知道某些XML是RDF,但是它通常存在,那么該元素是可選的。 RDF元素定義文檔中使用的兩個命名空間。然后是一個<rdf:Description>元素,描述其URI為“http:// somewhere / JohnSmith”的資源。如果缺少rdf:about屬性,則此元素將表示空白節(jié)點。

<vcard:FN>元素描述了資源的屬性。屬性名稱是vcard命名空間中的“FN”。 RDF通過連接命名空間前綴的URI引用和名稱的本地名稱部分的“FN”,將其轉換為URI引用。這提供了一個URI引用"http://www.w3.org/2001/vcard-rdf/3.0#FN"。屬性的值是文字"John Smith"。

<vcard:N>元素是一個資源。在這種情況下,資源由相對URI引用表示。 RDF通過將其與當前文檔的基本URI連接,將其轉換為絕對URI引用。

此RDF XML中有錯誤;它不完全代表我們創(chuàng)建的模型。模型中的空白節(jié)點已經(jīng)被賦予URI引用。它不再是空白。 RDF / XML語法不能表示所有RDF模型;例如它不能表示作為兩個語句的對象的空白節(jié)點。我們用來編寫這個RDF / XML的'dumb'作者沒有嘗試正確地寫入可以正確寫入的Models子集。它為每個空白節(jié)點提供一個URI,使其不再為空。

        // now write the model in XML form to a file
        model.write(System.out, "RDF/XML-ABBREV");
        
        // now write the model in N-TRIPLES form to a file
        model.write(System.out, "N-TRIPLES");
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:vcard="http://www.w3.org/2001/vcard-rdf/3.0#">
  <rdf:Description rdf:about="http://somewhere/JohnSmith">
    <vcard:N rdf:parseType="Resource">
      <vcard:Family>Smith</vcard:Family>
      <vcard:Given>John</vcard:Given>
    </vcard:N>
    <vcard:FN>John Smith</vcard:FN>
  </rdf:Description>
</rdf:RDF>
<http://somewhere/JohnSmith> <http://www.w3.org/2001/vcard-rdf/3.0#N> _:BX2D71b38d8eX3A1589596bd63X3AX2D7fff .
<http://somewhere/JohnSmith> <http://www.w3.org/2001/vcard-rdf/3.0#FN> "John Smith" .
_:BX2D71b38d8eX3A1589596bd63X3AX2D7fff <http://www.w3.org/2001/vcard-rdf/3.0#Family> "Smith" .
_:BX2D71b38d8eX3A1589596bd63X3AX2D7fff <http://www.w3.org/2001/vcard-rdf/3.0#Given> "John" .

讀取RDF

static final String inputFileName = "vc-db-1.rdf";

 // create an empty model
 Model model = ModelFactory.createDefaultModel();

 // use the FileManager to find the input file
 InputStream in = FileManager.get().open( inputFileName );
if (in == null) {
    throw new IllegalArgumentException(
                                 "File: " + inputFileName + " not found");
}

// read the RDF/XML file
model.read(in, null);

// write it to standard out
model.write(System.out);

讀取結果

<rdf:RDF
  xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
  xmlns:vcard='http://www.w3.org/2001/vcard-rdf/3.0#'
 >
  <rdf:Description rdf:nodeID="A0">
    <vcard:Family>Smith</vcard:Family>
    <vcard:Given>John</vcard:Given>
  </rdf:Description>
  <rdf:Description rdf:about='http://somewhere/JohnSmith/'>
    <vcard:FN>John Smith</vcard:FN>
    <vcard:N rdf:nodeID="A0"/>
  </rdf:Description>
  <rdf:Description rdf:about='http://somewhere/SarahJones/'>
    <vcard:FN>Sarah Jones</vcard:FN>
    <vcard:N rdf:nodeID="A1"/>
  </rdf:Description>
  <rdf:Description rdf:about='http://somewhere/MattJones/'>
    <vcard:FN>Matt Jones</vcard:FN>
    <vcard:N rdf:nodeID="A2"/>
  </rdf:Description>
  <rdf:Description rdf:nodeID="A3">
    <vcard:Family>Smith</vcard:Family>
    <vcard:Given>Rebecca</vcard:Given>
  </rdf:Description>
  <rdf:Description rdf:nodeID="A1">
    <vcard:Family>Jones</vcard:Family>
    <vcard:Given>Sarah</vcard:Given>
  </rdf:Description>
  <rdf:Description rdf:nodeID="A2">
    <vcard:Family>Jones</vcard:Family>
    <vcard:Given>Matthew</vcard:Given>
  </rdf:Description>
  <rdf:Description rdf:about='http://somewhere/RebeccaSmith/'>
    <vcard:FN>Becky Smith</vcard:FN>
    <vcard:N rdf:nodeID="A3"/>
  </rdf:Description>
</rdf:RDF>

Jena RDF包

Jena是用于語義Web應用程序的Java API。應用程序開發(fā)人員的關鍵RDF包是org.apache.jena.rdf.model。 API已經(jīng)根據(jù)接口進行了定義,以便應用程序代碼可以在不改變的情況下與不同的實現(xiàn)工作。此包包含用于表示模型,資源,屬性,文字,語句和RDF的所有其他關鍵概念的接口,以及用于創(chuàng)建模型的ModelFactory。所以應用程序代碼保持獨立的實現(xiàn),最好是盡可能使用接口,而不是特定的類實現(xiàn)。

org.apache.jena.tutorial包包含本教程中使用的所有示例的工作源代碼。

org.apache.jena ... impl包包含可能對許多實現(xiàn)通用的實現(xiàn)類。例如,它們定義類ResourceImpl,PropertyImpl和LiteralImpl,它們可以被不同的實現(xiàn)直接使用或子類化。應用程序應該很少,如果有的話,直接使用這些類。例如,不是創(chuàng)建ResourceImpl的新實例,最好使用正在使用的任何模型的createResource方法。這樣,如果模型實現(xiàn)使用了Resource的優(yōu)化實現(xiàn),則兩種類型之間不需要轉換。

瀏覽模型

給定資源的URI,可以使用Model.getResource(String uri)方法從模型中檢索資源對象。 此方法定義為返回一個Resource對象(如果模型中存在),否則創(chuàng)建一個新對象。

static final String inputFileName = "vc-db-1.rdf";
    static final String johnSmithURI = "http://somewhere/JohnSmith/";
    
    public static void main (String args[]) {
        // create an empty model
        Model model = ModelFactory.createDefaultModel();
       
        // use the FileManager to find the input file
        InputStream in = FileManager.get().open(inputFileName);
        if (in == null) {
            throw new IllegalArgumentException( "File: " + inputFileName + " not found");
        }
        
        
        // read the RDF/XML file
        model.read(new InputStreamReader(in), "");
        
        // retrieve the Adam Smith vcard resource from the model
        Resource vcard = model.getResource(johnSmithURI);

        // retrieve the value of the N property
        Resource name = (Resource) vcard.getRequiredProperty(VCARD.N)
                                        .getObject();
        // retrieve the given name property
        String fullName = vcard.getRequiredProperty(VCARD.FN)
                               .getString();
        // add two nick name properties to vcard
        // 獲取johnSmithURI資源后,對其添加兩個nickname屬性
        vcard.addProperty(VCARD.NICKNAME, "Smithy")
             .addProperty(VCARD.NICKNAME, "Adman");
        
        // set up the output
        System.out.println("The nicknames of \"" + fullName + "\" are:");
        // list the nicknames
        //返回聲明迭代器,獲取對象
        StmtIterator iter = vcard.listProperties(VCARD.NICKNAME);
        while (iter.hasNext()) {
            System.out.println("    " + iter.nextStatement().getObject()
                                            .toString());
        }
    }
The nicknames of "John Smith" are:
    Adman
    Smithy

查詢模型

上一節(jié)討論從具有已知URI的資源導航模型的情況。 本節(jié)介紹搜索模型。 核心Jena API僅支持有限的查詢原語。 更強大的查詢功能在SPARQL中。

Model.listStatements()方法列出了模型中的所有語句,也許是查詢模型的最粗糙的方法。 它的使用不推薦在非常大的模型。 Model.listSubjects()是類似的,但返回一個迭代器在所有具有屬性的資源,即一些語句的主題。

Model.listSubjectsWithProperty(Property p,RDFNode o)將返回所有資源的迭代器,這些資源具有值為o的屬性p。 如果我們假設只有vcard資源會有vcard:FN屬性,并且在我們的數(shù)據(jù)中,所有這些資源都有這樣的屬性,那么我們可以找到所有的vcards:

 static final String inputFileName = "vc-db-1.rdf";
    
    public static void main (String args[]) {
        // create an empty model
        Model model = ModelFactory.createDefaultModel();
       
        // use the FileManager to find the input file
        InputStream in = FileManager.get().open(inputFileName);
        if (in == null) {
            throw new IllegalArgumentException( "File: " + inputFileName + " not found");
        }
        
        // read the RDF/XML file
        model.read( in, "");
        
        // select all the resources with a VCARD.FN property
        ResIterator iter = model.listResourcesWithProperty(VCARD.FN);
        if (iter.hasNext()) {
            System.out.println("The database contains vcards for:");
            while (iter.hasNext()) {
                System.out.println("  " + iter.nextResource()
                                              .getRequiredProperty(VCARD.FN)
                                              .getString() );
            }
        } else {
            System.out.println("No vcards were found in the database");
        }            
    }
The database contains vcards for:
  Sarah Jones
  John Smith
  Becky Smith
  Matt Jones

模型操作

Jena提供了操作模型作為一個整體的三個操作,分別是并集,交集和差的運算。

兩個模型的并集是表示每個模型的語句集合的合并。這是RDF設計支持的關鍵操作之一。它允許合并來自不同數(shù)據(jù)源的數(shù)據(jù)。 考慮以下兩個模型:


當這些被合并時,兩個http://...JohnSmith節(jié)點被合并成一個,并且vcard:FN 弧被丟棄以產(chǎn)生:


   static final String inputFileName1 = "vc-db-3.rdf";    
    static final String inputFileName2 = "vc-db-4.rdf";
    
    public static void main (String args[]) {
        // create an empty model
        Model model1 = ModelFactory.createDefaultModel();
        Model model2 = ModelFactory.createDefaultModel();
       
        // use the class loader to find the input file
        InputStream in1 = FileManager.get().open(inputFileName1);
        if (in1 == null) {
            throw new IllegalArgumentException( "File: " + inputFileName1 + " not found");
        }
        InputStream in2 = FileManager.get().open(inputFileName2);
        if (in2 == null) {
            throw new IllegalArgumentException( "File: " + inputFileName2 + " not found");
        }
        
        // read the RDF/XML files
        model1.read( in1, "" );
        model2.read( in2, "" );
        
        // merge the graphs
        Model model = model1.union(model2);
        
        // print the graph as RDF/XML
        model.write(System.out, "RDF/XML-ABBREV");
        System.out.println();
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:vcard="http://www.w3.org/2001/vcard-rdf/3.0#">
  <rdf:Description rdf:about="http://somewhere/JohnSmith/">
    <vcard:N rdf:parseType="Resource">
      <vcard:Given>John</vcard:Given>
      <vcard:Family>Smith</vcard:Family>
    </vcard:N>
    <vcard:EMAIL>
      <vcard:internet>
        <rdf:value>John@somewhere.com</rdf:value>
      </vcard:internet>
    </vcard:EMAIL>
    <vcard:FN>John Smith</vcard:FN>
  </rdf:Description>
</rdf:RDF>

容器

RDF定義了一種特殊的資源來表示事物的集合。 這些資源稱為容器。 容器的成員可以是文字或資源。 有三種容器:

BAG是一個無序的集合
ALT是旨在表示可選的無序集合
SEQ是有序集合
容器由資源表示。 該資源將有一個rdf:type屬性,其值應為rdf:Bag,rdf:Alt或rdf:Seq之一,或其中一個的子類,具體取決于容器的類型。 容器的第一個成員是容器的rdf:_1屬性的值; 容器的第二個成員是容器的rdf:_2屬性的值,等等。 rdf:_nnn屬性被稱為序數(shù)屬性。

例如,包含Smith的vcards的簡單包的模型可能如下所示:

 static final String inputFileName = "vc-db-1.rdf";
    
    public static void main (String args[]) {
        // create an empty model
        Model model = ModelFactory.createDefaultModel();
       
        // use the class loader to find the input file
        InputStream in = FileManager.get().open( inputFileName );
        if (in == null) {
            throw new IllegalArgumentException( "File: " + inputFileName + " not found");
        }
        
        // read the RDF/XML file
        model.read(new InputStreamReader(in), "");
        
        // create a bag
        Bag smiths = model.createBag();
        
        // select all the resources with a VCARD.FN property
        // whose value ends with "Smith"
        StmtIterator iter = model.listStatements(
            new 
                SimpleSelector(null, VCARD.FN, (RDFNode) null) {
                    @Override
                    public boolean selects(Statement s) {
                            return s.getString().endsWith("Smith");
                    }
                });
        // add the Smith's to the bag
        while (iter.hasNext()) {
            smiths.add( iter.nextStatement().getSubject());
        }
        
        // print the graph as RDF/XML
        model.write(new PrintWriter(System.out));
        System.out.println();
        
        // print out the members of the bag
        NodeIterator iter2 = smiths.iterator();
        if (iter2.hasNext()) {
            System.out.println("The bag contains:");
            while (iter2.hasNext()) {
                System.out.println("  " +
                    ((Resource) iter2.next())
                                     .getRequiredProperty(VCARD.FN)
                                     .getString());
            }
        } else {
            System.out.println("The bag is empty");
        }
    }
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:vcard="http://www.w3.org/2001/vcard-rdf/3.0#">
  <rdf:Description rdf:about="http://somewhere/SarahJones/">
    <vcard:N rdf:parseType="Resource">
      <vcard:Given>Sarah</vcard:Given>
      <vcard:Family>Jones</vcard:Family>
    </vcard:N>
    <vcard:FN>Sarah Jones</vcard:FN>
  </rdf:Description>
  <rdf:Bag>
    <rdf:li>
      <rdf:Description rdf:about="http://somewhere/RebeccaSmith/">
        <vcard:N rdf:parseType="Resource">
          <vcard:Given>Rebecca</vcard:Given>
          <vcard:Family>Smith</vcard:Family>
        </vcard:N>
        <vcard:FN>Becky Smith</vcard:FN>
      </rdf:Description>
    </rdf:li>
    <rdf:li>
      <rdf:Description rdf:about="http://somewhere/JohnSmith/">
        <vcard:N rdf:parseType="Resource">
          <vcard:Given>John</vcard:Given>
          <vcard:Family>Smith</vcard:Family>
        </vcard:N>
        <vcard:FN>John Smith</vcard:FN>
      </rdf:Description>
    </rdf:li>
  </rdf:Bag>
  <rdf:Description rdf:about="http://somewhere/MattJones/">
    <vcard:N rdf:parseType="Resource">
      <vcard:Given>Matthew</vcard:Given>
      <vcard:Family>Jones</vcard:Family>
    </vcard:N>
    <vcard:FN>Matt Jones</vcard:FN>
  </rdf:Description>
</rdf:RDF>

The bag contains:
  Becky Smith
  John Smith

詞匯表

空白節(jié)點(Blank Node)
表示資源,但不指示資源的URI??瞻坠?jié)點表現(xiàn)為一階邏輯中存在的合格變量。
Dublin Core
關于Web資源的元數(shù)據(jù)標準。更多信息可以在Dublin Core網(wǎng)站上找到。
文字(Literal)
可以是屬性值的字符串。
對象(Object)
三元組的一部分,即語句的值。
謂詞(Predicate)
三元組的屬性部分。
屬性(Property)
屬性是資源的屬性。例如DC.title是一個屬性,和RDF.type一樣。
資源(Resource)
一些實體。它可以是諸如網(wǎng)頁的web資源,或者它可以是具體的物理事物,例如樹或汽車。它可以是一個抽象的想法,如象棋或足球。資源由URI命名。
聲明(Statement)
RDF模型中的弧,通常被解釋為事實。
主語Subject)
作為RDF模型中的弧源的資源
三元組(Triple)
包含主語,謂詞和對象的結構。語句的另一個術語。

腳注

RDF資源的標識符可以包括片段標識符,例如, http:// hostname / rdf / tutorial /#ch-簡介,因此,嚴格地說,RDF資源由URI引用標識。
除了作為一個字符串,字面量還有一個可選的語言編碼來表示字符串的語言。例如,文字“two”對于英語可能具有“en”的語言編碼,而對于法國,文字“deux”可能具有“fr”的語言編碼。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容