使用NebulaGraph Importer导入OwnThink数据

wylc123 1年前 ⋅ 205 阅读

前言

本文由 NebulaGraph 实习生@王杰贡献。

最近 @Yener 开源了史上最大规模的中文知识图谱——OwnThink(链接:https://github.com/ownthink/KnowledgeGraphData ),数据量为 1.4 亿条。

本文介绍如何将这份数据快速导入图数据库 NebulaGraph,全过程大约需要 30 分钟。

中文知识图谱 OwnThink 简介

思知(OwnThink)

知识图谱是由 Google 在 2012 年提出来的一个概念。主要是用来描述真实世界中存在的各种实体和概念,以及他们之间的关系。在搜索引擎、问答机器人、知识抽取等多个领域有着诸多应用。

最近 Yener 开源了史上最大规模的中文知识图谱—— OwnThink(链接:https://github.com/ownthink/KnowledgeGraphData),数据量为 1.4 亿条。数据以 (实体, 属性, 值) 和 (实体, 关系, 实体) 混合的三元组形式存储,数据格式为 csv。

百度网盘(链接: https://pan.baidu.com/s/1LZjs9Dsta0yD9NH-1y0sAw 提取码: 3hpp )注:解压密码是:https://www.ownthink.com/

查看原始文件

由于 ownthink_v2.csv 数据过多,摘录部分数据为例:

红色食品,描述,红色食品是指食品为红色、橙红色或棕红色的食品。

红色食品,是否含防腐剂,否
红色食品,主要食用功效,预防感冒,缓解疲劳
红色食品,用途,增强表皮细胞再生和防止皮肤衰老
大龙湫,描述,雁荡山景区分散,东起羊角洞,西至锯板岭;南起筋竹溪,北至六坪山。
大龙湫,中文名称,大龙湫
大龙湫,外文名称,big dragon autrum
大龙湫,门票价格,50元
大龙湫,著名景点,芙蓉峰
姚明[中国篮球协会主席、中职联公司董事长],妻子,叶莉

这里的 (红色食品,是否含防腐剂,否) 就是典型的 (实体, 属性, 值) 形式的三元组数据; 而 (姚明[中国篮球协会主席、中职联公司董事长],妻子,叶莉) 是典型的 (实体, 关系, 实体) 形式的三元组数据。

Step 1. 数据建模与清洗准备

建模

NebulaGraph 是一个开源的分布式图数据库(链接:https://github.com/vesoft-inc/nebula),相比 Neo4j 来说,它的主要特点是完全的分布式,因此图数据库 NebulaGraph 适合处理数据量超过单机的场景

图数据库通常支持的数据模型为有向属性图(directed property graph)。图中的每个顶点(vertex)可以用标签(tag)来表示类型(Neo4j 叫做 Label),顶点和顶点之间的关系用边(edge)连接起来。每种 tag 和 edge 还可以带有属性。——然而,这些功能对于知识图谱的三元组数据没什么意义:

分析上图的三元组数据,发现无论是 (实体, 属性, 值) 形式的三元组数据,还是 (实体, 关系, 实体) 形式的三元组数据,每条三元组数据均可以建模成两个点一条边的形式。前者三元组中的“实体”和“”建模为两个点(起点、终点),“属性”建模为一条边,后者三元组中的两个“实体”也建模为两个点(起点、终点),“关系”建模为一条边.

而且,所有的点都是相同类型(取名叫entity ),只需要一个属性(叫 name ),所有的边也都是同一类型(取名叫 relation ),边上也只有一个属性(叫 name )。

比如 (大龙湫,著名景点,芙蓉峰) 可以表示成下图这个样子:

数据清洗和预处理

按照前一节的分析,原始的每条三元组数据,还需要清洗转换为两个点和一条边才能变成属性图的模型。

下载清洗工具

本文测试的时候,使用的操作系统是 CentOS 7.5,工具由 Golang 语言编写而成。

你可以在这里(链接:https://github.com/jievince/rdf-converter)下载这个简单的清洗工具源代码并编译使用。

注意最新版的清洗后删掉了vid,可以使用这个版本:

remove hash operation for vid by Nicole00 · Pull Request #6 · jievince/rdf-converter · GitHub

该工具会把转换后的顶点的数据写入到 vertex.csv 文件、边数据写入到 edge.csv 文件。

说明:在测试过程中,发现有大量的重复点数据,所以工具里面也做了去重。完全去重后的点的数据大概是 4600 万条,完全去重后的边的数据大概是 1 亿 4000 万条。

清洗完的 vertex.csv 文件长这样:

-2469395383949115281,过度包装
-5567206714840433083,Over  Package
3836323934884101628,有的商品故意增加包装层数
1185893106173039861,很多采用实木、金属制品
3455734391170888430,非科学
9183164258636124946,教育
5258679239570815125,成熟市场
-8062106589304861485,"成熟市场是指低增长率,高占有率的市场。"

说明:每一行是一个顶点,第一列整型 -2469395383949115281 是顶点的 ID(叫做 VID),它是由第二列文字通过 hash 计算出来的,例如 -2469395383949115281 就是由 std::hash("过度包装") 计算出来的值。

清洗完的 edge.csv 文件:

3413383836870836248,-948987595135324087,含义
3413383836870836248,8037179844375033188,定义
3413383836870836248,-2559124418148243756,标签
3413383836870836248,8108596883039039864,标签
2587975790775251569,-4666568475926279810,描述
2587975790775251569,2587975790775251569,中文名称
2587975790775251569,3771551033890875715,外文名称
2587975790775251569,2900555761857775043,地理位置
2587975790775251569,-1913521037799946160,占地面积
2587975790775251569,-1374607753051283066,开放时间

说明:第一列是起点的 VID,第二列是终点的 VID,第三列是这条边的"属性"或者"描述"。

在本机完全去重的清洗程序运行时间大约是 6 分钟。

Step 2. NebulaGraph 启动准备

下载和安装

登陆 GitHub 后,在这里(链接:https://github.com/vesoft-inc/nebula/actions)找到 Nebula 的安装包。

找到你所用系统对应的下载链接:

笔者系统是 CentOS 7.5,下载 CentOS 7.5 最新的压缩包,解压后能找到 rpm 安装包 nebula-5ace754.el7-5.x86_64.rpm,注意 5ace754 是 git commit 号,使用时可能会有所不同。下载好后解压,输入下面命令进行安装,记得替换成新的 git commit:

$ rpm -ivh nebula-5ace754.el7-5.x86_64.rpm

启动 NebulaGraph 服务

在 命令行 CLI 输入下面命令启动服务

$ /usr/local/nebula/scripts/nebula.service start all

命令执行结果如下:

可以执行以下命令检查服务是否成功启动

$ /usr/local/nebula/scripts/nebula.service status all

命令执行结果如下:

连接 NebulaGraph 服务

输入下面命令连接 NebulaGraph:

$ /usr/local/nebula/bin/nebula -u user -p password

命令执行结果如下:

准备 schema 等元数据

NebulaGraph 的使用风格有点接近 MySQL,需要先准备各种元信息。

新建图空间 space

create space 的概念接近 MySQL 里面 create database。在 nebula console 里面输入下面这个命令。

nebula> CREATE SPACE test;

进入 test space

nebula> USE test;

创建点类型(entity)

nebula> CREATE TAG entity(name string);

创建边类型 (relation)

nebula> CREATE EDGE relation(name string);

最后简单确认下元数据是不是正确。

查看 entity 标签的属性

nebula> DESCRIBE TAG entity;

结果如下:

查看 relation 边类型的属性

nebula> DESCRIBE EDGE relation;

结果如下:

Step 3. 使用 nebula-importer 导入数据

登陆 GitHub 进入 https://github.com/vesoft-inc/nebula-importer ,nebula-importer 这个工具也是 Golang 语言写的,在这里下载并编译源代码。

另外,准备一个 YAML 配置文件,告诉这个 importer 工具去哪里找 csv 文件。(可直接复制下面这段)

version: v2

description: example

# 是否删除临时生成的日志和错误数据文件。
removeTempFiles: false

clientSettings:

  # nGQL 语句执行失败的重试次数。
  retry: 6

  # NebulaGraph 客户端并发数。
  concurrency: 10 

  # 每个 NebulaGraph 客户端的缓存队列大小。
  channelBufferSize: 128

  # 指定数据要导入的 NebulaGraph 图空间。
  space: ownthink

  # 连接信息。
  connection:
    user: root
    password: nebula
    address: 192.168.137.77:9669 

  postStart:
    # 配置连接 NebulaGraph 服务器之后,在插入数据之前执行的一些操作。
    commands: |
      DROP SPACE IF EXISTS ownthink;
      CREATE SPACE IF NOT EXISTS ownthink(partition_num=50, vid_type=FIXED_STRING(20));
      USE ownthink;
      CREATE  TAG IF NOT EXISTS `entity`(name string);
      CREATE EDGE IF NOT EXISTS `relation`(name string);

    # 执行上述命令后到执行插入数据命令之间的间隔。
    afterPeriod: 15s

  preStop:
    # 配置断开 NebulaGraph 服务器连接之前执行的一些操作。
    commands: |
      SUBMIT JOB STATS;


# 错误等日志信息输出的文件路径。    
logPath: ./err/importer.log

# CSV 文件相关设置。
files:

    # 数据文件的存放路径,如果使用相对路径,则会将路径和当前配置文件的目录拼接。本示例第一个数据文件为点的数据。
  - path: ./vertex.csv

    # 插入失败的数据文件存放路径,以便后面补写数据。
    failDataPath: ./err/vertexerr

    # 单批次插入数据的语句数量。
    batchSize: 128

    # 读取数据的行数限制。
    #limit: 10

    # 是否按顺序在文件中插入数据行。如果为 false,可以避免数据倾斜导致的导入速率降低。
    inOrder: true

    # 文件类型,当前仅支持 csv。
    type: csv

    csv:
      # 是否有表头。
      withHeader: false

      # 是否有 LABEL。
      withLabel: false

      # 指定 csv 文件的分隔符。只支持一个字符的字符串分隔符。
      delimiter: ","

    schema:
      # Schema 的类型,可选值为 vertex 和 edge。
      type: vertex

      vertex:

        # 点 ID 设置。
        vid:
           # 点 ID 对应 CSV 文件中列的序号。CSV 文件中列的序号从 0 开始。
           index: 0

           # 点 ID 的数据类型,可选值为 int 和 string,分别对应 NebulaGraph 中的 INT64 和 FIXED_STRING。
           type: string

        # Tag 设置。   
        tags:
            # Tag 名称。
          - name: entity

            # Tag 内的属性设置。
            props:
                # 属性名称。
              - name: name

                # 属性数据类型。
                type: string

                # 属性对应 CSV 文件中列的序号。
                index: 1
                
    # 本示例第二个数据文件为边的数据。
  - path: ./edge.csv
    failDataPath: ./err/edgeerr
    batchSize: 128
    #limit: 10
    inOrder: true
    type: csv
    csv:
      withHeader: false
      withLabel: false
    schema:
      # Schema 的类型为 edge。
      type: edge
      edge:
        # Edge type 名称。
        name: relation

        # 是否包含 rank。
        withRanking: false

        # 起始点 ID 设置。
        srcVID:
           # 数据类型。
           type: string

           # 起始点 ID 对应 CSV 文件中列的序号。
           index: 0

        # 目的点 ID 设置。
        dstVID:
           type: string
           index: 1

        # rank 设置。
        #rank:
           # rank 值对应 CSV 文件中列的序号。如果没有设置 index,请务必在第三列设置 rank 的值。之后的列依次设置各属性。
           #index: 2

        # Edge type 内的属性设置。
        props:
             # 属性名称。
           - name: name

             # 属性数据类型。
             type: string

             # 属性对应 CSV 文件中列的序号。
             index: 2                                

说明:测试时候发现 csv 数据文件中有大量转义字符 (\) 和换行字符 (\r),nebula-importer 也做了处理。

最后:开始导入数据 ??

./rdf-converter --config ./config.yaml

执行过程如下:

可以看到, 本次导入 QPS 大约在 40 w/s。全部导入总耗时大约 42 min。

Step 4. 随便读点什么试试

导入完毕后,我们可以使用 NebulaGraph 服务做一些简单的查询。回到 NebulaGraph 的命令行 CLI :

$ /usr/local/nebula/bin/nebula -u user -p password

进入刚才导入的三元组数据的 test 空间:

nebula> USE test;

现在,我们可以做一些简单查询

  • 例 1:与姚明有直接关联的边的类型和点的属性
(user@127.0.0.1) [test]> GO FROM hash("姚明[中国篮球协会主席、中职联公司董事长]") OVER relation  YIELD relation.name AS Name, $$.entity.name AS Value;

执行结果如下:

可以看到:本次查询返回 51 条数据,耗时 3 ms 左右;

  • 例2:查询姚明和其妻子叶莉在三跳之内的所有路径
(user@127.0.0.1) [test]> FIND ALL PATH FROM hash("姚明[中国篮球协会主席、中职联公司董事长]")  TO hash("叶莉") OVER relation UPTO 3 STEPS; 

执行结果如下:

当数据量较大时,查找全路径/最短经之类的操作会比较耗时。可以看到:本次查询返回 8 条数据,说明姚明和其妻子叶莉在三跳之内共有 8 条直接或间接的关系。

总结

本篇文章涉及到的一些概念和链接:

后面的工作

  • 调整 Nebula 的参数。似乎默认的日志级别和内存都不是很好,可以用下面这个命令关闭日志,这样导入性能可以好很多。
curl "http://127.0.0.1:12000/set_flags?flag=minloglevel&value=4"
  • 写个对应的 Python 版本示例

附录

NebulaGraph GitHub 地址:https://github.com/vesoft-inc/nebula

交流图数据库技术?加入 Nebula 交流群请先填写下你的 Nebula 名片,Nebula 小助手会拉你进群~~

NebulaGraph:一个开源的分布式图数据库。

GitHub:https://github.com/vesoft-inc/nebula

知乎:https://www.zhihu.com/org/nebulagraph/posts

微博:https://weibo.com/nebulagraph

来源:使用图数据库 Nebula Graph 数据导入快速体验知识图谱 OwnThink - 写文章·博客分享 / 特性讲解 - NebulaGraph 社区 (nebula-graph.com.cn)


相关文章推荐

全部评论: 0

    我有话说: