查询语言
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 "Alice" .
_:alice "040123456" (since=2006-01-02T15:04:05) .
_:alice "MA0123" (since=2006-02-02T13:01:09, first=true) .
_:bob "Bob" .
_:bob "MA0134" (since=2006-02-02T13:01:09) .
_:charlie "Charlie" .
_:dave "Dave" .
# -- Facets on UID predicates
_:alice _:bob (close=true, relative=false) .
_:alice _:charlie (close=false, relative=true) .
_:alice _:dave (close=true, relative=true) .
# -- Facets for variable propagation
_:movie1 "Movie 1" .
_:movie2 "Movie 2" .
_:movie3 "Movie 3" .
_:alice _:movie1 (rating=3) .
_:alice _:movie2 (rating=2) .
_:alice _:movie3 (rating=5) .
_:bob _:movie1 (rating=5) .
_:bob _:movie2 (rating=5) .
_:bob _:movie3 (rating=5) .
_:charlie _:movie1 (rating=2) .
_:charlie _:movie2 (rating=5) .
_:charlie _: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的since
facet应该按如下的方式查询:
{
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的别名
在查询某个谓语时,可以指定别名,格式类似于请求其他谓语的别名。orderasc
与 orderdesc
不能用作别名,因为它们有特别意义,其他的任何字符串都能用作别名
在这里,我们给分别给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(
即可:
{
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的谓语,这就是递归的意思
使用递归查询时注意:
- 在root之后只能指定一层谓语。这些会被递归查询。标量与节点都会被当作类似的
- 每个查询只建议有一个递归block
- 小心结果集可能会快速膨胀,如果结果集太大的话,会报错。在这种情况下使用更多的filter、使用分页限制条数,或者像上面一样提供一个深度参数
上面的递归查询在depth不同的时候,返回结果时不同的
- depth=1,查询到genre
{
"data": {
"me": [
{
"uid": "0x1de841",
"name@en": "Drama"
}
]
}
}
- 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"
}
]
}
]
}
}
- 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"
}
]
}
]
}
]
}
}
- 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"
}
]
}
]
}
]
}
]
}
}
- 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
- 在mutation时,会检查标量类型,并且在当这个值不能转为schema里的类型时会报错
- 在查询时,值类型会根据schema中谓语的类型返回
如果在执行插入一个triple的mutation时没有在schema中添加谓语类型,那么会根据第一个mutation推断类型,这些类型包括:
-
uid
,如果某个谓语的第一个mutation的主语跟宾语都是node - 根据rdf type派生,如果宾语是一个字面量,而且第一个mutation中有rdf type
- 其他的都是
default
类型
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 "15"^^ .
_:b "13" .
_:c "14"^^ .
_:d "14.5"^^ .
_:e "14.5" .
}
}
然后查询:
{
fgggg(func: has(age)){
expand(_all_)
}
}
报错:
: strconv.ParseInt: parsing "14.5": invalid syntax
Dgraph:
- 根据第一个三元组的隐式转换,将schema类型设置为
int
- 将保存的
13
载存储中转换成int
- 检查发现
14
可以被转换成int,但是会按string
存储 - 最后两个三元组会报错,因为
14.5
不能被转换成int
24.4 扩展类型
24.4.1 Password类型
可以在schema中使用password
类型给一个实体设置密码。不能直接查询密码,只能使用checkpwd
函数来判断一个密码是否匹配
首先,定义schema:
//alter
pass: password .
然后设置密码:
#mutate
{
set {
<0x123> "Password Example"
<0x123> "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
, bool
与geo
而string与dateTime类型有多个索引类型
24.5.1 string索引
string类型有如下索引类型:
Dgraph function | Required index / tokenizer | Notes |
---|---|---|
eq |
hash , exact , term , or fulltext |
对于 eq 函数来说性能最好的索引类型是 hash . 只有相似需要eq 的同时还需要全文检索的时候,再考虑使用 term 或 fulltext 索引。如果已经在用term 了,那就无需再用hash 或exact 了 |
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 可排序索引
不是所有的索引都会给所有的值建立一个排序。可排序的索引允许执行不等函数以及排序
-
int
与float
索引是可排序的 -
string
类型的exact
索引是可排序的 - 所有的
dateTime
索引是可排序的
例如,对于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] .
- set操作可以向list中添加一个值。值的顺序不能保证
- delete操作可以从list中删除一个值
- 对这些谓语的查询将按数组的格式返回list
- 索引可以被应用于值为list的谓语,你也可以在它们上执行函数
- 这些谓语不能进行排序
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
。每个triple以一个句号(full stop)结尾。triple中的subject一定是图中的一个节点,而object可以是一个node也可以是一个value
例如,下面的triple:
<0x01> "Alice" .
表示uid为0x01
的节点有一个string类型的name
,值为“Alice”。而下面的triple:
<0x01> <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 _:x .
_:class _:y .
_:class "awesome class" .
_:x "Alice" .
_:x "Mars" .
_:x _:y .
_:y "Bob" .
}
}
返回的结果:
{
"data": {
"code": "Success",
"message": "Done",
"uids": {
"class": "0x2712",
"x": "0x2713",
"y": "0x2714"
}
}
}
图被更新后,就仿佛储存如下的triple:
<0x6bc818dc89e78754> <0xc3bcc578868b719d> .
<0x6bc818dc89e78754> <0xb294fb8464357b0a> .
<0x6bc818dc89e78754> "awesome class" .
<0xc3bcc578868b719d> "Alice" .
<0xc3bcc578868b719d> "Mars" .
<0xc3bcc578868b719d> <0xb294fb8464357b0a> .
<0xb294fb8464357b0a> "Bob" .
空节点标签_:class
、_:x
以及_:
在mutation执行之后不能再涌来识别节点,也不会存储在dgraph中,下一个mutation一样可以复用它们
后续的mutation可以更新已有的uid的数据。例如,下面的mutation向class中添加了一个新学生:
{
set {
<0x6bc818dc89e78754> _:x .
_:x "Chris" .
}
}
25.3 外部id
Dgraph的输入语言是RDF,它还支持
格式的triple,这里的标签a_fixed_identifier
会被当作这个node的唯一识别符。例如,混合schema.org识别符、the movie database识别符以及空节点:
_:userA .
_:userA "FirstName LastName" .
.
"Robin Wright" .
0.8版本的Dgraph没有原生支持这样的外部id作为节点的识别符,外部id可以以xid
边的形式作为node的属性存储下来。例如,上面的谓语在Dgraph中是有效的,但是节点http://schema.org/Person在Dgraph中是以一个uid来识别的,比方说0x123
,它会有如下的一个边:
<0x123> "http://schema.org/Person" .
而Robin Wright可能有uid0x321
,以及triple:
<0x321> "https://www.themoviedb.org/person/32-robin-wright" .
<0x321> <0x123> .
<0x321> "Robin Wright" .
一个合适的schema可能是:
xid: string @index(exact) .
: uid @reverse .
查询举例:
{
var(func: eq(xid, "http://schema.org/Person")) {
allPeople as <~http://schema.org/type>
}
q(func: uid(allPeople)) {
}
}
查询举例,通过外部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> "Adelaide"@en .
<0x01> "Аделаида"@ru .
<0x01> "Adélaïde"@fr .
RDF类型通过标准的^^
分隔符附在字面量上,像这样:
<0x01> "32"^^ .
<0x01> "1985-06-08"^^ .
支持的RDF datatypes以及相关的内部类型以及相关的内部类型如下:
Storage Type | Dgraph type |
---|---|
string |
|
dateTime |
|
datetime |
|
int |
|
bool |
|
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> "Lewis Carrol"
<0xf11168064b01135b> "1998"
那么删除的mutation:
{
delete {
<0xf11168064b01135b> "1998" .
}
}
删除不需要的数据,并将它从索引中移除(如果有索引的话)
对于删除语句S P *
,会将节点N
所有谓语P
的数据(以及相关索引)都移除
{
delete {
<0xf11168064b01135b> * .
}
}
对于语句S * *
,会删除节点S
所有的出边(但是,节点自己可能会作为某些边的终点留存下来),另外被删除的边相关的任意反向边,还有被删除的数据的所有索引也都会被删除
{
delete {
<0xf11168064b01135b> * * .
}
}
注意,
* P O
与* * O
是不被支持的,因为找到所有的入边太难了