自留地

Dgraph-查询语言

2018-11-21  本文已影响1076人  羽_da59

查询语言

Dgraph的GraphQL+-是一种基于facebook的GraphQL的图查询语言。GraphQL并不是专门用于图数据库的,但是它像图一样的查询语法,schema验证以及子图形式的response使它成为一个非常好的语言选择。我们修改了这个语言,并且移除了某些feature,使它可以更好地支持图操作,更好地适用于图数据库,并将新的语言命名为“GraphQL+-”

GraphQL+-还在继续改进,我们在添加更多的feature,将来也会简化某些已有的feature

1. GraphQL+-基础

一个GraphQL+-查询会基于查询规范在图中进行匹配,并返回一个图作为结果

查询从查询root开始,由嵌套块组成。root会找到初始的node集合,供后面的匹配及过滤用

1.1.1 返回值

每个查询都有名字,由查询的root指定,查询结果也会使用这个名字

2.Facets:边属性

Dgraph支持facets(边上的键值对),来作为RDF三元组的扩展。Facets可以将属性添加到边上,而不是节点上。例如,两个人之间的friend边可以加上close属性,来标识友谊是否终结。Facets也可以用作边的权重

尽管你可能会学过很多遍facets,你还是可能会用错。例如你不应该给friend边加上date_of_birth这样的facet,而应该加上start_of_friendship这样的facet

注意,Facet不是Dgraph的第一公民

Facet的key是string,value可以是string, bool, int, float 或者 dateTime。对于int与float,只能是32位有符号的decimial interger,以及64位单浮点值

下面的mutation在mobile以及car上加了名为since的facet,记录Alice买车以及开始用这个手机号的时间

首先添加schema:

//ALTER
name: string @index(exact, term) .
rated: uid @reverse @count .

插入数据:

//MUTATE
{
  set {

    # -- Facets on scalar predicates
    _:alice <name> "Alice" .
    _:alice <mobile> "040123456" (since=2006-01-02T15:04:05) .
    _:alice <car> "MA0123" (since=2006-02-02T13:01:09, first=true) .

    _:bob <name> "Bob" .
    _:bob <car> "MA0134" (since=2006-02-02T13:01:09) .

    _:charlie <name> "Charlie" .
    _:dave <name> "Dave" .


    # -- Facets on UID predicates
    _:alice <friend> _:bob (close=true, relative=false) .
    _:alice <friend> _:charlie (close=false, relative=true) .
    _:alice <friend> _:dave (close=true, relative=true) .


    # -- Facets for variable propagation
    _:movie1 <name> "Movie 1" .
    _:movie2 <name> "Movie 2" .
    _:movie3 <name> "Movie 3" .

    _:alice <rated> _:movie1 (rating=3) .
    _:alice <rated> _:movie2 (rating=2) .
    _:alice <rated> _:movie3 (rating=5) .

    _:bob <rated> _:movie1 (rating=5) .
    _:bob <rated> _:movie2 (rating=5) .
    _:bob <rated> _:movie3 (rating=5) .

    _:charlie <rated> _:movie1 (rating=2) .
    _:charlie <rated> _:movie2 (rating=5) .
    _:charlie <rated> _:movie3 (rating=1) .
  }
}

2.1 标量谓语(value边)上的facet

查询Alice的name、mobile以及car返回的结果与没有facet是一样的

{  
  alice(func: eq(name,"Alice")){
     name
     mobile
     car
  }
}

语法@facets(facet-name)用于查询facet数据,Alice的sincefacet应该按如下的方式查询:

{
  data(func: eq(name, "Alice")) {
     name
     mobile @facets(since)
     car @facets(since)
  }
}

返回结果:

{
  "data": {
    "data": [
      {
        "name": "Alice",
        "mobile|since": "2006-01-02T15:04:05Z",
        "mobile": "040123456",
        "car|since": "2006-02-02T13:01:09Z",
        "car": "MA0123"
      }
    ]
  }
}

Facet会在相应边的统一level返回,key的格式是edgename|facetname

