本贴最后更新于 431 天前,其中的信息可能已经时异事殊

版权声明:可以任意转载,转载时请标明文章原始出处和作者信息:石磊

背景

知识图谱越来越火,技术人员开始习惯使用 Sparql 查询 RDF 数据。但是,我们如何构建一个 RDF 数据呢?

因为之前互联网上没有相关工具介绍的文章,所以,这里,我对常见的两种 RDF 构造工具做一个介绍。

相关知识

RDF

“资源描述框架(Resource Description Framework,RDF)”成为 W3C 推荐标准,与 XML 和 SOAP 等 Web 标准并排。RDF 可以应用于处理特殊输入数据(如 CRM)的领域,已经广泛用于社会网络和自助出版软件(如 LiveJournal 和 TypePad)。

关于 RDF 推荐去阮一峰的资源描述框架 RDF 进行了解,因为其介绍的浅显易懂。

Sparql

比如说我们查询 mysql, 使用的是 sql 语言,那么我们查询 RDf 数据,使用的就是 SPARQL。

学习这个语言的话,推荐直接去官方学习:https://www.w3.org/TR/rdf-sparql-query/

介绍列表

  • Jena

    Java 语言编写的,具有推理功能,适合开发和技术研究使用。

  • rdflib

    Python 语言编写的,但是功能简单,有基本的查询和构建功能。

Jena

Java 程序员将越来越多地得益于具有使用 RDF 模型的技能。在本文中,我将带您体验惠普实验室的开放源代码 Jena Semantic Web Framework(请参阅 官网)的一些功能。您将了解如何创建和填充 RDF 模型,如何将它们持久存储到数据库中,以及如何使用 RDQL 查询语言以程序方式查询这些模型。最后,我将说明如何使用 Jena 的推理能力从本体推断模型知识。

对于专业人员来说,大家直接阅读官网就行,但是新手对官网很迷茫,不知道怎么看,所以将推荐看的东西说一下。

  1. 简单的 RDF 介绍和 Sparql 查询相结合:http://jena.apache.org/tutorials/rdf_api.html
  2. https://github.com/apache/jena/tree/master/jena-core/src-examples 这里有十个例子,结合博客把它看懂,基本操作就基本没问题了。

写 triple

下面的函数分为 SPO 中 O 是否是 Node 节点来区分。在注释中举了两个例子。并且在主函数中给出了一个测试方式。

import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.rdf.model.Property;
import org.apache.jena.rdf.model.RDFNode;
import org.apache.jena.rdf.model.Resource;

import config.Config;

public class WriteRdf {

    public static void main(String[] args) {
        // 函数示例
        Model model = ModelFactory.createDefaultModel();
        writeAnTripleWhenObjectIsNode(model, "数组", "分面", "二维数组");
        model.write(System.out, "N3");
    }

    /**
     * 例子: < 周杰伦 > < 年龄 > '35'
     */
    public static void writeAnTripleWhenObjectIsNotNode(Model model, String s, String p, String o) {

        Property property = model.createProperty(p);
        model.createResource(s).addProperty(property, o);
    }

    /**
     * 例子: < 周杰伦 > < 妻子 > < 昆凌 >
     */
    public static void writeAnTripleWhenObjectIsNode(Model model, String s, String p, String o) {
        Resource resource = model.createResource(s);
        Property property = model.createProperty(p);
        RDFNode object = model.createResource(o);
        model.add(resource, property, object);
    }

}

导入 RDF 数据到 Jena 中

RDF 数据格式有很多,但是 jena 内部的数据是以 TDB 形式存在的,需要把 RDf 这些文本文件转化为 jena 自己的模型。这里给出三种方法:


    public static void save1() {
        String directory = "C:\\RDFdata\\Database1\\";
        Dataset ds = TDBFactory.createDataset(directory);
        Model model = ds.getDefaultModel();// 这里使用 TDB 的默认 Model
        String source = "C:\\RDFdata\\source\\drugs.nq";
        TDBLoader.loadModel(model, source); 
        ds.end();
        System.out.println("done");
    }

    public static void save2() {
        String directory = "C:\\RDFdata\\Database2\\";
        Dataset ds = TDBFactory.createDataset(directory);
        Model model = ds.getDefaultModel();// 这里使用 TDB 的默认 Model
        FileManager.get().readModel(model, "C:\\RDFdata\\source\\drugs.nq");
        ds.end();
        System.out.println("done");
    }

    public static void save3()  {
        Dataset ds = TDBFactory.createDataset("D:\\RDFdata\\1\\");
        String filename = "D://rdf.nt2";
        RDFDataMgr.read(ds, filename,Lang.N3);
        ds.close();
        System.out.println("done"); 
    }

