golang无依赖事务型图数据库插件eliasdb支持REST API和类SQL查询
Golang无依赖事务型图数据库插件EliasDB支持REST API和类SQL查询
EliasDB简介
EliasDB是一个基于图的数据库,旨在为需要将数据存储为图的项目提供轻量级解决方案。
主要特性
- 基于支持事务和纯内存存储的自定义键值存储构建
- 数据存储在通过边连接的节点(键值对象)中
- 存储的图可以通过分区进行分离
- 存储的图支持级联删除 - 删除一个节点及其所有"子节点"
- 所有存储的数据都被索引,可以通过全文短语搜索快速搜索
- EliasDB有一个GraphQL接口,可用于存储和检索数据
- 对于更复杂的查询,EliasDB有自己的查询语言EQL,具有类似SQL的语法
- 包含一个脚本解释器,用于定义数据库操作的替代操作或编写后端逻辑
- 完全用Go编写,仅使用gorilla/websocket来支持GraphQL订阅的WebSocket
- 可以作为嵌入式数据库使用,也可以作为独立应用程序使用
- 作为独立应用程序使用时,内置HTTPS网络服务器,提供用户管理、REST API和基本文件服务器
- 作为嵌入式数据库使用时,支持带有回滚的事务、数据迭代和基于规则的一致性管理
快速入门(独立应用程序)
下载预编译的Windows(win64)或Linux(amd64)包,解压并执行:
eliasdb server
可执行文件应自动创建3个子文件夹和一个配置文件。它应该在9090端口启动一个HTTPS服务器。要查看终端,请将浏览器指向:
https://localhost:9090/db/term.html
接受服务器的自签名证书后,您应该会看到一个Web终端。可以通过简单的CTRL+C或用一个字符覆盖eliasdb.lck文件的内容来停止EliasDB。
REST API示例
EliasDB提供了一个REST API,可以通过动态生成的swagger.json定义浏览。以下是使用REST API的示例代码:
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
// 查询节点数据
resp, err := http.Get("https://localhost:9090/db/v1/graph/main?part=main&kind=Person")
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response:", err)
return
}
fmt.Println("Response:", string(body))
}
EQL类SQL查询示例
EliasDB的EQL查询语言允许执行类似SQL的查询。以下是一个示例:
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
// 准备EQL查询
query := `{
"query": "get Person where name = 'John' traverse Friend:friends:>1 where name = 'Mary'",
"part": "main"
}`
// 发送查询请求
resp, err := http.Post(
"https://localhost:9090/db/v1/query/main",
"application/json",
strings.NewReader(query),
)
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
// 读取响应
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response:", err)
return
}
fmt.Println("Query result:", string(body))
}
完整示例Demo
以下是一个完整的示例,展示如何使用EliasDB的REST API和EQL查询:
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
type Node struct {
Key string `json:"key"`
Kind string `json:"kind"`
Name string `json:"name"`
Data map[string]string `json:"data"`
}
type Edge struct {
Key string `json:"key"`
Kind string `json:"kind"`
From string `json:"from"`
To string `json:"to"`
FromKind string `json:"from_kind"`
ToKind string `json:"to_kind"`
}
func main() {
// 1. 创建节点
person1 := Node{
Key: "john",
Kind: "Person",
Name: "John Doe",
Data: map[string]string{
"age": "30",
"city": "New York",
},
}
person2 := Node{
Key: "mary",
Kind: "Person",
Name: "Mary Smith",
Data: map[string]string{
"age": "28",
"city": "Boston",
},
}
// 存储节点
storeNode(person1)
storeNode(person2)
// 2. 创建边
friendship := Edge{
Key: "john-mary",
Kind: "Friend",
From: "john",
To: "mary",
FromKind: "Person",
ToKind: "Person",
}
// 存储边
storeEdge(friendship)
// 3. 执行EQL查询
query := map[string]string{
"query": "get Person where name = 'John Doe' traverse Friend:friends:>1 where name = 'Mary Smith'",
"part": "main",
}
queryResult := executeEQL(query)
fmt.Println("Query Result:", queryResult)
}
func storeNode(node Node) {
url := "https://localhost:9090/db/v1/graph/main"
jsonData, _ := json.Marshal(node)
resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
fmt.Println("Error storing node:", err)
return
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Printf("Stored node %s: %s\n", node.Key, string(body))
}
func storeEdge(edge Edge) {
url := "https://localhost:9090/db/v1/graph/main"
jsonData, _ := json.Marshal(edge)
resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
fmt.Println("Error storing edge:", err)
return
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Printf("Stored edge %s: %s\n", edge.Key, string(body))
}
func executeEQL(query map[string]string) string {
url := "https://localhost:9090/db/v1/query/main"
jsonData, _ := json.Marshal(query)
resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
fmt.Println("Error executing query:", err)
return ""
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
return string(body)
}
嵌入式使用示例
EliasDB也可以作为嵌入式数据库使用:
package main
import (
"fmt"
"devt.de/krotik/eliasdb/api"
"devt.de/krotik/eliasdb/eql"
"devt.de/krotik/eliasdb/graph"
"devt.de/krotik/eliasdb/graph/data"
"devt.de/krotik/eliasdb/graph/graphstorage"
)
func main() {
// 1. 创建内存存储
gs, err := graphstorage.NewMemoryGraphStorage("mystorage")
if err != nil {
panic(err)
}
// 2. 创建图管理器
gm := graph.NewGraphManager(gs)
// 3. 创建分区
gm.CreatePartition("main")
// 4. 添加节点和边
node1 := data.NewGraphNode()
node1.SetAttr("key", "john")
node1.SetAttr("kind", "Person")
node1.SetAttr("name", "John Doe")
node1.SetAttr(data.NodeAttrPartition, "main")
node2 := data.NewGraphNode()
node2.SetAttr("key", "mary")
node2.SetAttr("kind", "Person")
node2.SetAttr("name", "Mary Smith")
node2.SetAttr(data.NodeAttrPartition, "main")
// 存储节点
gm.StoreNode("main", node1)
gm.StoreNode("main", node2)
// 创建边
edge := data.NewGraphEdge()
edge.SetAttr("key", "john-mary")
edge.SetAttr("kind", "Friend")
edge.SetAttr("from", "john")
edge.SetAttr("to", "mary")
edge.SetAttr("fromkind", "Person")
edge.SetAttr("tokind", "Person")
edge.SetAttr(data.NodeAttrPartition, "main")
// 存储边
gm.StoreEdge("main", edge)
// 5. 执行EQL查询
res, err := eql.ParseAndExecute("get Person where name = 'John Doe'", gm, "main")
if err != nil {
panic(err)
}
// 6. 处理结果
for _, row := range res.Rows {
fmt.Println("Node:", row[0])
}
// 7. 启动REST API服务
api.Start(gm, "localhost:9090")
}
总结
EliasDB是一个功能丰富的图数据库,提供:
- 无外部依赖的轻量级解决方案
- 支持事务操作
- 提供REST API接口
- 支持类SQL的EQL查询语言
- 可作为独立服务或嵌入式数据库使用
通过上述示例代码,您可以快速开始使用EliasDB的REST API和EQL查询功能来构建图数据库应用。
更多关于golang无依赖事务型图数据库插件eliasdb支持REST API和类SQL查询的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang无依赖事务型图数据库插件eliasdb支持REST API和类SQL查询的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
EliasDB - Go语言无依赖事务型图数据库插件
EliasDB是一个用纯Go编写的轻量级图数据库,具有以下特点:
- 无外部依赖
- 支持ACID事务
- 提供REST API接口
- 支持类SQL查询语言(EQL)
- 嵌入式设计,可作为库直接集成到应用中
基本概念
EliasDB中的数据组织为:
- 节点(Node):表示实体,有类型和属性
- 边(Edge):表示节点间关系,有类型和方向
- 分区(Partition):数据逻辑分组,类似命名空间
安装
go get github.com/krotik/eliasdb
基本使用示例
1. 创建数据库实例
package main
import (
"github.com/krotik/eliasdb/api"
"github.com/krotik/eliasdb/eql"
"github.com/krotik/eliasdb/graph"
"github.com/krotik/eliasdb/graph/data"
"github.com/krotik/eliasdb/graph/graphstorage"
)
func main() {
// 创建内存存储
gs := graphstorage.NewMemoryGraphStorage("mygraph")
// 创建图管理器
gm := graph.NewGraphManager(gs)
// 创建分区
gm.EnsureNodeType("main", "Person")
gm.EnsureNodeType("main", "City")
gm.EnsureEdgeType("main", "LivesIn")
// 启动REST API服务
api.StartServer(":9090", "/api/v1", gm, "web")
}
2. 添加数据
// 添加节点
person := data.NewGraphNode()
person.SetAttr("key", "john")
person.SetAttr("name", "John Doe")
person.SetAttr("age", 34)
person.SetAttr("kind", "Person")
city := data.NewGraphNode()
city.SetAttr("key", "ny")
city.SetAttr("name", "New York")
city.SetAttr("kind", "City")
// 添加边
edge := data.NewGraphEdge()
edge.SetAttr("key", "john_ny")
edge.SetAttr("kind", "LivesIn")
edge.SetAttr("from", "john")
edge.SetAttr("to", "ny")
// 事务方式写入
gm.StoreNode("main", person)
gm.StoreNode("main", city)
gm.StoreEdge("main", edge)
3. 使用EQL查询
// 查询所有名为John的人
res, err := eql.ParseAndExecute("get Person where name = 'John Doe'", gm, "main")
// 查询John住在哪里
res, err := eql.ParseAndExecute(`
traverse end:City from Person:john
via LivesIn:john_ny
`, gm, "main")
4. REST API示例
EliasDB提供了完整的REST API接口:
- 查询节点:
GET /api/v1/query/main?q=get Person where name = 'John Doe'
- 添加节点:
POST /api/v1/node/main/Person
{ "key": "mary", "name": "Mary Smith", "age": 28 }
- 添加关系:
POST /api/v1/edge/main/LivesIn
{ "key": "mary_ny", "from": "mary", "to": "ny" }
高级特性
1. 事务处理
tx := gm.NewGraphTraversal("main")
defer tx.Rollback()
// 在事务中操作
tx.StoreNode(person)
tx.StoreEdge(edge)
// 提交事务
if err := tx.Commit(); err != nil {
// 处理错误
}
2. 全文搜索
// 创建全文索引
gm.EnsureNodeFulltextIndex("main", "Person", "name")
// 使用全文搜索查询
res, err := eql.ParseAndExecute(`
get Person where fulltext(name) = 'John'
`, gm, "main")
3. 复杂遍历查询
// 查找John的朋友的朋友
res, err := eql.ParseAndExecute(`
traverse depth:2 from Person:john
via Friend:*
`, gm, "main")
性能优化建议
-
为常用查询条件创建索引:
gm.EnsureNodeIndex("main", "Person", "age")
-
对大图使用分页查询:
res, err := eql.ParseAndExecute(` get Person limit 10 offset 20 `, gm, "main")
-
考虑使用磁盘存储替代内存存储:
gs := graphstorage.NewDiskGraphStorage("data", "mygraph")
适用场景
EliasDB适合以下场景:
- 需要嵌入式图数据库的Go应用
- 中小规模图数据(百万节点级别)
- 需要事务支持的场景
- 需要简单REST接口的项目
对于超大规模图数据,可能需要考虑Neo4j等专业图数据库解决方案。
EliasDB以其简洁性和零依赖特性,成为Go生态中图数据库的一个轻量级选择。