导入本体到Jena TDB数据库
本体的存储方法或称本体持久化,大致分为基于内存的方式、基于文件的方式、基于数据库的方式和专门的管理工具方式4种(傅柱等, 2013)。其中,基于数据库的方式又有基于关系数据库、基于面向对象数据库、基于Native XML数据库和基于NoSQL的三元组数据库(Triple Store)4种主要方式。基于数据库的本体持久化方式充分利用了数据库的安全可靠(数据保密、数据完整性、并发控制、故障恢复等)、高效、易于管理并易于与应用系统集成等优点,是主要的本体持久化方式。
在本体中,数据被表示为一系列由主语(subject)、谓词(predicate)和宾语(object)组成的陈述(statement),即三元组(triple)的集合。基于关系数据库的本体持久化使用二维表对本体的三元组进行处理,不可避免地需要对本体中的复杂关系进行不自然的分解,而查询时又需要将基于图的查询转换为关系查询(傅柱等, 2013) ,需要进行大量的关联、连接操作,因而,现有基于关系数据库的本体存储方法都存在大规模存储、更新、修改和查询效率低、数据库操作代价大等问题(李勇和李跃龙, 2008)。因此,效率、性能更优越的专门或扩展了RDF存储、查询甚至推理能力的非关系型三元组数据库(Triple Store,或称图数据库),如GraphDB (OWLIM) [1]、Virtuoso Universal Server[2]、AllegroGraph[3]、Jena TDB(Triple DB)等(Rohloff et al., 2007)目前已逐渐成为本体存储主流工具。本文采用基于Jena 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和POSG。

