当前位置: 首页 > 面试题库 >

从代码创建Golang代码后,它并未插入BigQuery的表中

董意蕴
2023-03-14
问题内容

我有一个使用此架构的BigQuery表:

name    STRING  NULLABLE    
age     INTEGER NULLABLE    
amount  INTEGER NULLABLE

我可以使用以下代码成功插入表格中:

ctx := context.Background()
client, err := bigquery.NewClient(ctx, projectID)
if err != nil {
    log.Fatal(err)
}

u := client.Dataset(dataSetID).Table("test_user").Uploader()

savers := []*bigquery.StructSaver{
    {Struct: test{Name: "Sylvanas", Age: 23, Amount: 123}},
}

if err := u.Put(ctx, savers); err != nil {
    log.Fatal(err)
}
fmt.Printf("rows inserted!!")

这行得通,因为该表已经在bigquery上创建,我现在要做的就是删除该表(如果存在)并从代码中再次创建它:

type test struct {
    Name   string
    Age    int
    Amount int
}

if err := client.Dataset(dataSetID).Table("test_user").Delete(ctx); err != nil {
    log.Fatal(err)
}

fmt.Printf("table deleted")

t := client.Dataset(dataSetID).Table("test_user")

// Infer table schema from a Go type.
schema, err := bigquery.InferSchema(test{})

if err := t.Create(ctx,
    &bigquery.TableMetadata{
        Name:           "test_user",
        Schema:         schema,
    }); err != nil {
    log.Fatal(err)
}

fmt.Printf("table created with the test schema")

这也非常好用,因为要删除表并使用我的结构测试中的推断模式创建表。

当我尝试在删除/创建过程之后执行上述插入操作时,问题就来了。没有引发任何错误,但是它没有插入数据(如果我注释了删除/创建部分,则插入工作正常)。

我究竟做错了什么?我是否需要以某种方式提交创建表事务以进行插入,或者是否需要关闭DDBB连接?


问题答案:

根据旧答案,BigQuery流缓冲区可能需要最多2分钟的时间才能正确地附加到已删除并立即重新创建的表上。

我进行了一些测试,以我为例,该表仅用了几秒钟的时间,而不是其他问题报告的2〜5分钟。生成的代码与您的代码完全不同,但应使用概念。

我尝试的是,而不是直接插入行,而是将它们添加到缓冲通道中,然后等到可以验证当前表是否正确保存了值,然后再开始发送它们。

我使用了一种相当简单的结构来运行测试(因此编写代码更加容易):

type Row struct {
    ByteField []byte
}

我通过以下方式生成行:

func generateRows(rows chan<- *Row) {
    for {
            randBytes := make([]byte, 100)
            _, _ = rand.Read(randBytes)
            rows <- &row{randBytes}
            time.Sleep(time.Millisecond * 500) // use whatever frequency you need to insert rows at
    }
}

注意我如何将行发送到通道。不必生成它们,而只需从数据源中获取它们。

下一部分是找到一种方法来检查表是否正确保存了行。我所做的是尝试将缓冲的行之一插入表中,恢复该行,并验证是否一切正常。如果该行未正确返回,则将其发送回缓冲区。

func unreadyTable(rows chan *row) bool {
    client, err := bigquery.NewClient(context.Background(), project)
    if err != nil {return true}

    r := <-rows // get a row to try to insert       
    uploader := client.Dataset(dataset).Table(table).Uploader()
    if err := uploader.Put(context.Background(), r); err != nil {rows <- r;return true}

    i, err := client.Query(fmt.Sprintf("select * from `%s.%s.%s`", project, dataset, table)).Read(context.Background())
    if err != nil {rows <- r; return true}
    var testRow []bigquery.Value
    if err := i.Next(&testRow); err != nil {rows <- r;return true}
    if reflect.DeepEqual(&row{testrow[0].([]byte)}, r) {return false} // there's probably a better way to check if it's equal
    rows <- r;return true
}

