Jena对本体、RDF三元组的API操作记录
目錄
目標
導入RDF
導入本體文件
新增三元組
(1)Statement方式
(2)Resource方式
問題記錄
參考文獻
目標
? ? ? ? 通過這份源碼以及對應配套的博客內容的學習,基本上是了解和掌握了知識圖譜的一些基本信息,如果你認真看了作者寫的那幾篇文檔,應該有了以下幾點的了解和認識:
(1)清楚的了解RDF/RDFS/OWL是什么,之間是什么關系,以及他們的簡單用法
(2)搞清了本體、實體、三元組、TDB、Fuseki這些名詞的概念和作用
(3)知道本體文件應該怎么編寫,知道怎么從關系mysql關系數據庫中將數據導出生成.nt三元組數據
(4)大致了解如何通過sparql通過Fuseki進行三元組的查詢
(5)大致知道怎么通過知識庫圖譜進行對話問答系統的建設
在此,在此感謝作者的總結和貢獻。
? ? ? ? 本篇主要記錄下,如何直接通過jena的API進行本體導入、RDF三元組數據導入以及對三元組數據的增刪改查操作,實際上網上有很多優秀的博文,我主要是記錄下我在學習的過程中遇到的問題。
(1)將ttl本體文件導入到TDB中
(2)將.nt數據直接導入到TDB中
(3)在TDB中創建指定model名稱的model,并且支持往model里新增、刪除三元組
(4)從TDB中查詢新增的三元組數據
? ? ? ? 注:jena版本3.6
導入RDF
? ? ? ? 在官網以及一些博客上可以很容易查到關于RDF導入的操作,主要包括兩種情況。 一種是直接從.nt文件中加載,加載到內存中,然后進行各種查詢。
? ? ? ? 一種是將.nt文件加載到TDB中,然后通過Dataset進行查詢。
? ? ? ? 我主要考慮第二種,主要是為了持久化做準備,可以新增三元組,而且TDB也可以暴露出去給Fuseki,供上層查詢使用。
String tdbPath = "/opt/tdb1"; String rdfFile = "/opt/rdf/kg_movie.nt"; String modelName = "KgMovie";Dataset ds = TDBFactory.createDataset(tdbPath);Model model = ds.getNamedModel(modelName); RDFDataMgr.read(model,rdfFilePath);ds.cose();? ? ? ? 這幾行代碼非常簡單,網上還有很多其他方式的,比如通過FileManager.get()獲取文件流,然后再通過model.read去做的。都可以,不過有些方法可能逐步會被遺棄掉。使用的時候,查一下官方的API說明。
? ? ? ? 另外,有些博客提到事務,比如ds.begin(ReadWrite.WRITE)、model.begin()、model.commit()等,也可以用,但是我沒發現有什么很特別的意義,不使用也是沒關系。?
導入本體文件
public boolean loadOntModel(String modelName, String ttlFilePath){if(!ds.isInTransaction())ds.begin(ReadWrite.WRITE);try{if(ds.containsNamedModel(modelName)){logger.warn("已經存在對應本體描述!");ds.commit();return false;}Model model = RDFDataMgr.loadModel(ttlFilePath);ds.addNamedModel(modelName,model);ds.commit();logger.info("{}本體描述已導入",modelName);}catch (Exception e){logger.error(CommTool.getStackTraceInfo(e));return false;}finally{if(ds.isInTransaction())ds.end();}return true;}? ? ? ? 這段代碼可以看到,先通過RDFDataMgr.loadModel直接記載ttl的本體文件到一個模型中,然后將模型放到Dataset中,ds是DataSet,通過TDBFactory.createDataset(tdbPath)創建的。 執行完之后,會在對應的TDB目錄下創建如下的文件:
? ? ? ? 同樣導入RDF的時候也會創建這些。?
?TDB存儲的本體數據集由node表、Triple和Quad索引、prefixes表組成,存放在指定的文件系統目錄下。TDB采用B+樹維護三種基本形式的Triple索引:SPO、POS和OSP(S、P、O分別代表Subject、Predicate和Object)。若存在命名圖(Named Graph),則同時維護相應的Quad索引(G表示Graph):GOSP、SPOG、GSPO、OSPG、GPOS和POSG。
在實際操作中,以下幾點非常重要。
新增三元組
? ? ? ? 網上關于新增三元組的方式我查到的有三種,一種是通過Statement,mode.add的方式,一種是直接通過Resourece的方式,還有一種是直接通過Sparql的Insert語句。 前面兩種我都做了嘗試,都是沒有問題的。
(1)Statement方式
public static void test4(){String directory = "D:\\jena\\ctd" ;Dataset dataset = TDBFactory.createDataset(directory) ;String perx_s = "http://www.jingu.com#/movie/121";//電影String perx_p = "http://www.jingu.com#/movieTitle";String perx_o = "行尸走肉大暴亂";Model model = dataset.getNamedModel("kgMovie");Selector selector = new SimpleSelector(model.createResource(perx_s),model.createProperty(perx_p),model.createResource(perx_o));StmtIterator it = model.listStatements(selector);if(it.hasNext()){System.out.println("已存在");Statement stmt = model.createStatement(model.createResource(perx_s),model.createProperty(perx_p),model.createResource(perx_o));model.remove(stmt);System.out.println("已刪除");}else{Statement stmt = model.createStatement(model.createResource(perx_s),model.createProperty(perx_p),model.createResource(perx_o));model.add(stmt);System.out.println("已添加");}dataset.close();}? ? ? ? 代碼其實很簡單,就是直接寫入一個三元組數據,這種方式,從我目前理解來說,我覺得不如Resource方式直觀,Resource方式可以維護關系,維護屬性,維護類型等等。
? ? ? ? 這里可以看到有model.remove的方法,通過remove將三元組刪除掉。 這種刪除方式意味著需要先查詢,然后再remove掉。
(2)Resource方式
public static void addSPO(){String NS = "http://www.kgdemo.com#";String directory = "D:\\jena\\ctd" ;Dataset dataset = TDBFactory.createDataset(directory) ;Model model = dataset.getNamedModel("kgMovie");Resource movieClass = ResourceFactory.createResource(NS+"Movie");Property movieTitle = ResourceFactory.createProperty(NS,"movieTitle");Property movieReleaseDate = ResourceFactory.createProperty(NS,"movieReleaseDate");Resource m1 = model.createResource(NS+"movie/2");m1.addProperty(RDF.type,movieClass);m1.addProperty(movieTitle,"大戶西游2");m1.addProperty(movieReleaseDate,"2022-10-22");model.commit();dataset.close();}? ? ? ? 這種方式和ttl能夠對的上,正常情況下,我們肯定也是先設計ttl本體模式層,然后再進行三元組數據生產。 可以通過mysql導入,也可以直接通過界面化的方式新增三元組。 通過界面方式新增三元的方式,就要求我們需要自己按照規范寫入三元組數據。?
? ? ? ? 通過Resource的方式,可以設置class,設置rdf:type,可以設置Property屬性等等。 代碼可以將整個本體描述的規范都體現出來。還是非常方便。
問題記錄
? ? ? ? 我實際預期想要實現的功能是通過Jena API將ttl本體描述文件或者.nt文件的數據導入到TDB中,往TDB中通過api新增三元組數據,然后通過sparql將新增的三元組數據查詢出來。?
? ? ? ? 貼一段查詢的代碼,如下:
public static void test5(){String directory = "D:\\jena\\ctd" ;Dataset dataset = TDBFactory.createDataset(directory) ;// Potentially expensive query.String sparqlQueryString = "SELECT distinct ?s ?p ?o where { ?s ?p ?o}" ;// See http://incubator.apache.org/jena/documentation/query/app_api.htmlModel model = dataset.getNamedModel("kgMovie");Query query = QueryFactory.create(sparqlQueryString) ;QueryExecution qexec = QueryExecutionFactory.create(query, model) ;try {ResultSet results = qexec.execSelect() ;System.out.println(results.hasNext());for ( ; results.hasNext() ; ){QuerySolution soln = results.nextSolution() ;String count =soln.get("o").toString();logger.info("{}-->{}-->{}",soln.get("s"),soln.get("p"),soln.get("o"));}} finally { qexec.close() ; }// Close the dataset.dataset.close();}? ? ? ? 這段代碼中,QueryExecutionFactory.create的第二個入參可以是dataset,也可以是model,如果直接使用的dataset,會發現不管怎樣都查詢不到新增進來的三元組,如果使用model就可以查詢到。?
? ? ? ? 也就是說,在新增三元組的時候,往那個model里新增了,查詢的時候就到那個model里查詢。 dataset默認應該是defaultModel,并不是全部。?
? ? ? ? 至此,除了查詢、推理這塊,整個界面化知識圖譜所需要的技術基本都調研完畢,后續我們可以進行界面化的構建本體、新增和維護三元組數據到指定modelName的模型中去,并提供查詢接口供上層KBQA使用。
參考文獻
【1】使用Jena-TDB存儲RDF本體、知識圖譜文件
【2】導入本體到Jena TDB數據庫
總結
以上是生活随笔為你收集整理的Jena对本体、RDF三元组的API操作记录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 项目管理十大管理过程和知识领域思维导图(
- 下一篇: linux 修复ntfs磁盘,安装和使用