如果要查询某个边上的所有facet,使用@facets不加参数即可:

{
  data(func: eq(name, "Alice")) {
     name
     mobile @facets
     car @facets
  }
}

2.2 Facet的别名

在查询某个谓语时,可以指定别名,格式类似于请求其他谓语的别名。orderascorderdesc不能用作别名,因为它们有特别意义,其他的任何字符串都能用作别名

在这里,我们给分别给since, close两个facet设置别名car_since, close_friend

{
   data(func: eq(name, "Alice")) {
     name
     mobile
     car @facets(car_since: since)
     friend @facets(close_friend: close) {
       name
     }
   }
}

2.3 UID谓语(uid边)的facet

UID边上的域名类似于value边

例如,friend是有一个名为close的facet的边

查询friend边的close facet:

{
   data(func: eq(name, "Alice")) {
     name
     friend @facets(close) {
       name
     }
   }
}

对于像friend这种的uid边,facet会进入edge|facet下面相应的子节点。上面的例子中你会看到,Alice与Bob之间的friend|close与Bob的结果出现在一起:

{
  "data": {
    "data": [
      {
        "name": "Alice",
        "friend": [
          {
            "name": "Charlie",
            "friend|close": false
          },
          {
            "name": "Dave",
            "friend|close": true
          },
          {
            "name": "Bob",
            "friend|close": true
          }
        ]
      }
    ]
  }
}

Bob有一辆车,并且这个车有一个名为since的facet,在下面的例子中我们可以看到car|since也是在Bob的属性里:

{
  data(func: eq(name, "Alice")) {
    name
    friend @facets {
      name
      car @facets
    }
  }
}
{
  "data": {
    "data": [
      {
        "name": "Alice",
        "friend": [
          {
            "name": "Charlie",
            "friend|close": false,
            "friend|relative": true
          },
          {
            "name": "Dave",
            "friend|close": true,
            "friend|relative": true
          },
          {
            "name": "Bob",
            "car|since": "2006-02-02T13:01:09Z",
            "car": "MA0134",
            "friend|close": true,
            "friend|relative": false
          }
        ]
      }
    ]
  }
}

2.4 在Facet上过滤

Dgraph支持基于facet过滤边,过滤方式类似于没有facet但是有与facet同名的函数

找到Alice已经close的friend:

{
  data(func: eq(name, "Alice")) {
    friend @facets(eq(close, true)) {
      name
    }
  }
}

如果要在filter的同时返回facet,再加上 @facets(<facetname>)即可:

{
  data(func: eq(name, "Alice")) {
    friend @facets(eq(close, true)) @facets(relative) { # filter close friends and give relative status
      name
    }
  }
}

Facet查询也可以使用AND, OR 以及 NOT组合起来:

{
  data(func: eq(name, "Alice")) {
    friend @facets(eq(close, true) AND eq(relative, true)) @facets(relative) { # filter close friends in my relation
      name
    }
  }
}

2.5 使用facet排序

可以使用uid边上的facet排序。下面我们把Alice、Bob以及Charlie各自对电影的评分对电影进行排序:

{
  me(func: anyofterms(name, "Alice Bob Charlie")) {
    name
    rated @facets(orderdesc: rating) {
      name
    }
  }
}

2.6 将facet的值赋给变量

UID边上的facet可以以边到facet值的映射的格式保存到值变量里

{
  var(func: eq(name, "Alice")) {
    friend @facets(a as close, b as relative)
  }

  friend(func: uid(a)) {
    name
    val(a)
  }

  relative(func: uid(b)) {
    name
    val(b)
  }
}

2.7 Facet与值传播

