dgraph 簡介
dgraph 是基於 golang 開發的開源的分布式圖數據庫. 誕生時間不長, 發展卻很迅速. 目前是 v20.x 版本, dgraph 集群主要包含 3 種節點:
- Zero: 是集群的核心, 負責調度集群服務器和平衡服務器組之間的數據
- Alpha: 保存數據的 謂詞 和 索引. 謂詞包括數據的 屬性 和數據之間的 關系; 索引是為了更快的進行數據的過濾和查找
- Ratel: dgraph 的 UI 接口, 可以在此界面上進行數據的 CURD, 也可以修改數據的 schema
通過增加 Alpha 的數量完成 dgraph 的水平擴展.
dgraph 是 golang 開發的, 所以部署非常簡單, 更簡單的方式是使用 docker
docker pull dgraph/dgraph:latest
然后配置一個 docker-comopse.yml, 一鍵啟動 dgraph 服務:
version: "3.2"
services:
zero:
image: dgraph/dgraph:latest
volumes:
- type: volume
source: dgraph
target: /dgraph
volume:
nocopy: true
ports:
- 5080:5080
- 6080:6080
restart: on-failure
command: dgraph zero --my=zero:5080
alpha:
image: dgraph/dgraph:latest
volumes:
- type: volume
source: dgraph
target: /dgraph
volume:
nocopy: true
ports:
- 7080:7080
- 8080:8080
- 9080:9080
restart: on-failure
command: dgraph alpha --my=alpha:7080 --lru_mb=2048 --zero=zero:5080
ratel:
image: dgraph/dgraph:latest
volumes:
- type: volume
source: dgraph
target: /dgraph
volume:
nocopy: true
ports:
- 8000:8000
command: dgraph-ratel
volumes:
dgraph:
啟動 dgraph, 在上面 docker-compose.yml 相同的文件夾下執行:
docker-compose up -d
如果沒有錯誤, 可以通過: http://<YOUR IP/Domain>:8000/ 來訪問 draph 的 UI 界面.
dgraph 使用示例(基於 golang)
通過 dgraph 的 UI 界面, 可以完成所有的操作, 但要想將 dgraph 和應用結合, 還得使用 dgraph 的 SDK.
dgraph 的 SDK 支持各種語言, 官方支持的主要有: Go, C#, Java, Javascript, Python.
dgraph 本身就是基於 golang 開發的, 所以對 Go 的支持肯定最全面, 下面就使用 golang 的 client 來演示 dgraph 的操作.
golang client 安裝
安裝最新版的 client:
go get github.com/dgraph-io/dgo/v200
創建 schema
代碼:
1 func NewDgraphClient() *dgo.Dgraph {
2 conn, err := grpc.Dial("localhost:9080", grpc.WithInsecure())
3 if err != nil {
4 log.Fatal(err)
5 }
6
7 client := dgo.NewDgraphClient(api.NewDgraphClient(conn))
8
9 return client
10 }
11
12 func CreateSchema(client *dgo.Dgraph) error {
13 schema := `
14 name: string @index(term) .
15 age: int .
16
17 type Person {
18 name
19 age
20 }
21 `
22 op := &api.Operation{Schema: schema}
23
24 err := client.Alter(context.Background(), op)
25 return err
26 }
執行成功后, 在 UI 界面(http://localhost:8000)上驗證是否創建成功:
schema(pred:[name, age]) {
perdicate
type
index
}
結果如下:
{
"data": {
"schema": [
{
"predicate": "age",
"type": "int"
},
{
"predicate": "name",
"type": "string",
"index": true
}
]
},
... 省略 ...
}
數據的 CURD
首先, 新增數據
1 type Person struct {
2 Uid string `json:"uid"`
3 Name string `json:"name"`
4 Age int `json:"age"`
5 Friends []Person `json:"friends"`
6 }
7
8 func AddSomeData(client *dgo.Dgraph) error {
9 p1 := &Person{
10 Name: "Dog",
11 Age: 10,
12 }
13 p1.Friends = make([]Person, 0)
14
15 p2 := &Person{
16 Name: "Monkey",
17 Age: 20,
18 }
19 p3 := &Person{
20 Name: "Cat",
21 Age: 30,
22 }
23
24 p1.Friends = append(p1.Friends, *p2)
25 p1.Friends = append(p1.Friends, *p3)
26
27 mu := &api.Mutation{CommitNow: true}
28 pb, err := json.Marshal(p1)
29 if err != nil {
30 return err
31 }
32
33 mu.SetJson = pb
34 _, err = client.NewTxn().Mutate(context.Background(), mu)
35 return err
36 }
查詢數據:
1 func QueryData(client *dgo.Dgraph) error {
2 q := `
3 query q($name: string){
4 q(func:allofterms(name, $name)){
5 name
6 age
7 uid
8 friends{
9 name
10 age
11 uid
12 }
13 }
14 }
15 `
16 txn := client.NewTxn()
17 res, err := txn.QueryWithVars(context.Background(), q, map[string]string{"$name": "Dog"})
18 if err != nil {
19 return err
20 }
21 fmt.Println(res.String())
22 return nil
23 }
為了簡化, 返回值中我直接打印了 string 格式, 其實返回的是個 json 結構.
可以看出, 返回值中包含了上一步創建的 3 個 Person, 其中 2 個作為 Dog 的 friends 返回的.
更新數據:
1 func UpdateData(client *dgo.Dgraph) error {
2 mu := &api.Mutation{
3 CommitNow: true,
4 SetNquads: []byte(`<0xfffd8d67d832b975> <age> "12" .`),
5 }
6
7 _, err := client.NewTxn().Mutate(context.Background(), mu)
8 return err
9 }
其中 <0xfffd8d67d832b975> 是數據的 uid, 根據上面 query 示例的返回值中可以查找到.
這里需要注意的是,
刪除數據(刪除數據的一個屬性):
1 func DeleteProp(client *dgo.Dgraph) error {
2 mu := &api.Mutation{
3 CommitNow: true,
4 DelNquads: []byte(`<0xfffd8d67d832b976> <age> * .`),
5 }
6
7 _, err := client.NewTxn().Mutate(context.Background(), mu)
8 return err
9 }
刪除了 <0xfffd8d67d832b976> 這條數據的
將數據的屬性和關系都刪除之后, 這條數據就相當於刪除了.
直接根據 Uid 刪除數據的 api 也有, 但是使用后無效(具體我提了個 issue 到 dgraph 的代碼庫)
事務
draph 是支持事務的, 上面的例子中其實已經使用了事務, 只不過每個事務中只有一個操作.
如果有多個操作, 類似下面這樣的代碼即可:
1 ctx := context.Background()
2 tnx := client.NewTxn()
3
4 _, err := tnx.Mutate(ctx, mu1)
5 if err != nil {
6 tnx.Discard(ctx)
7 }
8 _, err = tnx.Mutate(ctx, mu2)
9 if err != nil {
10 tnx.Discard(ctx)
11 }
12
13 tnx.Commit(ctx)
總結
圖數據庫不是萬能的, 它的目的也不是取代關系數據庫.
我們根據使用場景在合適的時候選用 dgraph, 可以更加的輕松的完成數據分析, 而不用深陷 sql 的坑中.