如上图所示,本体应用程序首先通过URI(Uniform Resource Identifier)地址映射文件实现本体URI与其对应的本体模块文件存放的文件系统地址的映射,然后使用自定义的Java类TDBPortal通过程序或配置文件读取各本体模块文件持久化到TDB。TDB中数据可通过TDBPortal实现增删改查操作,和进一步应用于本体查询与推理等操作;或作为SPARQL(SPARQL Protocol and RDF Query Language)服务器Jena Fuseki的数据源,对外提供基于HTTP的SPARQL查询服务。
下面介绍TDBPortal
package cn.geodata.ont.tdb; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import org.apache.commons.lang3.StringUtils;
import org.apache.jena.riot.RDFDataMgr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import cn.geodata.ont.file.OntFile; import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.query.Dataset;
import com.hp.hpl.jena.query.ReadWrite;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.tdb.TDBFactory;
import com.hp.hpl.jena.tdb.base.file.Location; /**
* @TODO TDB CRUD操作,包含事务
* @author Zhiwei HOU
* @date 2015年12月2日
*/
public class TDBPortal
{
final static Logger logger = LoggerFactory.getLogger(TDBPortal.class); // 必须close
Dataset ds = null; /**
* 连接TDB
*
* @param tdbPath TDB目录或配置文件tdb-assembler.ttl路径. tdbPath可以通过配置文件进行设置
* @param useAssemblerFile 是否使用配置文件连接
*/
public TDBPortal(String tdbPath, boolean useAssemblerFile)
{
if (!useAssemblerFile)
{
Location location = Location.create(tdbPath);
ds = TDBFactory.createDataset(location);
}
else
ds = TDBFactory.assembleDataset(tdbPath);
} public TDBPortal(String tdbPath)
{
Location location = Location.create(tdbPath);
ds = TDBFactory.createDataset(location);
} /**
* 往模型中添加内容。不载入引用本体
*
* @param modelUri 本体的uri
* @param sourcePath 本体文件实际地址
* @param override 是否覆盖
* @return
* @Houzw at 2016年4月1日下午11:36:13
*/
public int loadModel(String modelUri, String sourcePath, Boolean isOverride)
{
Model model = null;
ds.begin(ReadWrite.WRITE);
try
{
if (ds.containsNamedModel(modelUri))
{
if (isOverride)// 覆盖
{
removeModel(modelUri);//只是移除地址,实际数据不会移除
loadModel(modelUri, sourcePath, false);
}
}
else
{
model = ds.getNamedModel(modelUri);// 没有则创建一个,model不会为null
model.begin();
RDFDataMgr.read(model, sourcePath);
model.commit();
}
// 已有,但是不覆盖,则直接返回
ds.commit();
logger.info("本体模型数据已经导入");
return 1;
}
catch (Exception e)
{
return 0;
}
finally
{
if (model != null)
model.close();
ds.end();
}
} /**
* 导入本体。OntModel不支持事务。同时载入引用本体
*
* @param modelUri 模型uri
* @param sourcePath 本体文件(集成文件)地址
* @param override 是否覆盖
* @return
* @Houzw at 2016年4月1日下午11:36:09
*/
public int loadOntModel(String modelUri, String sourcePath, Boolean isOverride)
{
OntModel model = ModelFactory.createOntologyModel();// 不支持事务
ds.begin(ReadWrite.WRITE);
try
{
if (ds.containsNamedModel(modelUri))
{
if (isOverride)// 覆盖
{
removeModel(modelUri);
loadOntModel(modelUri, sourcePath, false);
}
}
else
{
model = OntFile.loadOntModelWithLocMapper(sourcePath);//导入本体文件
ds.addNamedModel(modelUri, model); }
// 已有,但是不覆盖,则直接返回
ds.commit();
System.out.println(modelUri + " 已导入");
logger.info(modelUri + " 已导入");
return 1;
}
catch (Exception e)
{
System.out.println(e.getLocalizedMessage());
logger.error(e.getLocalizedMessage());
return 0;
}
finally
{
ds.end();
}
} public Model getDefaultModel()
{
ds.begin(ReadWrite.READ);
Model model;
try
{
model = ds.getDefaultModel();
ds.commit();
}
finally
{
ds.end();
}
return model;
} /**
* 获取指定模型
*/
public Model getModel(String modelUri)
{
Model model = null;
ds.begin(ReadWrite.READ);
try
{
model = ds.getNamedModel(modelUri);
}
finally
{
ds.end();
}
return model;
} public void loadDefaultModel(String sourcePath)
{
Model model = null;
ds.begin(ReadWrite.WRITE);
try
{
model = ds.getDefaultModel();
model.begin();
if (!StringUtils.isBlank(sourcePath))
RDFDataMgr.read(model, sourcePath);
model.commit();
ds.commit();
}
finally
{
if (model != null)
model.close();
ds.end();
}
} public void removeModel(String modelUri)
{
if (!ds.isInTransaction())
ds.begin(ReadWrite.WRITE);
try
{
ds.removeNamedModel(modelUri);
ds.commit();
System.out.println(modelUri + " 已被移除");
logger.info(modelUri + " 已被移除");
}
finally
{
ds.end();
}
} /**
* 列出所有模型的uri
*/
public List<String> listModels()
{
ds.begin(ReadWrite.READ);
List<String> uriList = new ArrayList<>();
try
{
Iterator<String> names = ds.listNames();// DefaultModel没有name
String name = null;
while (names.hasNext())
{
name = names.next();
uriList.add(name);
}
}
finally
{
ds.end();
}
return uriList;
} /**
* 必须关闭TDB连接
*/ public void close()
{
ds.close();
}
}
以上简单介绍了基于Jena TDB的本体存储。目前我对AssemblerFile配置文件的配置还没有深入的研究,了解的朋友可以告诉我,O(∩_∩)O谢谢
——————————————————————————————————————
补充:
TDB 也提供了命令行的方式导入本体数据,具体参考官方文档或参考http://blog.csdn.net/rk2900/article/details/38342181
水平有限,错误难免,多指教。TDB 的具体内容可查阅其官方文档
[1] http://ontotext.com/products/graphdb/
[2] http://www.openlinksw.com/
[3] http://franz.com/
导入本体到Jena TDB数据库的更多相关文章
- Jena TDB 101 Java API without Assembler
Update on 2015/05/12 ongoing tutorials site on https://github.com/zhoujiagen/semanticWebTutorialUsin ...
- Jena TDB 102
1 Introduction TDB is a RDF storage of Jena. official guarantees and limitations TDB support full ra ...
- Jena TDB assembler syntax
1 introduction Assembler is a DSL of Jena to specify something to build, models and dataset, for exa ...
- paip.导入数据英文音标到数据库mysql为空的问题之道解决原理
paip.导入数据英文音标到数据库mysql为空的问题之道解决原理 #---原因:mysql 导入工具的bug #---解决:使用双引号不个音标括起来. 作者 老哇的爪子 Attilax 艾龙, E ...
- 一、导入、导出远程Oracle数据库
一.导入.导出远程Oracle数据库 其语法实示例如下: imp/exp [username[/password[@service]]] 其中service是服务实例名,关于如何创建服务实 ...
- paip.将数据导入到在英语语音数据库mysql道路解决空原则问题
paip.将数据导入到在英语语音数据库mysql道路解决空原则问题 #---原因:mysql 导入工具bug #---解决:不要使用双引号括注音. 笔者 老哇爪 Attilax 艾龙. EMAIL: ...
- EXCEL导入GridView,然后再汇入数据库.
原文:EXCEL导入GridView,然后再汇入数据库. 近日项目中有一个多笔料号要输入,我做了一个用javascript复制输入框的功能,可以输入多笔料号. 但是使用者反馈,料号太多,可能几百个料号 ...
- 【exp/imp】将US7ASCII字符集的dmp文件导入到ZHS16GBK字符集的数据库中
[exp/imp]将US7ASCII字符集的dmp文件导入到ZHS16GBK字符集的数据库中 1.1 BLOG文档结构图 1.2 前言部分 1.2.1 导读和注意事项 各位技术爱好者,看完本文后 ...
- (转)如何将 Excel 文件导入到 Navicat for MySQL 数据库
场景:工作中需要统计一段时间的加班时长,人工统计太过麻烦,就想到使用程序实现来统计 1 如何将 Excel 文件导入到 Navicat for MySQL 数据库 Navicat for MySQL ...
随机推荐
- 在父容器div中图片下方有一条空隙问题
问题:<div><img src="mm1.jpg"></div> 然后,表现就是一张图片呈现,类似下面这样: 恩,看上去很正常,一切都是理所当 ...
- java中线程安全问题
在java中单线程和多线程是什么意思,他们有什么区别,分别的作用是什么? 在一个程序中,这些独立运行的程序片断叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”.多线程处理一个常见的例 ...
- 【java基础】java中Object对象中的Hashcode方法的作用
以下是关于HashCode的官方文档定义: hashcode方法返回该对象的哈希码值.支持该方法是为哈希表提供一些优点,例如,java.util.Hashtable 提供的哈希表. hashCode ...
- smarty基本用法,循环,判断
require './smarty/Smarty.class.php'; $sm = new Smarty; $sm->setTemplateDir("./dir");//设 ...
- Python基本序列-字典
Python 基本序列-字典 字典(dict)是"键-值 对"的无序可变序列,字典中的每个元素包含两部分,"键"和"值". 字典中的&quo ...
- GOF23设计模式之策略模式(strategy)
一.策略模式概述 策略模式对应于解决某一个问题的一个算法族,允许用户从该算法族中任选一种算法解决一个问题,同时可以方便的更换算法或者增加新的算法.并且由客户端决定调用哪个算法. 策略模式的本质: 分离 ...
- appium历史版本下载地址
https://github.com/appium/appium-desktop/releases
- python中scipy学习——随机稀疏矩阵及操作
1.生成随机稀疏矩阵: scipy中生成随机稀疏矩阵的函数如下: scipy.sparse.rand(m,n,density,format,dtype,random_state) 1 参数介绍: 参数 ...
- JNI的一个简单实例
本例子使用的操作系统MacOS, 64位JVM. JNI编写的几个步骤如下: 编写Java代码,并注明native方法: public class HelloJni { public native v ...
- Java测试用例简介
最近需要向组内其他成员普及一下关于Java测试用例的相关知识,特在此进行一下简单的学习和总结. JUnit简介 JUnit是一个开源的Java单元测试框架,JUnit4对原有的JUnit框架进行了大幅 ...