Facet的int、float类型的值可以被赋给变量,这就是值传播(values propagate

Alice、Bob以及Charlie每个人都对每个电影评了分,一个facetrating上的值变量保存了从电影到评分的映射。查询可以从多条路径到达一个电影,并将每条路径上的评分加起来。下面的查询就把Alice、Bob、Charlie对三个电影的评分加起来了:

{
  var(func: anyofterms(name, "Alice Bob Charlie")) {
    num_raters as math(1)
    rated @facets(ra as rating) {     #这里ra直接就是三人对每部电影的评分总和map
         #total_rating as math(ra)    total_rating跟ra时等价的
        avg_rating as math(ra/num_raters)S
    }
  }    

  data(func: uid(ra)) {
    name
    total_rating : val(ra)
    avg_rating : val(avg_rating)
  }
}

2.8 Facet与聚合

赋给值变量的Facet是可以被聚合的

{
  data(func: eq(name, "Alice")) {
    name
    rated @facets(r as rating) {
      name
    }
    avg(val(r))
  }
}

注意,因为r是每部电影到其总评分的映射,所以下面的想要分别计算Alice与Bob各自对所有电影的平均评分的查询语句是错误的:

{
  data(func: anyofterms(name, "Alice Bob")) {
    name
    rated @facets(r as rating) {
      name
    }
    avg(val(r))
  }
}

计算每个用户对电影的平均评分需要一个映射用户到他们各自的评分的变量:

{
  var(func: has(~rated)) {
    num_rated as math(1)
    ~rated @facets(r as rating) {#关键是这里,反向边可以获得每个人对所有电影的总评分
      avg_rating as math(r / num_rated)
    }
  }

  data(func: uid(avg_rating)) {
    name
    val(avg_rating)
  }
}

3. K-最短路径查询

4. 递归查询

递归查询让你遍历一系列谓语(通过filter、facet等),直到到达所有叶子节点,或者到达depth参数写的最大深度

为了获得某个有30000部电影的题材下的十部电影,并获取这些电影中的两个演员,我们可以做如下查询:

{
    me(func: gt(count(~genre), 30000), first: 1) @recurse(depth: 1, loop: true) {
        uid
        name@en
        ~genre (first:3) @filter(gt(count(starring), 2)) #十个太多,三个
        starring (first: 2)
        performance.actor
    }
}
#这个查询的root是个genre,但是下面的starring、performance.actor显然不是genre的谓语,这就是递归的意思

使用递归查询时注意:

上面的递归查询在depth不同的时候,返回结果时不同的

  1. depth=1,查询到genre
{
  "data": {
    "me": [
      {
        "uid": "0x1de841",
        "name@en": "Drama"
      }
    ]
  }
}
  1. depth=2,genre->movie
{
  "data": {
    "me": [
      {
        "uid": "0x1de841",
        "name@en": "Drama",
        "~genre": [
          {
            "uid": "0x17",
            "name@en": "House of Boys"
          },
          {
            "uid": "0x1e",
            "name@en": "U raskoraku"
          },
          {
            "uid": "0x38",
            "name@en": "I Want You"
          }
        ]
      }
    ]
  }
}
  1. depth=3,genre->movie->starring
{
  "data": {
    "me": [
      {
        "uid": "0x1de841",
        "name@en": "Drama",
        "~genre": [
          {
            "uid": "0x17",
            "name@en": "House of Boys",
            "starring": [
              {
                "uid": "0x1622f"
              },
              {
                "uid": "0x38fa9"
              }
            ]
          },
          {
            "uid": "0x1e",
            "name@en": "U raskoraku",
            "starring": [
              {
                "uid": "0x2a1d57"
              },
              {
                "uid": "0x2f7e3a"
              }
            ]
          },
          {
            "uid": "0x38",
            "name@en": "I Want You",
            "starring": [
              {
                "uid": "0xa6775"
              },
              {
                "uid": "0xad95f"
              }
            ]
          }
        ]
      }
    ]
  }
}
  1. depth=4,genre->movie->starring->performance.actor
{
  "data": {
    "me": [
      {
        "uid": "0x1de841",
        "name@en": "Drama",
        "~genre": [
          {
            "uid": "0x17",
            "name@en": "House of Boys",
            "starring": [
              {
                "uid": "0x1622f",
                "performance.actor": [
                  {
                    "uid": "0x5352a1",
                    "name@en": "Marco Wirges"
                  }
                ]
              },
              {
                "uid": "0x38fa9",
                "performance.actor": [
                  {
                    "uid": "0x2c7490",
                    "name@en": "Mohamed Moulouaa"
                  }
                ]
              }
            ]
          },
          {
            "uid": "0x1e",
            "name@en": "U raskoraku",
            "starring": [
              {
                "uid": "0x2a1d57",
                "performance.actor": [
                  {
                    "uid": "0x1d9bd8",
                    "name@en": "Danilo Stojković"
                  }
                ]
              },
              {
                "uid": "0x2f7e3a",
                "performance.actor": [
                  {
                    "uid": "0x836ab7",
                    "name@en": "Jovan-Burdus Janicijevic"
                  }
                ]
              }
            ]
          },
          {
            "uid": "0x38",
            "name@en": "I Want You",
            "starring": [
              {
                "uid": "0xa6775",
                "performance.actor": [
                  {
                    "uid": "0x97dd22",
                    "name@en": "Antonio Velázquez"
                  }
                ]
              },
              {
                "uid": "0xad95f",
                "performance.actor": [
                  {
                    "uid": "0x29824",
                    "name@en": "Cristina Plazas"
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}
  1. depth=5,genre->movie->starring->performance.actor,查询结果跟depth=4一样

5. Fragments

fragment关键词允许你定义新的可以被查询引用的fragment,像GraphQL specification一样。如果有多个部分需要查询相同的字段,可以定义一个fragment,并多次调用它。Fragment可以被嵌套,但是不可以组成环。示例如下:

curl localhost:8080/query -XPOST -d $'
query {
  debug(func: uid(1)) {
    name@en
    ...TestFrag
  }
}
fragment TestFrag {
  initial_release_date
  ...TestFragB
}
fragment TestFragB {
  country
}' | python -m json.tool | less

6. GraphQL变量

7. 用自定义Tokenizers分词

8. 函数

9. 连接Filter

10. 别名

11. 分页

12. Count

13. 排序

14. 多查询块

15. 查询变量

16. 值变量

17. 聚合

18. 值变量上的Math

19. GroupBy

20. Expand Predicates

21. Cascade命令

22. Normalize命令

23. Debug

24. Schema

对每个谓语来说,schema指定它的目标的类型。如果一个谓语p的类型为T,那么对于所有的主-谓-宾三元组,宾语的类型都是T

如果在执行插入一个triple的mutation时没有在schema中添加谓语类型,那么会根据第一个mutation推断类型,这些类型包括:

24.1 Schema Type

Dgraph支持标量类型,以及uid类型

24.1.1 标量类型

对于所有的谓语是标量类型的三元组,宾语是字面量

Dgraph Type Go type
default string
int int64
float float
string string
bool bool
dateTime time.Time (RFC3339 format [Optional timezone] eg: 2006-01-02T15:04:05.999999999+10:00 or 2006-01-02T15:04:05.999999999)
geo go-geom
password string (encrypted)

24.1.2 UID类型

uid类型表示一个node到node的边,在Dgraph内部,每个node都用一个uint64类型的id表示

Dgraph Type Go type
uid uint64

24.2 添加或修改Schema

Schema mutation可以添加或者修改schema

如果某个谓语you多个标量值也可以通过指定一个类型list,使用一个S P添加。下面这个例子中的occupations可以为每个S P保存一个字符串list

可以使用@index指定索引类型,并且可以通过参数指定tokenizer。当给一个谓语指定index之后,必须给这个index指定类型。例如:

name: string @index(exact, fulltext) @count .
age: int @index(int) .
friend: uid @count .
dob: dateTime .
location: geo @index(geo) .
occupations: [string] @index(term) .    #occupations的值是一个string数组

如果某个谓语没存数据,一个schema mutation会建立一个空的schema准备接收三元组。

如果在mutation之前已经有数据了,已有的数据不会被核对来遵从新的schema。但是在查询时,Dgraph会试图将已有的数据转化为新的schema中的类型,并且会忽略任何转换错误

忽略错误好像会导致查询时出现某些很异常的问题,比如某些谓语会丢失

如果已经有数据,但是制定了新的index类型,那么任何原有的但是不在更新后的index类型列表中的inde都会被丢弃,新的index类型会自动被创建

如果在schema mutation的时候指定了反向边,它也会被计算出来

24.3 RDF类型

在mutation的时候,Dgraph支持多种RDF类型

除了在执行第一个mutation的时候隐式推断类型,RDF类型还可以覆盖保存的schema

如果一个谓语在schema中一个类型,而一个mutation中的RDF含有不同Dgraph底层数据类型,转换到schema中的type时抛出了不兼容的异常,但是值被存储为RDF中的类型相应的Dgraph类型。查询结果通常会以schema中的类型返回

例如,如果age这个谓语没有在schema中设置类型,执行下面的mutation:

{
 set {
  _:a <age> "15"^^<xs:int> .
  _:b <age> "13" .
  _:c <age> "14"^^<xs:string> .
  _:d <age> "14.5"^^<xs:string> .
  _:e <age> "14.5" .
 }
}

然后查询:

{
    fgggg(func: has(age)){
    expand(_all_)
  }
}

报错:

: strconv.ParseInt: parsing "14.5": invalid syntax

Dgraph:

24.4 扩展类型

24.4.1 Password类型

可以在schema中使用password类型给一个实体设置密码。不能直接查询密码,只能使用checkpwd函数来判断一个密码是否匹配

首先,定义schema:

//alter
pass: password .

然后设置密码:

#mutate
{
  set {
    <0x123> <name> "Password Example"
    <0x123> <pass> "ThePassword" .
  }
}

检查密码:

#query
{
  check(func: uid(0x123)) {
    name
    checkpwd(pass, "ThePassword")
  }
}

输出:

{
  "check": [
    {
      "name": "Password Example",
      "pass": [
        {
          "checkpwd": true
        }
      ]
    }
  ]
}

24.5 索引

当使用函数进行过滤的时候,Dgraph会使用索引让大数据集的索引更高效

所有的标量类型都可以被索引

int, float, bool 以及 geo 都只有一个默认索引类型,tokenizers的名字依次为 int, float, boolgeo

而string与dateTime类型有多个索引类型

24.5.1 string索引

string类型有如下索引类型:

Dgraph function Required index / tokenizer Notes
eq hash, exact, term, or fulltext 对于 eq 函数来说性能最好的索引类型是 hash. 只有相似需要eq的同时还需要全文检索的时候,再考虑使用 termfulltext 索引。如果已经在用term了,那就无需再用hashexact
le, ge, lt, gt exact 允许快速排序
allofterms, anyofterms term 允许根据语句中的一个项进行查询
alloftext, anyoftext fulltext 通过指定的词干以及停止词匹配语言
regexp trigram 正则表达式匹配,也可以用于相等验证

警告

不正确的index选择可能会极大地增加性能负载,并且提高事务冲突的概率。尽量只使用最少的、最简单的索引类型

24.5.2 DateTime索引

下列索引类型适用于dateTime类型:

Index name / Tokenizer Part of date indexed
year 对年建索引(默认)
month 对年、月建索引
day 对年、月、日建索引
hour 对年、月、日、小时建索引

24.5.3 可排序索引

不是所有的索引都会给所有的值建立一个排序。可排序的索引允许执行不等函数以及排序

例如,对于string类型的name边,为了对name进行排序以对它执行不等过滤,必须指定exact索引类型。这种情况下schema查询将返回至少返回下面的内容:

{
  "predicate": "name",
  "type": "string",
  "index": true,
  "tokenizer": [
    "exact"
  ]
}

24.5.4 Count索引

对于带有@count的谓语,Dgraph会对每个节点的出边数建立索引。这可以使下面这种查询变的更快:

{
  q(func: gt(count(pred), threshold)) {
    ...
  }
}

24.5 List类型

标量类型的谓语也可以存储值list。标量类型需要使用[]包起来,表明它是一个list类型,这些list使无序的集合

occupations: [string] .
score: [int] .

24.6 反向边

图的边是单向的。对于节点到节点的边,有时需要构建反向。只要某个主-谓-宾三元组需要一个反向边,手动添加即可。如果某个谓语都会有一个反向,只要在schema中指定@reverse,Dgraph就会自动计算出反向边

anEdge的反向边是~anEdge

对于已有的数据,Dgraph会计算所有的反向边。对于在schema修改之后新添加的数据,Dgraph会为每个新加的三元组计算并添加反向边

24.7 查询schema

查询所有的schema:

schema { }

查询特定的字段:

schema {
  type
  index
  reverse
  tokenizer
}

查询特定谓语:

schema {
  type
  index
  reverse
  tokenizer
}

25. Mutation

添加或移除数据被称作mutation

一个添加三元组的mutation使用set关键词添加数据:

{
  set {
    # triples in here
  }
}

25.1 Triple

输入的语言是遵循W3C格式的 RDF N-Quad format三元组

triple的格式如下:

<subject> <predicate> <object> 

意味着以subject为标志的图节点通过有向边predicate连接到object。每个triple以一个句号(full stop)结尾。triple中的subject一定是图中的一个节点,而object可以是一个node也可以是一个value

例如,下面的triple:

<0x01> <name> "Alice" .

表示uid为0x01的节点有一个string类型的name,值为“Alice”。而下面的triple:

<0x01> <friend> <0x02> .

表示uid为0x01的节点通过friend边连接到0x02

Dgraph会为每个节点创建一个唯一的64位识别符——uid。一个mutation要么使用空节点或外部id节点(blank or external id nodes)让Dgraph为subject或者object创建uid,或者指定一个之前的mutation创建的uid

25.2 空节点与uid

mutation中的空节点写作_:identifier,标志mutation内部的节点。Dgraph会为每个空节点创建一个uid,并将它作为mutation的结果返回。例如,下面的mutation:

{
 set {
    _:class <student> _:x .
    _:class <student> _:y .
    _:class <name> "awesome class" .
    _:x <name> "Alice" .
    _:x <planet> "Mars" .
    _:x <friend> _:y .
    _:y <name> "Bob" .
 }
}

返回的结果:

{
  "data": {
    "code": "Success",
    "message": "Done",
    "uids": {
      "class": "0x2712",
      "x": "0x2713",
      "y": "0x2714"
    }
  }
}

图被更新后,就仿佛储存如下的triple:

<0x6bc818dc89e78754> <student> <0xc3bcc578868b719d> .
<0x6bc818dc89e78754> <student> <0xb294fb8464357b0a> .
<0x6bc818dc89e78754> <name> "awesome class" .
<0xc3bcc578868b719d> <name> "Alice" .
<0xc3bcc578868b719d> <planet> "Mars" .
<0xc3bcc578868b719d> <friend> <0xb294fb8464357b0a> .
<0xb294fb8464357b0a> <name> "Bob" .

空节点标签_:class_:x以及_:在mutation执行之后不能再涌来识别节点,也不会存储在dgraph中,下一个mutation一样可以复用它们

后续的mutation可以更新已有的uid的数据。例如,下面的mutation向class中添加了一个新学生:

{
 set {
    <0x6bc818dc89e78754> <student> _:x .
    _:x <name> "Chris" .
 }
}

25.3 外部id

Dgraph的输入语言是RDF,它还支持<a_fixed_identifier> <predicate> literal/node格式的triple,这里的标签a_fixed_identifier会被当作这个node的唯一识别符。例如,混合schema.org识别符、the movie database识别符以及空节点:

_:userA <http://schema.org/type> <http://schema.org/Person> .
_:userA <http://schema.org/name> "FirstName LastName" .
<https://www.themoviedb.org/person/32-robin-wright> <http://schema.org/type> <http://schema.org/Person> .
<https://www.themoviedb.org/person/32-robin-wright> <http://schema.org/name> "Robin Wright" .

0.8版本的Dgraph没有原生支持这样的外部id作为节点的识别符,外部id可以以xid边的形式作为node的属性存储下来。例如,上面的谓语在Dgraph中是有效的,但是节点http://schema.org/Person在Dgraph中是以一个uid来识别的,比方说0x123,它会有如下的一个边:

<0x123> <xid> "http://schema.org/Person" .

而Robin Wright可能有uid0x321,以及triple:

<0x321> <xid> "https://www.themoviedb.org/person/32-robin-wright" .
<0x321> <http://schema.org/type> <0x123> .
<0x321> <http://schema.org/name> "Robin Wright" .

一个合适的schema可能是:

xid: string @index(exact) .
<http://schema.org/type>: uid @reverse .

查询举例:

{
  var(func: eq(xid, "http://schema.org/Person")) {
    allPeople as <~http://schema.org/type>
  }

  q(func: uid(allPeople)) {
    <http://schema.org/name>
  }
}

查询举例,通过外部id查找Eobin Wright:

{
  robin(func: eq(xid, "https://www.themoviedb.org/person/32-robin-wright")) {
    expand(_all_) { expand(_all_) }
  }
}

注意 xid边不会在mutation的时候自动添加。用户需要自己判断某个xid是否存在,并添加节点及xid

25.4 语言与RDF类型

RDF N-Quad允许给一个字符串值指定语言类型以及一个RDF类型,语言通过@lang指定,例如:

<0x01> <name> "Adelaide"@en .
<0x01> <name> "Аделаида"@ru .
<0x01> <name> "Adélaïde"@fr .

RDF类型通过标准的^^分隔符附在字面量上,像这样:

<0x01> <age> "32"^^<xs:int> .
<0x01> <birthdate> "1985-06-08"^^<xs:dateTime> .

支持的RDF datatypes以及相关的内部类型以及相关的内部类型如下:

Storage Type Dgraph type
<xs:string> string
<xs:dateTime> dateTime
<xs:date> datetime
<xs:int> int
<xs:boolean> bool
<xs:double> float
<xs:float> float
geo:geojson geo
http://www.w3.org/2001/XMLSchema#string string
http://www.w3.org/2001/XMLSchema#dateTime dateTime
http://www.w3.org/2001/XMLSchema#date dateTime
http://www.w3.org/2001/XMLSchema#int int
http://www.w3.org/2001/XMLSchema#boolean bool
http://www.w3.org/2001/XMLSchema#double float
http://www.w3.org/2001/XMLSchema#float float

参阅章节RDF schema types来理解RDF类型如何影响mutation与storage

25.5 批量mutation

每个mutation都可能包含多个RDF三元组,对于大的数据上传操作,这些mutation可以批量、并发执行。工具dgraph-live-loader就是用于干这个的,默认是每批1000行RDF,同时并发100个

Dgraphloader以一个gzip压缩格式的N-Quad文件(不含{ set {的三元组列表),具体查看Bulk Data Loading

25.6 删除

删除操作,是用delete关键字标志的,它可以从存储中移除三元组

例如,如果存储中含有:

<0xf11168064b01135b> <name> "Lewis Carrol"
<0xf11168064b01135b> <died> "1998"

那么删除的mutation:

{
  delete {
     <0xf11168064b01135b> <died> "1998" .
  }
}

删除不需要的数据,并将它从索引中移除(如果有索引的话)

对于删除语句S P *,会将节点N所有谓语P的数据(以及相关索引)都移除

{
  delete {
     <0xf11168064b01135b> <author.of> * .
  }
}

对于语句S * *,会删除节点S所有的出边(但是,节点自己可能会作为某些边的终点留存下来),另外被删除的边相关的任意反向边,还有被删除的数据的所有索引也都会被删除

{
  delete {
     <0xf11168064b01135b> * * .
  }
}

注意,* P O* * O 是不被支持的,因为找到所有的入边太难了

上一篇下一篇

猜你喜欢

热点阅读