iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 28
0
AI & Data

看圖說故事,讓 Neo4j 重新詮釋你的資料庫系列 第 28

使用 Golang Driver 開發 Neo4j 應用程式

#前面已經分享過以 HTTP API 或 JavaScript driver 開發 Neo4j 前端應用,今天我們就來看後端應用囉,這篇文章會以 Golang 語言為參考。
目前(2020/10) Neo4j 官方支援的程式語言有 Java、 .NET、JavaScript、Python、Go,針對 Java 還有額外支援框架 Spring、Neo4j-OGM。
其他語言如 Ruby、PHP、Erlang/Elixir、Perl、C/C++、Clojure、Haskell、R 則都是 Neo4j 社區中的開發者們所貢獻,但也都有收錄在官方教學

安裝 Golang driver for Neo4j

使用 go get 或 GO Module 管理 package,建議後者。

go get github.com/neo4j/neo4j-go-driver/neo4j
go mod init github.com/eggttball/go-neo4j
go mod edit -require github.com/neo4j/neo4j-go-driver@v1.8.3

Import neo4j driver

import "github.com/neo4j/neo4j-go-driver/neo4j"

宣告 Neo4j driver 物件

連線 Neo4j 資料庫服務的第一個步驟,便是宣告 driver 物件,一個應用程式只需要初始化這樣一個物件即可,勿初始化多個 driver,並在程式結束後手動關閉,一個 driver 會維護一個 Connection Pool 來自動管理資料庫的連線與釋放。
以下的範例程式碼在初始化 Session 後立即關閉 driver,只是示範關閉 driver,實務應用上,勿頻繁地關閉 driver 並重新初始化 driver。

session 物件則是管理一連串交易的容器,如果你寫多執行緒的應用,不需要擔心 driver 物件的狀態不同步;但是 session 物件就必須注意其狀態,不可以執行緒共用,並應在完成交易後立即關閉。

create driver and session

driver, err := neo4j.NewDriver("bolt://localhost:7687", neo4j.BasicAuth("neo4j", password, ""), func(c *neo4j.Config) {
    c.Encrypted = encrypted
})
if err != nil {
    return "", err
}
defer driver.Close()

session, err := driver.Session(neo4j.AccessModeWrite)
if err != nil {
    return "", err
}
defer session.Close()

這邊指定的 Access Mode Read/Write 有助於在連線因果叢集時,讓叢集決定要將 Cypher 查詢指派給 Core server 還是 Replica server,正確的設定 Access Mode 將有助於資料庫的效能大幅提升。
不過在 Session 初始化時的 Access Mode 只會影響自動交易,如果是手動交易,Access Mode 最終還是取決於 Session.WriteTransaction 或是 Session.ReadTransaction

自動 Commit 的交易

Session.Run 就相當於 HTTP API 的 /tx/commit,在單次的資料庫要求開啟交易並立即確認執行。

Result.Consume 會一次讀取所有的回傳資料並回傳 Summary

result, err := session.Run("CREATE (a:Person {name: $name})", map[string]interface{}{"name":
name})
if err != nil {
    return err
}

if _, err = result.Consume(); err != nil {
    return err
}

手動交易

greeting, err := session.WriteTransaction(func(transaction neo4j.Transaction) (interface{}, error) {
    result, err := transaction.Run(
        "CREATE (a:Greeting) SET a.message = $message RETURN a.message + ', from node ' + id(a)",
        map[string]interface{}{"message": "hello, world"})
    if err != nil {
        return nil, err
    }
    if result.Next() {
        return result.Record().GetByIndex(0), nil
    }
    return nil, result.Err()
})

這邊用到了 Result.Next() 來確認是否有回傳結果,以及 Result.Record() 來取得每一筆資料
如果預期回傳的資料有多筆,可以這樣寫。

for result.Next() {
    record = result.Record();
    if value, ok := record.Get('field_name'); ok {
        // a value with alias field_name was found
        // process value
    }
}

以上也刻意示範了 Get by index 和 Get by field name 的選擇作法

Cypher 與 Golang driver 的資料型別對應

從資料庫取得的結果都會是 interface{} 型別,在程式碼中的操作很不便,但我們可以把它 UnBoxing 成真正的物件型別,列表如下

Cypher Type Driver Type
null nil
List []interface{}
Map map[string]interface{}
Boolean bool
Integer int64
Float float
String string
ByteArray []byte
Node neo4j.Node
Relationship neo4j.Relationship
Path neo4j.Path
Point neo4j.Point
Date neo4j.Date
Time neo4j.OffsetTime
LocalTime neo4j.LocalTime
DateTime time.Time
LocalDateTime neo4j.LocalDateTime
Duration neo4j.Duration

例如

value, ok := record.Get('birthday').(neo4j.Date)

連線因果叢集

如果資料庫是採用因果叢集架構,只需要將協定改成 bolt+routing 中可,後面接的機器位址則必須是任一台 Core Server。

if driver, err = neo4j.NewDriver("bolt+routing://localhost:7687", neo4j.BasicAuth("username", "password", "")); err != nil {
    return err
}

資考資源:

https://github.com/neo4j/neo4j-go-driver
https://neo4j.com/docs/pdf/neo4j-driver-manual-1.7-go.pdf
https://godoc.org/github.com/neo4j/neo4j-go-driver/neo4j


上一篇
使用 JavaScript API 開發 Neo4j 應用程式
下一篇
以 GraphQL 查詢 Neo4j 資料庫
系列文
看圖說故事,讓 Neo4j 重新詮釋你的資料庫30

尚未有邦友留言

立即登入留言