### 查询

首先获取到 model

        Dataset ds = TDBFactory.createDataset("D:\\pdd\\");
        Model model = ds.getDefaultModel();

然后编写 sparql 语句,再进行查询

                String query111=
                "select (count(*) as ?num)" +
                        "Where"+
                        "{"+    
                            "?s <http://kmap.xjtudlc.com/pdd_data/property/diagnoses_icd9>  ?o."+
                        "}";
        QueryExecution qexec = QueryExecutionFactory.create(query111, model);
        System.out.println(qexec.getQuery().toString());
        ResultSet resultSet = qexec.execSelect();

        String rerult = ResultSetFormatter.asText(resultSet);
        System.out.println(rerult);

输出形式有很多,也可以遍历进行输出,并输出自己想要的结果。

比如,我们想获取某一个属性 o,

            ResultSet resultSet = qexec.execSelect();
        String o="";
        List<QuerySolution> rerult2 = ResultSetFormatter.toList(resultSet);
        System.out.println(rerult2.size());
        for (QuerySolution querySolution : rerult2) {
            o=querySolution.get("o").toString();
            System.out.println(o);
        }

其他

除了这些,jena 的特斯就是进行推理,可以将查询图进行分析。这里我用的不多,就不进行展示了。

rdflib

RDFLib 工作处理 RDF 是一个纯 Python 包。

RDFLib 包含大多数处理 RDF 的东西, 包括:

  1. 解析和序列化 RDF/XML, N3, NTriples, N-Quads, Turtle, TriX, RDFa and Microdata.
  2. 一个图模型
  3. 存储模型.
  4. SPARQL 1.1 实现 - 支持 SPARQL 1.1 查询和更新数据.

官方网站: https://rdflib.readthedocs.io

### 导入文件

# 导入 nt 文件
from rdflib import Graph

g = Graph()

'''
format: 'rdf/xml' 'xml', 'n3', 'nt', 'trix', 'rdfa'
'''
g.parse("icd10.nt", format="n3")

# 打印图的大小
print(len(g))  # prints 2

# 遍历所有三元组
import pprint

for stmt in g:
    pprint.pprint(stmt)

支持的文件格式有:’rdf/xml’ ‘xml’, ‘n3’, ‘nt’, ‘trix’, ‘rdfa’

创建 RDF 文件

增加一个节点,并以 turtle 形式序列化输出

from rdflib import Graph
g = Graph()

g.add( (bob, RDF.type, FOAF.Person) )
g.add( (bob, FOAF.name, name) )
g.add( (bob, FOAF.knows, linda) )
g.add( (linda, RDF.type, FOAF.Person) )
g.add( (linda, FOAF.name, Literal('Linda') ) )

print g.serialize(format='turtle')

Sparql 查询

# 利用 SPARQL 进行查询
qres = g.query("""
    SELECT *
    WHERE {?subject ?predicate  ?object} 
    LImit 10

""")

for row in qres:
    print(row)

对比

  1. python 版本的 rdflib 包 更简洁,语法简单,更容易理解
  2. rdflib 的官方文档更加简洁,符合新手的认知能力,建议初学者使用 python 来进行最好!
  3. Jena 文档首先需要吐槽,很不友好。
  4. Jena 的持久化做的比较好,在查询方式,序列化方式等方面做的更加专业。
  5. Jena 提供了持久化的事务能力。
  6. Jena 提供了远程调用方案,可以解决数据共享问题。我们可以开放一个 a SPARQL end-point 让其他人通过 http 连连接,就像 DBpedia 提供的查询接口一样。
  7. 总体来说,jena 更专业一点,rdflib 对新用户更友好,功能也够用。

PDD 与 我

我作为核心成员,发布了一个医疗的数据集 PDD,在 http://kmap.xjtudlc.com/pdd/ 同时,我们最近在整理最新的 ICD10 的数据集,与湘雅医院、腾讯的移动互联事业群(微信)在合作,准备利用知识图谱进行疾病诊断与药物推荐等方面工作。

  • 知识图谱
    1 引用 • 3 回帖
  • rdf
    2 引用 • 6 回帖
  • jena
    1 引用 • 3 回帖
  • Python

    Python 是一种面向对象、直译式电脑编程语言,具有近二十年的发展历史,成熟且稳定。它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务。它的语法简捷和清晰,尽量使用无异义的英语单词,与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块。

    212 引用 • 360 回帖 • 895 关注
感谢    关注    收藏    赞同    反对    举报    分享