跳转至
开发版采用单机部署,无需产品 License 文件。需要多机部署或大规模性能测试? 了解企业版

Go SDK 指南

本文介绍如何使用 Go SDK 连接悦数图数据库开发版并进行简单查询。

前提条件

  • 对于本地部署用户,悦数图数据库开发版服务组正在运行中。更多信息,请参见快速开始。

操作步骤

  1. 修改 Go 模块依赖项以使用 Go SDK 的本地版本。例如:

    workspace=/app/myapp
    
    # 在 Go 项目中,运行 go mod edit
    cd ${workspace}
    go get github.com/vesoft-inc/nebula-go/v5@5.3.0
    

    更多信息,请参见 go.mod 文件参考。

  2. 使用 SDK 连接悦数图数据库开发版并执行查询,例如:

    Note

    针对本地部署用户,在连接悦数图数据库开发版时,除了指定用户名和密码外,还可以启用无会话模式。该模式允许您不提供身份验证信息。更多信息,请参见无会话模式。

    package main
    
    import (
     "fmt"
    
     nebula "github.com/vesoft-inc/nebula-go/v5"
    )
    
    const (
     address  = "<host>:<port>"
     username = "<username>"
     password = "<password>"
    )
    
    // Initialize logger
    var log = nebula.DefaultLogger
    
    func basicClient() {
     client, err := nebula.NewNebulaClient(address, username, password)
     if err != nil {
      log.Error(err.Error())
      return
     }
     resp, err := client.Execute("return 1 as a")
     if err != nil {
      log.Error(err.Error())
      return
     }
     log.Info(fmt.Sprintf("columns: %v", resp.Columns()))
     for resp.HasNext() {
      row, err := resp.Next()
      if err != nil {
       log.Error(err.Error())
       return
      }
      v1, err := row.GetValueByIndex(0)
      if err != nil {
       log.Error(err.Error())
       return
      }
      log.Info(v1.String())
      v2, err := row.GetValueByName("a")
      if err != nil {
       log.Error(err.Error())
       return
      }
      log.Info(v2.String())
     }
    }
    
    func basicPool() {
     pool, err := nebula.NewNebulaPool(address, username, password)
     if err != nil {
      log.Error(err.Error())
      return
     }
     client, err := pool.GetClient()
     if err != nil {
      log.Error(err.Error())
      return
     }
     resp, err := client.Execute("return 1 as a")
     if err != nil {
      log.Error(err.Error())
      return
     }
     log.Info(fmt.Sprintf("columns: %v", resp.Columns()))
     for resp.HasNext() {
      row, err := resp.Next()
      if err != nil {
       log.Error(err.Error())
       return
      }
      v1, err := row.GetValueByIndex(0)
      if err != nil {
       log.Error(err.Error())
       return
      }
      log.Info(v1.String())
      v2, err := row.GetValueByName("a")
      if err != nil {
       log.Error(err.Error())
       return
      }
      log.Info(v2.String())
     }
    }
    
    func main() {
     basicClient()
     basicPool()
    }
    

    若目标图不在默认 Schema(/default_schema)中,可按以下方式指定 Schema:

    // 方式一:对于 NewNebulaClient 获取的 client,手动设置 Schema 和图
    _, err = client.Execute("SESSION SET SCHEMA /my_schema")
    if err != nil {
     log.Error(err.Error())
     return
    }
    
    _, err = client.Execute("USE my_graph")
    if err != nil {
     log.Error(err.Error())
     return
    }
    
    resp, err = client.Execute("MATCH (v) RETURN v LIMIT 10")
    if err != nil {
     log.Error(err.Error())
     return
    }
    
    // 方式二:对于 NewNebulaPool,可在初始化时指定 Schema 和图
    pool, err := nebula.NewNebulaPool(
     address,
     username,
     password,
     nebula.WithPoolSchema("/my_schema"),
     nebula.WithPoolGraph("my_graph"),
    )
    if err != nil {
     log.Error(err.Error())
     return
    }
    defer pool.Close()
    
    client2, err := pool.GetClient()
    if err != nil {
     log.Error(err.Error())
     return
    }
    defer pool.PutClient(client2)
    
    resp, err = client2.Execute("MATCH (v) RETURN v LIMIT 10")
    if err != nil {
     log.Error(err.Error())
     return
    }
    

    使用连接池时,WithPoolSchema和WithPoolGraph会在连接创建时自动设置会话上下文。若未指定WithPoolSchema,新建会话将使用默认 Schema(例如/default_schema)。

    更多信息,请参见 SESSION SET SCHEMA 和 USE 子句。 参数<host>、<port>、<username>和<password>须替换为实际的悦数图数据库开发版连接信息。

最佳实践

在处理查询结果时,您可以使用以下任一方法来存储结果值:

  • 方法一:在循环内声明结构体变量

      resp, err = client.Execute(query)
      if err != nil {
          log.Error(fmt.Sprintf("Failed to execute query: %v", err))
          return
      }
      for resp.HasNext() {
          var p Person
          if err := resp.Scan(&p.id, &p.birthday, &p.firstName); err != nil {
              log.Error(fmt.Sprintf("Failed to scan row: %v", err))
              return
          }
          if p.id.Valid && p.birthday.Valid && p.firstName.Valid {
              fmt.Printf("id: %d, ", p.id.Data)
              fmt.Printf("birthday: %d-%d-%d, ", p.birthday.Data.GetYear(),
                  p.birthday.Data.GetMonth(), p.birthday.Data.GetDay())
              fmt.Printf("first name: %s\n", p.firstName.Data)
          }
      }
    
  • 方法二:在循环外声明结构体变量

      resp, err = client.Execute(query)
      if err != nil {
          log.Error(fmt.Sprintf("Failed to execute query: %v", err))
          return
      }
      var p Person
      for resp.HasNext() {
          if err := resp.Scan(&p.id, &p.birthday, &p.firstName); err != nil {
              log.Error(fmt.Sprintf("Failed to scan row: %v", err))
              return
          }
          if p.id.Valid && p.birthday.Valid && p.firstName.Valid {
              fmt.Printf("id: %d, ", p.id.Data)
              fmt.Printf("birthday: %d-%d-%d, ", p.birthday.Data.GetYear(),
                  p.birthday.Data.GetMonth(), p.birthday.Data.GetDay())
              fmt.Printf("first name: %s\n", p.firstName.Data)
          }
      }
    

在上述两种方法中,查询结果被扫描到Person结构体中,其定义如下:

type Person struct {
    id        nebula.NullInt64
    birthday  nebula.NullDate
    firstName nebula.NullString
}

在方法一中,Person结构体在循环内声明,因此每次迭代都会创建一个新的p实例。在方法二中,它在循环外声明,因此每次迭代都重用同一个p实例。两种方法均可用,但方法二在处理数据量较大结果集时,在内存使用和性能方面更为高效。

更多信息