使用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;elseresult = 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;elseresult = 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 {@Testvoid 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();}@Testvoid 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数据库


  1. http://franz.com/ ↩
  2. https://neo4j.com/ ↩
  3. https://jena.apache.org/documentation/sdb/ ↩
  4. https://jena.apache.org/documentation/tdb/index.html ↩
  5. https://jena.apache.org/documentation/fuseki2/index.html ↩
  6. https://www.cnblogs.com/yes-V-can/p/5526096.html ↩

使用Jena-TDB存储RDF本体、知识图谱文件相关推荐

  1. 知识图谱(八)——知识存储和检索

    背景 知识图谱是一种有向图结构,描述了现实世界存在的实体.事件或者概念以及它们之间的关系,为自动问答.信息检索等应用提供支撑.其中,图中的节点表示实体.事件或概念,图中的边表示相邻节点间的关系,如下图 ...

  2. 知识图谱实践篇(四):Apache jena SPARQL endpoint及推理

    在上一篇我们学习了如何利用D2RQ来开启endpoint服务,但它有两个缺点: 1. 不支持直接将RDF数据通过endpoint发布到网络上. 2. 不支持推理. 这次我们介绍的Apache Jena ...

  3. 知识图谱:RDF 或LPG(属性图),您应该选择哪一个?

    Graph正在成为一种广泛使用的数据表示方法,因为它们提供了灵活性.因此,用于图形数据管理的数字技术越来越受欢迎.到 2023 年,图形技术将促进全球30%的组织更快地实现数据情境化. 最流行的图数据 ...

  4. 知识图谱与数据库技术:RDF三元组库和Neo4j图数据库

    知识图谱与数据库系统 随着知识图谱规模的日益增长,知识图谱数据管理问题愈加突出.近年来,知识图谱和数据库领域均认识到大规模知识图谱数据管理任务的紧迫性. 由于传统关系数据库无法有效适应知识图谱的图数据 ...

  5. 【知识图谱】(task3)知识图谱的存储和查询

    note 用图数据库的场景: 高性能关系查询:需要快速遍历许多复杂关系的任何用例,如欺诈检测,社交网络分析,网络和数据库基础设施等: 模型的灵活性:任何依赖于添加新数据而不会中断现有查询池的用例.模型 ...

  6. 配置Fuseki服务器管理知识图谱三元组

    配置Fuseki服务器管理知识图谱三元组 By 龙前尘 实验环境:Win8.apache-jena-fuseki-3.5.0 转载请注明地址: http://blog.csdn.net/svenhua ...

  7. 知识图谱构建技术初探

    自底向上--知识图谱构建技术初探 from: https://www.anquanke.com/post/id/149122 发布时间:2018-06-28 16:00:40 文/阿里安全 染青 &q ...

  8. 自底向上构建知识图谱全过程

    http://www.sohu.com/a/245246344_160850 阿里妹导读:知识图谱的构建技术主要有自顶向下和自底向上两种.其中自顶向下构建是指借助百科类网站等结构化数据源,从高质量数据 ...

  9. CCKS-2017 行业知识图谱构建与应用-下篇

    http://www.sohu.com/a/192557627_99934777 摘要: 这篇是PPT的下半部分,更加偏重于实战中关键技术的难点剖析. 行业知识图谱关键技术 上篇我们讲行业知识图谱生命 ...

  10. 通俗讲解自底向上构建知识图谱全过程

    知识图谱的基础介绍,供学习参考. 转载自:https://mp.weixin.qq.com/s/7cBbtqvPQUVrLZUNDx8XDQ 知识图谱的构建技术主要有自顶向下和自底向上两种.其中自顶向 ...

最新文章

  1. 介绍几款浏览器兼容性测试工具
  2. python画层次结构图_Maptree-层级结构数据展示的绝佳尝试
  3. c/c++文件I/O函数学习--不断补充
  4. curl提示不支持https协议解决方法
  5. java中mq组建是什么_Java教程之RabbitMQ介绍
  6. linux postfix 日志,linux – 如何计算Postfix的mailq的消息?
  7. Linux 系统应用编程——进程间通信(上)
  8. centos 启动一个redis_基于prometheus+grafana体系监控redis缓存服务
  9. java jni helloword_JNI学习一:编写HelloWorld程序
  10. 5G边缘计算:开源架起5G MEC生态发展新通路
  11. 110 redis的哨兵集群 redis-cluster docker安装
  12. C++11模板友元语法
  13. STM32—ADC多通道采集电压
  14. matlab 有限元 图书,MATLAB有限元分析与应用
  15. matlab 频散曲线,Matlab绘制频散曲线程序代码
  16. 第五讲 中外数学名题趣题欣赏与解析
  17. WPF随笔(四)--窗口多屏显示及全屏
  18. 服务器修复oxc0000098,修复oxc0000098的方法
  19. 搜索引擎代码资源[转]
  20. Linux的命令回收站在哪,Trash-Cli:Linux 上的命令行回收站工具

热门文章

  1. CNC:CNC计算机数控系统技术之数控仿真宏程序代码讲解、案例应用集合之详细攻略
  2. 22. 关于定时任务指定的时间间隔内没有完成任务的处理
  3. 怎么将flac文件转成mp3文件?
  4. 网站选用老域名还是新域名好?
  5. 记录一下近期自己的顿悟
  6. 大数据与云计算之间的联系,一篇文章搞明白!
  7. LeanCloud带图形校验码的短信发送Vue组件开发
  8. STM32MP1如何让洗衣机操作界面更炫酷?
  9. QLCDNumber设置背景色和显示数字颜色
  10. SAT数学:必背公式之三角函数