使用 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/[email protected]

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


<<:  [Python]如何Speech to Text: SpeechRecognition

>>:  菜鸟网页基础DAY28

[ JS个人笔记 ] Event Loop事件循环—DAY11

理解js单执行绪&非同步运行机制 由於js为单执行绪,也就是一次只处理一件事情并依序执行,但...

D26 如何用 Apps Script 自动化地创造与客制 Google Sheet?(三)依照范本大量复制试算表

今天的目标: 要怎麽样依照范本复制并改动 Google Sheet,并一次性地的将结果搜集到同一份 ...

Day 11 - 用 canvas 复刻 小画家 多边形

方法一 此多边形方法虽然不是小画家的画法,但一样可以达成多边形的做法,如下: /** * 滑鼠点下画...

Day 19:Hexo 文章分类设定小知识!你都知道了吗?

我自己的写文习惯是如果文章内容刚好符合两个分类,就会同时设定两个分类。不过这也意外让我入了一个坑啊(...

Day 12 Compose UI Dialog

今年的疫情蛮严重的,希望大家都过得安好,希望疫情快点过去,能回到一些线下技术聚会的时光~ 今天目标:...