当前位置:   article > 正文

使用Jena-TDB存储RDF本体、知识图谱文件_怎样存rdf格式 java

怎样存rdf格式 java

使用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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 加入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;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178

单元测试类

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();
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

在实际操作中,可能会报错:

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数据库

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/370573
推荐阅读
相关标签
  

闽ICP备14008679号