golang 源碼分析:cayley-3-
cayley 可以使用多種後端存儲,那麼如何使用 mysql 作爲後端存儲呢,首先我們看下如何配置:
store:
# backend to use
backend: mysql
# address or path for the database
address: "root:@tcp(localhost:3306)/cayley?loc=Local&charset=utf8mb4&collation=utf8mb4_general_ci"
# open database in read-only mode
read_only: false
# backend-specific options
options:
nosync: false
query:
timeout: 30s
load:
ignore_duplicates: false
ignore_missing: false
batch: 10000
backend 設置成 mysql,並且指定 dsn 即可,接着我們使用 mysql 作爲後端存儲導入數據:
首先創建數據庫 cayley
% mysql.server start
Starting MySQL
.. SUCCESS!
% mysql -uroot
Welcome to the MySQL monitor. Commands end with ; or \g.
mysql> create database cayley;
初始化下看看是否成功
% ../cayley/cayley init -c cayley_example.yml
I0528 23:40:40.065734 81480 command.go:915] Cayley version: v0.8.x-dev (dev snapshot)
I0528 23:40:40.066011 81480 command.go:915] using config file: cayley_example.yml
I0528 23:40:40.066107 81480 database.go:71] using backend "mysql" (root:@tcp(localhost:3306)/cayley?loc=Local&charset=utf8mb4&collation=utf8mb4_general_ci)
檢查下,發現已經創建了兩個表
mysql> use cayley;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+------------------+
| Tables_in_cayley |
+------------------+
| nodes |
| quads |
+------------------+
2 rows in set (0.00 sec)
這兩個表分別存了頂點和四元祖
mysql> show create table nodes\G
*************************** 1. row ***************************
Table: nodes
Create Table: CREATE TABLE `nodes` (
`hash` binary(20) NOT NULL,
`refs` int NOT NULL,
`value` blob,
`value_string` text,
`datatype` text,
`language` text,
`iri` tinyint(1) DEFAULT NULL,
`bnode` tinyint(1) DEFAULT NULL,
`value_int` bigint DEFAULT NULL,
`value_bool` tinyint(1) DEFAULT NULL,
`value_float` double DEFAULT NULL,
`value_time` datetime(6) DEFAULT NULL,
PRIMARY KEY (`hash`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.02 sec)
show create table quads\G
*************************** 1. row ***************************
Table: quads
Create Table: CREATE TABLE `quads` (
`horizon` bigint unsigned NOT NULL AUTO_INCREMENT,
`subject_hash` binary(20) NOT NULL,
`predicate_hash` binary(20) NOT NULL,
`object_hash` binary(20) NOT NULL,
`label_hash` binary(20) DEFAULT NULL,
`ts` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`horizon`),
UNIQUE KEY `horizon` (`horizon`),
UNIQUE KEY `spo_unique` (`subject_hash`,`predicate_hash`,`object_hash`),
UNIQUE KEY `spol_unique` (`subject_hash`,`predicate_hash`,`object_hash`,`label_hash`),
KEY `label_hash_fk` (`label_hash`),
KEY `spo_index` (`subject_hash`,`predicate_hash`,`object_hash`),
KEY `ops_index` (`object_hash`,`predicate_hash`,`subject_hash`),
KEY `pos_index` (`predicate_hash`,`object_hash`,`subject_hash`),
KEY `osp_index` (`object_hash`,`subject_hash`,`predicate_hash`),
CONSTRAINT `label_hash_fk` FOREIGN KEY (`label_hash`) REFERENCES `nodes` (`hash`),
CONSTRAINT `object_hash_fk` FOREIGN KEY (`object_hash`) REFERENCES `nodes` (`hash`),
CONSTRAINT `predicate_hash_fk` FOREIGN KEY (`predicate_hash`) REFERENCES `nodes` (`hash`),
CONSTRAINT `subject_hash_fk` FOREIGN KEY (`subject_hash`) REFERENCES `nodes` (`hash`)
) ENGINE=InnoDB AUTO_INCREMENT=314 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
導入數據
../cayley/cayley load -c cayley_example.yml -i ../cayley/data/**nq --alsologtostderr=true
I0528 23:43:00.003584 82856 command.go:915] Cayley version: v0.8.x-dev (dev snapshot)
I0528 23:43:00.006404 82856 command.go:915] using config file: cayley_example.yml
I0528 23:43:00.008158 82856 database.go:91] using backend "mysql" (root:@tcp(localhost:3306)/cayley?loc=Local&charset=utf8mb4&collation=utf8mb4_general_ci)
查看下存儲數據
mysql> select * from nodes limit 1\G
*************************** 1. row ***************************
hash: 0x278A31F9BA54E8D73ADBC4F1AE82B1D2442DE516
refs: 3
value: NULL
value_string: NULL
datatype: NULL
language: NULL
iri: NULL
bnode: NULL
value_int: NULL
value_bool: 1
value_float: NULL
value_time: NULL
1 row in set (0.00 sec)
當然也可以開啓 http 服務來訪問 cayley
../cayley/cayley http -c cayley_example.yml --host=0.0.0.0:64210
瀏覽器打開 http://127.0.0.1:64210/,可以看到
那麼如何使用 go 來操作我們的圖數據庫呢
package main
import (
"fmt"
"log"
"github.com/cayleygraph/cayley"
_ "github.com/cayleygraph/cayley/graph/sql/mysql"
"github.com/cayleygraph/quad"
)
func main() {
// Create a brand new graph
// store, err := cayley.NewGraph("sql", "root:@tcp(localhost:3306)/cayley?loc=Local&charset=utf8mb4&collation=utf8mb4_general_ci", nil)
store, err := cayley.NewGraph("mysql", "root:@tcp(localhost:3306)/cayley?loc=Local&charset=utf8mb4&collation=utf8mb4_general_ci", nil)
if err != nil {
log.Fatalln(err)
}
store.AddQuad(quad.Make("phrase of the day", "is of course", "Hello World!", "label1"))
store.AddQuad(quad.Make("Hello World!", "is of course", "Hello World1!", "label2"))
store.AddQuad(quad.Make("Hello World1!", "is course", "Hello World2!", "label2"))
// Now we create the path, to get to our data
p := cayley.StartPath(store, quad.String("phrase of the day")).Out(quad.String("is of course")).Out(quad.String("is of course")).Out(quad.String("is course"))
// Now we iterate over results. Arguments:
// 1. Optional context used for cancellation.
// 2. Flag to optimize query before execution.
// 3. Quad store, but we can omit it because we have already built path with it.
err = p.Iterate(nil).EachValue(nil, func(value quad.Value) {
nativeValue := quad.NativeOf(value) // this converts RDF values to normal Go types
fmt.Println(nativeValue)
})
if err != nil {
log.Fatalln(err)
}
}
運行下
% go run ./test/cayley/exp5/main.go
Hello World2!
總結下,圖數據庫其實是圖到持久化存儲的一種遷移實現,我們知道圖有兩種數據結構可以來表示,鄰接表和鄰接矩陣。圖數據其實是鄰接矩陣的形式存儲的,同時利用了鄰接矩陣的稀疏性,存儲了訂單和邊,對應了兩個表 node 和 quad。實現上,圖數據庫有專用存儲和借用三方存儲兩種形式。cayley 是借用第三方存儲實現的。它在上層封裝了迭代器,並且封裝了 gizmo 查詢和 graphql 等,方便我們更加直觀處理圖相關邏輯。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/SHt_64kpVSnOd0-xogL2Ww