Dgraph - an open source, low latency, high throughput, native and distributed graph database.
From Install Scripts (Linux/Mac) Install the binaries with curl https://get.dgraph.io -sSf | bash
启动 Dgraph zero 该程序控制Dgraph集群,维护成员信息、分配分片和移动分片等。默认使用5080端口与外部通讯dgraph zero
启动 Dgraph data server 数据服务,默认使用9080端口与外部通讯 dgraph alpha --lru_mb 2048 --zero localhost:5080
提示:您可以通过修改 lru_mb 参数设置 Dgraph alpha 服务的预设内存。这只是对 Dgraph alpha 服务的一个提示,实际使用率会高于此值。建议将lru_mb设置为可用内存 的三分之一。
dgraph-ratel
可以通过浏览器打开 http://localhost:8000.连接Ratel进行相关可视化操作。也可以通过命令行执行:curl localhost:8080/query -XPOST -d $'...' 或者是把引号之间的内容通过浏览器执行。
mutations 有两种标准格式: RDF (Resource Description Framework) N-Quad and JSON (JavaScript Object Notation). RDF 是一个gua is a widely used standard in Graph or Ontology systems.
正确:_:michael and _:amit.
也是但不推荐:<_:uid43> or <_:uid4e030f> <其他错误写法>
<0x4e030f> "some new data" .
Note 你应该只引用存在的 UIDs,如果你对不存在的UID执行mutation操作, Dgraph 将返回错误。 使用 blank nodes创建新节点,Dgraph为新的节点分配一个新的 UID。
在图中,对象(或实体)称为节点,关系称为边或谓词。
图表不仅仅适用于社交网络。其他的合适场景包括
相互连接的数据,比如需要连接的SQL表 高级搜索 推荐引擎 模式检测 网络,如计算机、道路和电信 流程,比如业务流程和生物流程 事件之间的因果关系或其他联系 公司或市场的结构
在关系处理方面,图形数据库比SQL数据库快得多。SQL数据库被类似图形的数据拖住了,因为遵循边意味着连接表;有时大表;边越多,连接越多,需要加载和处理的数据也越多。 在图形数据库中,边是一个基本结构,所以跟随边是一个简单的查找,这使得这个操作非常快。Dgraph是一个图形数据库。它优化了图形数据的存储和查询速度。
每个查询 都有一个名字,返回结果也以该名字标记
通过检索条件 func: ... 匹配节点. 函数 eq 找到相同的节点. 结果是匹配的节点及有节点引出向外的边。示例:
{
find_michael(func: eq(name@., "Michael")) {
uid
name@.
age
}
}
在Dgraph和GraphQL+-中,查询返回的是图形,而不是表或数据列表。
函数及筛选 Functions and filtering
Functions can only be applied to predicates that have been indexed - that’s part of the lesson about schema. The logical connectives AND, OR and NOT combine multiple functions in a filter.
friend (orderasc: age) {...}
friend (orderasc: name@., offset: 1, first: 2) {...}
{
name
age
count(friend)
}
The root func: 只接受一个函数 and doesn’t accept AND, OR and NOT connectives as in filters. So the syntax (func: ...) @filter(... AND ...) is required when filtering on multiple properties at the root.
{
lots_of_friends(func: ge(count(friend), 2)) @filter(ge(age, 20) AND lt(age, 30)) {
name@.
age
friend { name@. }
}
}
The function has(edge_name) returns nodes that have an outgoing edge of the given name.
The output graph can set names for edges in the output with aliasing. 如下例,number_of_friends 是别名。
number_of_friends : count(friend)
The @cascade 表示除去不完全包含匹配边的节点。
The @normalize 表示仅返回设置了别名的边对应的节点,同时去除嵌套。
Queries 可以支持包含注释,以 # 开头的行是注释。
Dgraph支持facet(边上的键值对)作为RDF三元组的扩展。也就是说,facet向边添加属性,而不是向节点添加属性。例如,两个节点之间的朋友边缘可能具有表示亲密的友谊的布尔属性。Facets 也可以用作边的权重。
Dgraph存储了一个描述 predicates(谓词、边)类型的 schema (模式)。
当我们想要向现有模式添加新数据时,我们可以直接添加它。但是如果我们想在新模式中添加新数据,我们有两个选择:1、添加数据并让Dgraph计算出模式,2、或者指定模式,然后添加数据。但是函数和过滤只能应用于索引谓词,为此我们需要指定模式。
添加修改数据 mutating data
外部标识符
Dgraph 不支持为节点设置外部 id。如果应用程序需要 Dgraph 分配的 uid 以外的节点的惟一标识符,那么这些标识符必须作为边提供。由用户应用程序来确保此类 id/key 的唯一性。
_:myID "something"@en .
_:myID "某物"@zh-Hans .
See the JSON:
{
"set": [
{
"uid": "_:myID",
"an_edge@en": "something",
"an_edge@zh-Hans": "某物"
}
]
}
边是定向的,查询时不能反向遍历边。在数据建模方面,一些反向边缘总是有意义的,比如friend。其他的,例如boss_of,有时是双向的,但并不总是双向的。
在两个方向查询有两个方式:1、将反向边添加到模式中,并添加所有反向边数据。2、告诉 Dgraph 始终使用模式中的 @reverse 关键字存储反向边缘。
运行模式突变,Dgraph将计算所有反向边缘。an_edge的反边缘是~an_edge。
尝试使用以前突变中的空白节点是行不通的。空白节点不会持久存储在存储中,因此当引用在以前的突变中创建的节点时:
不可以通过如下方式:
_:sarah _:company1 .
而是
.
使用Dgraph实例的uid编写一个连接公司和友谊数据的突变。整个过程通常是通过编程完成的——查询数据以获得uid,制定突变,然后批处理更新。
三种方式
删除关系及子节点
{
"delete": [
{
"uid": "0x2", # Answer UID.
"comment": {
"uid": "0x3" # Delete relation (edge) with the Comment
}
},
{
"uid": "0x3" # Delete the actual comment
}
]
}
对于图_predicate_中的任何节点,查询所有输出边的名称。
注意,这与设计图表时的模式或意图不同,因为任何给定节点可能具有或不具有其他节点具有的所有谓词。通常,大型图通常表示建模数据的部分视图。我们分析数据的工作是理解数据中的关系,同时处理缺陷或不完整的知识。
expand(...predicates...)
In Ggraph github repository you’ll find a dataset about movies, directors and actors.This dataset is a one million triple subset of a larger dataset of movies that contains around 230000 actors and around 86000 movies.
dgraph 可以通过as关键词将一个查询块的任意部分设为一个变量, 以供后面的子查询或者其它查询块使用. 这个变量本质上是一个uid列表, 因此要利用uid函数进行引用。
{
PJ as var(func:allofterms(name@en, "Peter Jackson")) @normalize @cascade {
F as director.film
}
peterJ(func: uid(PJ)) @normalize @cascade {
name : name@en
actor.film {
performance.film @filter(uid(F)) {
film_name: name@en
}
performance.character {
character: name@en
}
}
}
}
{
var(func: allofterms(name@en, "Taraji Henson")) {
actor.film {
F as performance.film {
G as genre
}
}
}
Taraji_films_by_genre(func: uid(G)) {
genre_name : name@en
films : ~genre @filter(uid(F)) {
film_name : name@en
}
}
}
联合
{
var(func: allofterms(name@en, "Peter Jackson")) {
F_PJ as director.film {
starring{
A_PJ as performance.actor
}
}
}
var(func: allofterms(name@en, "Martin Scorsese")) {
F_MS as director.film {
starring{
A_MS as performance.actor
}
}
}
actors(func: uid(A_PJ)) @filter(uid(A_MS)) @cascade {
actor: name@en
actor.film {
performance.film @filter (uid(F_PJ, F_MS)) {
name@en
}
}
}
}
Value variables - min and max
{
q(func: allofterms(name@en, "Ang Lee")) {
director.film {
uid
name@en
# Count the number of starring edges for each film
num_actors as count(starring)
# In this block, num_actors is the value calculated for this film.
# The film with uid and name
}
# Here num_actors is a map of film uid to value for all
# of Ang Lee's films
#
# It can't be used directly, but aggregations like min and max
# work over all the values in the map
most_actors : max(val(num_actors))
}
# to use num_actors in another query, make sure it's done in a context
# where the film uid to value map makes sense.
}
Value variables - sum and avg
{
ID as var(func: allofterms(name@en, "Steven Spielberg")) {
director.film {
num_actors as count(starring)
}
average as avg(val(num_actors))
}
avs(func: uid(ID)) @normalize {
name : name@en
average_actors : val(average)
num_films : count(director.film)
}
}
Value variables: filtering and ordering
{
ID as var(func: allofterms(name@en, "Steven")) {
director.film {
num_actors as count(starring)
}
average as avg(val(num_actors))
}
avs(func: uid(ID), orderdesc: val(average)) @filter(ge(val(average), 40)) @normalize {
name : name@en
average_actors : val(average)
num_films : count(director.film)
}
}
Value variables: math functions
{
var(func:allofterms(name@en, "Jean-Pierre Jeunet")) {
name@en
films as director.film {
stars as count(starring)
directors as count(~director.film)
ratio as math(stars / directors)
}
}
best_ratio(func: uid(films), orderdesc: val(ratio)){
name@en
stars_per_director : val(ratio)
num_stars : val(stars)
}
}
{ # Get all directors
var(func: has(director.film)) @cascade {
director.film {
date as initial_release_date
}
# Store maxDate as a variable
maxDate as max(val(date))
daysSince as math(since(maxDate)/(24*60*60))
}
# Order by maxDate
me(func: uid(maxDate), orderdesc: val(maxDate), first: 10) {
name@en
days : val(daysSince)
# For each director, sort by release date and get latest movie.
director.film(orderdesc: initial_release_date, first: 1) {
name@en
initial_release_date
}
}
GroupBy
{
var(func:allofterms(name@en, "Steven Spielberg")) {
director.film @groupby(genre) {
a as count(uid)
}
}
byGenre(func: uid(a), orderdesc: val(a)) {
name@en
num_movies : val(a)
}
}
expand and _predicate_
{
var(func:allofterms(name@en, "Cherie Nowlan")) {
pred as _predicate_
}
q(func:allofterms(name@en, "Cherie")) {
expand(val(pred)) { expand(_all_) }
}
}
当Dgraph基于过滤器搜索字符串、日期或其他值时,它需要一个索引来提高搜索效率。
int、float、geo和date都有默认索引,但是string有选择索引类型的选项。可以为同一个字符串值谓词构建多个索引。
对于字符串,可以使用以下索引:
Regular Expressions
{
aliens(func: regexp(name@en, /.*alien.*/i)) @cascade {
name@en
~genre {
name@en
starring {
performance.actor @filter(regexp(name@en,
/(.*ali.*e.*n.*)|(.*a.*lie.*n.*)|(.*a.*l.*ien.*)/i)) {
name@en
}
}
}
}
}
全文搜索是谷歌为web页面所做的。它与术语匹配不同,因为它试图尊重语言、语法和时态。例如,将搜索词run与包含run、running和run的文档匹配。 它不完全匹配术语,而是使用:
词干检查:查找一个常见的基本单词,以便在时态、复数/单数或其他屈折变化方面的差异仍然匹配
停止单词:删除and、or、it和可能经常出现而无法搜索的单词。
假设集群机器数为3台,下载和安装:此步骤与单机部署的下载安装相同, 在3台机器上均执行上述指令.
启动服务
//选择某一台机器上启动zero服务, 用my参数指定自身的host, 以便和集群的alpha服务通讯, 用replicas指定副本数
dgraph zero --my dev210.sugo.net:5080 --replicas 3
//在三台机器上启动alpha服务, 用my参数指定自身的host
dgraph alpha --lru_mb 2048 --my dev210.sugo.net:7080 --zero dev210.sugo.net:5080 //210机器执行
dgraph alpha --lru_mb 2048 --my dev211.sugo.net:7080 --zero dev210.sugo.net:5080 //211机器执行
dgraph alpha --lru_mb 2048 --my dev212.sugo.net:7080 --zero dev210.sugo.net:5080 //212机器执行
//选择某一台机器启动ratel服务
dgraph-ratel
注意:集群模式下, 若zero设置了replicas参数, 则集群必须有半数以上的alpha节点存活才可对外提供服务. 在本例下, 即需要2个及以上数量的alpha节点存活才能提供服务.