使用这样的功能,我们只需要添加for ; unreadyTable(rows); time.Sleep(time.Second) {}即可,直到可以安全插入行为止。

最后,我们将所有内容放在一起:

func main() {

    // initialize a channel where the rows will be sent
    rows := make(chan *row, 1000) // make it big enough to hold several minutes of rows

    // start generating rows to be inserted
    go generateRows(rows)

    // create the BigQuery client
    client, err := bigquery.NewClient(context.Background(), project)
    if err != nil {/* handle error */}

    // delete the previous table
    if err := client.Dataset(dataset).Table(table).Delete(context.Background()); err != nil {/* handle error */}

    // create the new table
    schema, err := bigquery.InferSchema(row{})
    if err != nil {/* handle error */}
    if err := client.Dataset(dataset).Table(table).Create(context.Background(), &bigquery.TableMetadata{Schema: schema}); err != nil {/* handle error */}

    // wait for the table to be ready
    for ; unreadyTable(rows); time.Sleep(time.Second) {}

    // once it's ready, upload indefinitely
    for {
            if len(rows) > 0 { // if there are uninserted rows, create a batch and insert them
                    uploader := client.Dataset(dataset).Table(table).Uploader()
                    insert := make([]*row, min(500, len(rows))) // create a batch of all the rows on buffer, up to 500
                    for i := range insert {insert[i] = <-rows}
                    go func(insert []*row) { // do the actual insert async
                            if err := uploader.Put(context.Background(), insert); err != nil {/* handle error */}
                    }(insert)
            } else { // if there are no rows waiting to be inserted, wait and check again
                    time.Sleep(time.Second)
            }
    }
}

注意:由于math.Min()不喜欢int,因此必须包含func min(a,b int)int{if a<b{return a};return b}

这是我完整的工作示例。



 类似资料:
  • 本文向大家介绍django 多对多表的创建和插入代码实现,包括了django 多对多表的创建和插入代码实现的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了django-多对多表的创建和插入代码实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 表的创建 数据的添加 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐

  • 我的程序正在尝试从JFreeChart的旧版本升级,我们正在使用ant编译JFreeChart并将其作为一个组件导入。jar文件。我正在尝试将新的源代码(我在他们的网站上找不到jar)放到一个工作环境中。jar文件,通过使用: 当试图用新代码编译时。jar文件。我得到的错误是“package org.jfree.chart”不存在。我如何使用更新程序。最新JFreeChart版本的jar文件?

  • 问题内容: 我正在使用golang网络应用程序。在这种情况下,我需要迭代HTML行的次数。 我该如何实施? 问题答案: 要在Go模板中重复执行某些操作,您可以使用操作。但是该动作希望可以对其进行迭代,例如切片,数组或映射。 传递零值切片 所以你必须养活它。但是不需要内存的空片就足够了,例如。 模板代码: 测试它: 输出(在Go Playground上尝试): 使用填充的切片 如我们所见,索引从0开

  • 我需要从wsdl(使用wsdl url)为一个操作创建SOAP请求xml。我从一个web服务调用得到一个响应,我需要从这个响应中获取一些值,并将其添加到另一个web服务Soap请求中,然后再次执行一个web服务调用。因此,为了向soap请求添加新值,我需要获得完整的soap请求xml。这就是为什么我问如何从WSDD获得soap请求xml。我不能使用SoapUI,因为它每次都是动态的,所以我需要编写

  • 我需要为应用程序中的不同对象实例创建单独的日志。例如,如果我们处理书籍,我需要为每本书创建单独的日志文件。它可以与log4j2配合使用。xml文件,但我的内存中可能有数百个这样的对象,我不想创建这么长的配置文件。我想从代码中创建appender和logger。我查找了工作代码示例,但什么也没找到。 我尝试使用RollingFileAppender。createAppender,但未找到如何将其附加

  • 我试图用web表单做一个web调查应用程序。问题是我在调查创建部分有麻烦。