本体的存储方法或称本体持久化,大致分为基于内存的方式、基于文件的方式、基于数据库的方式和专门的管理工具方式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数据库的更多相关文章

  1. Jena TDB 101 Java API without Assembler

    Update on 2015/05/12 ongoing tutorials site on https://github.com/zhoujiagen/semanticWebTutorialUsin ...

  2. Jena TDB 102

    1 Introduction TDB is a RDF storage of Jena. official guarantees and limitations TDB support full ra ...

  3. Jena TDB assembler syntax

    1 introduction Assembler is a DSL of Jena to specify something to build, models and dataset, for exa ...

  4. paip.导入数据英文音标到数据库mysql为空的问题之道解决原理

    paip.导入数据英文音标到数据库mysql为空的问题之道解决原理 #---原因:mysql 导入工具的bug #---解决:使用双引号不个音标括起来. 作者 老哇的爪子 Attilax 艾龙,  E ...

  5. 一、导入、导出远程Oracle数据库

    一.导入.导出远程Oracle数据库  其语法实示例如下:    imp/exp [username[/password[@service]]]   其中service是服务实例名,关于如何创建服务实 ...

  6. paip.将数据导入到在英语语音数据库mysql道路解决空原则问题

    paip.将数据导入到在英语语音数据库mysql道路解决空原则问题 #---原因:mysql 导入工具bug #---解决:不要使用双引号括注音. 笔者 老哇爪 Attilax 艾龙.  EMAIL: ...

  7. EXCEL导入GridView,然后再汇入数据库.

    原文:EXCEL导入GridView,然后再汇入数据库. 近日项目中有一个多笔料号要输入,我做了一个用javascript复制输入框的功能,可以输入多笔料号. 但是使用者反馈,料号太多,可能几百个料号 ...

  8. 【exp/imp】将US7ASCII字符集的dmp文件导入到ZHS16GBK字符集的数据库中

    [exp/imp]将US7ASCII字符集的dmp文件导入到ZHS16GBK字符集的数据库中 1.1  BLOG文档结构图 1.2  前言部分 1.2.1  导读和注意事项 各位技术爱好者,看完本文后 ...

  9. (转)如何将 Excel 文件导入到 Navicat for MySQL 数据库

    场景:工作中需要统计一段时间的加班时长,人工统计太过麻烦,就想到使用程序实现来统计 1 如何将 Excel 文件导入到 Navicat for MySQL 数据库 Navicat for MySQL  ...

随机推荐

  1. BZOJ2946 Poi2000 公共串 【后缀自动机】

    Description 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l 读入单词 l 计算最长公共子串的长度 l 输出结果 Input 文件的第一行是整数 n,1<=n& ...

  2. BZOJ1597土地购买 【斜率优化DP】

    BZOJ1597土地购买 [斜率优化DP] Description 农夫John准备扩大他的农场,他正在考虑N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足( ...

  3. win32窗口样式GWL_EXSTYLE

    Private Const GWL_STYLE = (-16)             '窗口样式 '窗口风格Private Const WS_CAPTION = &HC00000       ...

  4. homeland 开源论坛系统搭建试用

    备注: 需要使用docker docker-compose   1. clone 代码 git clone https://github.com/ruby-china/homeland-docker. ...

  5. k8s helm 包管理私服chartmuseum 安装

    备注:   预备环境需要安装helm  1. 安装chartmuseum  参考 # on Linux curl -LO https://s3.amazonaws.com/chartmuseum/re ...

  6. luarocks yum 安装引起的lapis lua 包查找问题(centos7版本)

    备注:     大家在进行lapis 开发的时候有些人比较懒直接使用yum 按照luarocks,之后   使用luarocks 安装lapis 一般来说对于linux 64位的环境都会有些问题(包找 ...

  7. CSS内容简单归纳

    具体内容请查阅<CSS参考手册> 一.CSS模块介绍 1.1 CSS1中定义了网页基本属性 字体.颜色.补白.基本选择器等 1.2 CSS2中在CSS1的基础上添加了高级功能 浮动和定位. ...

  8. Linux 文件系统目录结构

    进入 Linux 根目录(即 "/",Linux文件系统的入口,也是处于最高一级的目录),运行 "ls -l" 命令,可以看到 Linux 系统目录. 1./b ...

  9. jeecg中List页面的高级查询

    1.普通的高级查询 <t:datagrid name="orderworthList" title="订单价值统计" actionUrl="or ...

  10. 最近遇到的几个纯C编程的陷阱

    首先是一个不容易看出来的语法上的陷阱 经过调试得出的错误是对非socket的socket操作出错,sockfd在调试过程中发现是0,不是一个合理的文件描述符. 仔细一看原来是括号忘记加了,该运算是先用 ...