使用Jena-TDB存储RDF本体、知识图谱文件
来源:互联网 发布:淘宝宝贝突然下架 编辑:程序博客网 时间:2024/05/22 17:33
使用Jena-TDB存储RDF本体、知识图谱文件
by 龙前尘
实验环境:win8、Java 1.8、Jena/Jena-TDB 3.0.1
转载请注明地址:
http://blog.csdn.net/svenhuayuncheng/article/details/78751300
何为TDB
RDF是目前通用的本体或知识图谱存储格式,其使用业内统一标准的RDF、RDFS规范,进行知识的组织。
固然,可以将RDF简单地固化到.nt文件,甚至可以直接存储到.txt文件。但若对于RDF有CRUD操作,那么简单地使用文档,是事倍功半的。
为了方便用户管理本体或知识图谱,将RDF固化到一个通用的数据库中,才是最优做法。
将RDF固化,有多种方法,例如基于图数据库的:AllegroGraph1、Neo4j2;或者基于存储固定结构的数据库:关系型数据库、NoSQL数据库;或者基于索引的ES、基于缓存的Redis等。
作为Java中本体文件的管理编辑工具,Jena自然也提供了固化三元组的工具,并且共支持三种模式:RDB、SDB、TDB。
其中,由于速度较慢,RDB(关系数据库)已逐渐式微;SDB是使用 SQL 数据库存储和查询 RDF 数据的模块;TDB是使用triple store的形式对RDF数据提供持久性存储(persistent store)。根据官方文档所述,相比较于SDB,TDB更快、更具扩展性,并且官方对于TDB的支持力度更大3。在Jena官网上,对于SDB和RDB的documentation也不多,而TDB的文档相对详尽。因此,本文选择TDB来做实验,尝试对RDF三元组进行固化和查询操作。
TDB,是Jena用于RDF存储和查询的模块,并且支持所有Jena API。在单机上,TDB可被用于高性能的RDF存储,并且可以使用命令行或者Java API的形式来操作TDB模块。此外,TDB采用了事务(是的,类似于关系型数据库的transaction)来封装数据库操作,防止进程意外终止、系统崩溃等特殊情况带来的数据损坏。同一时间,一个TDB数据集只能被一个JVM虚拟机进程访问,否则会造成数据破坏(脏数据)4。
如果想要多个进程同时访问TDB数据集,需要使用提供SPARQL服务的Fuseki5模块来操作。Fuseki提供SPARQL协议来查询、升级、以及通过HTTP的REST 服务来升级TDB数据。
如何使用TDB
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和POSG6。
在实际操作中,以下几点非常重要。
- 建立Dataset:首先,需要建立一个Dataset对象。Dataset是TDB的一个封装类,可简单地视其为一个数据库;
- 装载Model:其次,需要装载一个Model。Jena的操作都是围绕Model数据结构展开,可视每一个Model为数据库中的一张表。一个Dataset对象里可包含多个Model,类似于一个数据库里面可以包含多张表,这些Model都有各自的名字,用户可以访问某个Model,而不用把所有Model加载到内存。Dataset中默认存在一个DefaultModel;
- 固化TDB文件:再次,装载Model时,需要输入TDB文件夹的地址。该位置就是将包含了RDF数据的Model,固化到TDB的地址。在下次启动时,可以从这个TDB文件地址,读取到之前固化的各个Model。
- 提交和关闭操作:最后,所有update完成后,需要提交Model,提交Dataset,进行事务提交。然后一定要关闭Model,关闭Dataset。
简单地说,操作过程为:新建Dataset对象,将RDF文件的三元组读取到Model中,再将Model对象固化到TDB文件,从而完成数据持久化。
如何安装TDB
- 建议使用Maven管理依赖包:在POM中加入以下依赖
<dependency> <groupId>org.apache.jena</groupId> <artifactId>jena-core</artifactId> <version>3.0.1</version></dependency><dependency> <groupId>org.apache.jena</groupId> <artifactId>jena-tdb</artifactId> <version>3.0.1</version></dependency>
- 加入jar包:在这里下载后,在build path中加入Apache Jena jar包
实验代码
TDB操作类
import com.qa.demo.systemController.FaqDemo;import org.apache.jena.query.Dataset;import org.apache.jena.query.ReadWrite;import org.apache.jena.rdf.model.Model;import org.apache.jena.tdb.TDBFactory;import org.apache.jena.util.FileManager;import org.nlpcn.commons.lang.util.logging.Log;import org.nlpcn.commons.lang.util.logging.LogFactory;import java.util.*;/** * Created time: 2017_11_09 * Author: Devin Hua * Function description: * To accomplish persistence by storing RDF txt file with TDB . */public class TDBPersistence { public static final Log LOG = LogFactory.getLog(FaqDemo.class); public Dataset dataset = null; /** * 建立TDB数据文件夹; */ public TDBPersistence(String tdbName) { dataset = TDBFactory.createDataset(tdbName); } /** * 将rdf文件加载到model中; */ public void loadModel(String modelName, String rdfFilePath, Boolean isOverride) { int result; Model model = null; dataset.begin(ReadWrite.WRITE); try { //已有同名model,且不需要使用新的三元组覆盖旧TDB文件; if (dataset.containsNamedModel(modelName) && (!isOverride)) { result = 1; } //没有同名model,或者有同名文件需要覆盖; else { if (dataset.containsNamedModel(modelName)) result = 2; else result = 3; //移除已有的model; dataset.removeNamedModel(modelName); //建立一个新的TDB Model,一个TDB可以有多个model,类似数据库的多个表; model = dataset.getNamedModel(modelName); //事务开始; model.begin(); //读取RDF文件到model中; FileManager.get().readModel(model, rdfFilePath); //将事务提交; model.commit(); //务必记得将dataset的事务提交,否则无法完成增删改查操作; dataset.commit(); } } catch (Exception e) { LOG.error(e.toString()); result = 0; } finally { if (model != null && !model.isEmpty()) model.close(); dataset.end(); } switch (result) { case 0: LOG.error(modelName + ":读取model错误!"); break; case 1: LOG.info(modelName + ":已有该model,不需要覆盖!"); break; case 2: LOG.info(modelName + ":已有该model,覆盖原TDB文件,并建立新的model!"); break; case 3: LOG.info(modelName + ":建立新的TDB model!"); break; } } /** * 删除Dataset中的某个model; */ public void removeModel(String modelName) { if (!dataset.isInTransaction()) dataset.begin(ReadWrite.WRITE); try { dataset.removeNamedModel(modelName); dataset.commit(); LOG.info(modelName + ":已被移除!"); } finally { dataset.end(); } } /** * 关闭TDB连接; */ public void closeTDB() { dataset.close(); } /** * 判断Dataset中是否存在model; */ public boolean findTDB(String modelName) { boolean result; dataset.begin(ReadWrite.READ); try { if (dataset.containsNamedModel(modelName)) result = true; else result = false; } finally { dataset.end(); } return result; } /** * 列出Dataset中所有model; */ public List<String> listModels() { dataset.begin(ReadWrite.READ); List<String> uriList = new ArrayList<>(); try { Iterator<String> names = dataset.listNames(); String name; while (names.hasNext()) { name = names.next(); uriList.add(name); } } finally { dataset.end(); } return uriList; } /** * 获得Dataset中某个model; */ public Model getModel(String modelName) { Model model; dataset.begin(ReadWrite.READ); try { model = dataset.getNamedModel(modelName); } finally { dataset.end(); } return model; } /** * 获取默认模型; */ public Model getDefaultModel() { dataset.begin(ReadWrite.READ); Model model; try { model = dataset.getDefaultModel(); dataset.commit(); } finally { dataset.end(); } return model; }}
单元测试类
import org.apache.jena.rdf.model.Model;import org.junit.jupiter.api.Test;import java.util.List;class TDBPersistenceTest { @Test void listModels() { //TDB的数据文件夹地址; String TDBPath = "src\\main\\resources\\data\\kbfile\\TDB"; TDBPersistence tdbPersistence = new TDBPersistence(TDBPath); List<String> models = tdbPersistence.listModels(); if (models == null || models.isEmpty() || models.size() == 0) System.out.println("Dataset中不存在非默认model!"); else { for (String model : models) { System.out.println("model: " + model); } } tdbPersistence.closeTDB(); } @Test void loadModel() { //TDB的数据文件夹地址; String TDBPath = "src\\main\\resources\\data\\kbfile\\TDB"; //在Dataset中存放model的名字; String modelName = "TDB_agriculture"; //表示若有同名model,是否需要覆盖; Boolean flag = true; //rdf三元组文件的路径; String rdfPathName = "src/main/resources/data/kbfile/NT_triplets.nt"; //建立对象; TDBPersistence tdbPersistence = new TDBPersistence(TDBPath); //新建model; tdbPersistence.loadModel(modelName, rdfPathName, flag); //事务完成后必须关闭Dataset; tdbPersistence.closeTDB(); }}
在实际操作中,可能会报错:
Code: 4/UNWISE_CHARACTER in PATH: The character matches no grammar rules of URIs/IRIs. These characters are permitted in RDF URI References, XML system identifiers, and XML Schema anyURIs.
遇到这种情况,一般是RDF文件地址写错。注意使用文件的相对路径时,可以参考上述示例代码来写。在代码中,笔者也有提及,大家特别留意。
此外,当完成写操作后,都必须执行model.commit()或dataset.commit(),来完成事务提交,否则TDB固化的数据不会update,也请大家注意。
以上,欢迎大家探讨、指正!
注:TDB操作代码部分参考于博客导入本体到Jena TDB数据库
- http://franz.com/ ↩
- https://neo4j.com/ ↩
- https://jena.apache.org/documentation/sdb/ ↩
- https://jena.apache.org/documentation/tdb/index.html ↩
- https://jena.apache.org/documentation/fuseki2/index.html ↩
- https://www.cnblogs.com/yes-V-can/p/5526096.html ↩
- 使用Jena-TDB存储RDF本体、知识图谱文件
- eclipse中使用Jena解析本体文件
- eclipse中使用Jena解析本体文件
- Jena TDB的使用简介
- Jena TDB
- 使用jena写入多个本体文件到mysql
- 知识图谱1-【什么是RDF?】
- jena下载,做本体使用
- 本体和知识图谱学习
- 用Jena解析本体Ontology Jena的使用 Jena实例
- jena构建本体,读取owl文件,输出owl文件相关知识
- Jena使用教程—RDF Model使用
- Jena,TDB,Sparql
- 【Jena使用手册】Apache Jena导入N-Triple等RDF文件
- 使用Jena ARQ API 查询RDF图
- Jena使用教程---RDF数据的创建
- Jena使用教程---RDF MODEL的理解
- 使用Jena访问RDF数据库环境搭
- 阿里云技术升级 价格调整普惠用户
- React创建类时关于this的疑惑
- 阿里云产品 ECS、RDS、CDN、OCS、OSS、ACE、SLB介绍
- 资料: 关于美国屠杀印第安人的“真相”
- JS学习
- 使用Jena-TDB存储RDF本体、知识图谱文件
- web使用openoffice实现在线预览office文档
- opencv computer vison
- Android源码解析之singleTask launchMode
- 小白使用react——解决this.props.history.push无法跳转的问题
- Docker容器的生命周期管理
- BAT批处理 获取当前系统日期前一天的日期
- Hibernate(八)---管理Session
- JQuery的选择器对控件ID含有特殊字符的解决方法-涨姿势了!