Go语言开发者的Apache Arrow使用指南:高级数据结构

news2025/1/11 0:37:05

经过对前面两篇文章《Arrow数据类型》[1]和《Arrow Go实现的内存管理》[2]的学习,我们知道了各种Arrow array type以及它们在内存中的layout,我们了解了Go arrow实现在内存管理上的一些机制和使用原则。

Arrow的array type只是一个定长的、同类型的值序列。在实际应用中,array type更多时候只是充当基础类型,我们需要具有组合基础类型能力的更高级的数据结构。在这一篇文章中,我们就来看看Arrow规范以及一些实现中提供的高级数据结构,包括Record Batch、Chunked Array以及Table。

我们先来看看Record Batch[3]

1. Record Batch

Record这个名字让我想起了[Pascal编程语言](https://en.wikipedia.org/wiki/Pascal_(programming_language "Pascal编程语言"))中的Record。在Pascal中,Record的角色大致与Go中的Struct类似,也是一组异构字段的集合。下面是《In-Memory Analytics with Apache Arrow》[4]书中的一个Record例子:

// 以Go语言呈现
type Archer struct {
 archer string
 location string
 year int16
}

Record Batch则顾名思义,是一批Record,即一个Record的集合:[N]Archer。

如果将Record的各个字段作为列,将集合中的每个Record作为行,我们能得到如下面示意图中的结构:

ffbc547fd2dc1ac7dd947abe74bf23e4.png

Go Arrow实现中没有直接使用“Record Batch”这个名字,而是使用了“Record”,这个“Record”实际代表的就是Record Batch。下面是Go Arrow实现定义的Record接口:

// github.com/apache/arrow/go/arrow/record.go

// Record is a collection of equal-length arrays matching a particular Schema.
// Also known as a RecordBatch in the spec and in some implementations.
//
// It is also possible to construct a Table from a collection of Records that
// all have the same schema.
type Record interface {
    json.Marshaler

    Release()
    Retain()

    Schema() *Schema

    NumRows() int64
    NumCols() int64

    Columns() []Array
    Column(i int) Array
    ColumnName(i int) string
    SetColumn(i int, col Array) (Record, error)

    // NewSlice constructs a zero-copy slice of the record with the indicated
    // indices i and j, corresponding to array[i:j].
    // The returned record must be Release()'d after use.
    //
    // NewSlice panics if the slice is outside the valid range of the record array.
    // NewSlice panics if j < i.
    NewSlice(i, j int64) Record
}

我们依然可以使用Builder模式来创建一个arrow.Record,下面我们就来用Go代码创建[N]Archer这个Record Batch:

// record_batch.go
func main() {
    schema := arrow.NewSchema(
        []arrow.Field{
            {Name: "archer", Type: arrow.BinaryTypes.String},
            {Name: "location", Type: arrow.BinaryTypes.String},
            {Name: "year", Type: arrow.PrimitiveTypes.Int16},
        },
        nil,
    )

    rb := array.NewRecordBuilder(memory.DefaultAllocator, schema)
    defer rb.Release()

    rb.Field(0).(*array.StringBuilder).AppendValues([]string{"tony", "amy", "jim"}, nil)
    rb.Field(1).(*array.StringBuilder).AppendValues([]string{"beijing", "shanghai", "chengdu"}, nil)
    rb.Field(2).(*array.Int16Builder).AppendValues([]int16{1992, 1993, 1994}, nil)

    rec := rb.NewRecord()
    defer rec.Release()

    fmt.Println(rec)
}

运行上述示例,输出如下:

$go run record_batch.go 
record:
  schema:
  fields: 3
    - archer: type=utf8
    - location: type=utf8
    - year: type=int16
  rows: 3
  col[0][archer]: ["tony" "amy" "jim"]
  col[1][location]: ["beijing" "shanghai" "chengdu"]
  col[2][year]: [1992 1993 1994]

在这个示例里,我们看到了一个名为Schema的概念,并且NewRecordBuilder创建时需要传入一个arrow.Schema的实例。和数据库表Schema类似,Arrow中的Schema也是一个元数据概念,它包含一系列作为“列”的字段的名称和类型信息。Schema不仅在Record Batch中使用,在后面的Table中,Schema也是必要元素。

arrow.Record可以通过NewSlice可以ZeroCopy方式共享Record Batch的内存数据,NewSlice会创建一个新的Record Batch,这个Record Batch中的Record与原Record是共享的:

// record_batch_slice.go

sl := rec.NewSlice(0, 2)
fmt.Println(sl)
cols := sl.Columns()
a1 := cols[0]
fmt.Println(a1)

新的sl取了rec的前两个record,输出sl得到如下结果:

record:
  schema:
  fields: 3
    - archer: type=utf8
    - location: type=utf8
    - year: type=int16
  rows: 2
  col[0][archer]: ["tony" "amy"]
  col[1][location]: ["beijing" "shanghai"]
  col[2][year]: [1992 1993]

["tony" "amy"]

相同schema的record batch可以合并,我们只需要分配一个更大的Record Batch,然后将两个待合并的Record batch copy到新Record Batch中就可以了,但显然这样做的开销很大。

Arrow的一些实现中提供了Chunked Array的概念,可以更低开销的来完成某个列的array的追加。

注:Chunked array并不是Arrow Columnar Format的一部分。

2. Chunked Array

如果说Record Batch本质上是不同Array type的横向聚合,那么Chunked Array就是相同Array type的纵向聚合了,用Go语法表示就是:[N]Array或[]Array,即array of array。下面是一个Chunked Array的结构示意图:

20ddbcdebd62f4a1cd31f70c352ce1fe.png

我们看到:Go的Chunked array的实现使用的是一个Array切片:

// github.com/apache/arrow/go/arrow/table.go

// Chunked manages a collection of primitives arrays as one logical large array.
type Chunked struct {
    refCount int64 // refCount must be first in the struct for 64 bit alignment and sync/atomic (https://github.com/golang/go/issues/37262)

    chunks []Array

    length int
    nulls  int
    dtype  DataType
}

按照Go切片的本质,Chunked Array中的各个元素Array间的实际内存buffer并不连续。并且正如示意图所示:每个Array的长度也并非是一样的。

注:在《Go语言第一课》[5]中的第15讲中有关于切片本质的深入系统的讲解。

我们可以使用arrow包提供的NewChunked函数创建一个Chunked Array,具体见下面源码:

// chunked_array.go

func main() {
    ib := array.NewInt64Builder(memory.DefaultAllocator)
    defer ib.Release()

    ib.AppendValues([]int64{1, 2, 3, 4, 5}, nil)
    i1 := ib.NewInt64Array()
    defer i1.Release()

    ib.AppendValues([]int64{6, 7}, nil)
    i2 := ib.NewInt64Array()
    defer i2.Release()
    
    ib.AppendValues([]int64{8, 9, 10}, nil)
    i3 := ib.NewInt64Array()
    defer i3.Release()

    c := arrow.NewChunked(
        arrow.PrimitiveTypes.Int64,
        []arrow.Array{i1, i2, i3},
    )
    defer c.Release()

    for _, arr := range c.Chunks() {
        fmt.Println(arr)
    }
    
    fmt.Println("chunked length =", c.Len())
    fmt.Println("chunked null count=", c.NullN())
}

我们看到在Chunked Array聚合了多个arrow.Array实例,并且这些arrow.Array实例的长短可不一致,arrow.Chunked的Len()返回的则是Chunked中Array的长度之和。下面是示例程序的输出结果:

$go run chunked_array.go 
[1 2 3 4 5]
[6 7]
[8 9 10]
chunked length = 10
chunked null count= 0

这样来看,Chunked Array可以看成一个逻辑上的大Array。

好了,问题来了!Record Batch是用来聚合等长array type的,那么是否有某种数据结构可以用来聚合等长的Chunked Array呢?答案是有的!下面我们就来看看这种结构:Table。

3. Table

Table和Chunked Array一样并不属于Arrow Columnar Format的一部分,最初只是Arrow的C++实现中的一个数据结构,Go Arrow的实现也提供了对Table的支持。

Table的结构示意图如下(图摘自《In-Memory Analytics with Apache Arrow》[6]一书):

f8fa26a45cd14bf10998f46807b6b848.png

我们看到:和Record Batch的每列是一个array不同,Table的每一列为一个chunked array,所有列的chunked array的Length是相同的,但各个列的chunked array中的array的长度可以不同。

Table和Record Batch相似的地方是都有自己的Schema。

下面的示意图(来自这里[7])对Table和Chunked Array做了十分直观的对比:

613f1fce0b14ac9613bc9ce614180f1e.png

Record Batch是Arrow Columnar format中的一部分,所有语言的实现都支持Record Batch;但Table并非format spec的一部分,并非所有语言的实现对其都提供支持。

另外从图中看到,由于Table采用了Chunked Array作为列,chunked array下的各个array内部分布并不连续,这让Table在运行时丧失了一些局部性。

下面我们就使用Go arrow实现来创建一个table,这是一个3列、10行的table:

// table.go

func main() {
 schema := arrow.NewSchema(
  []arrow.Field{
   {Name: "col1", Type: arrow.PrimitiveTypes.Int32},
   {Name: "col2", Type: arrow.PrimitiveTypes.Float64},
   {Name: "col3", Type: arrow.BinaryTypes.String},
  },
  nil,
 )

 col1 := func() *arrow.Column {
  chunk := func() *arrow.Chunked {
   ib := array.NewInt32Builder(memory.DefaultAllocator)
   defer ib.Release()

   ib.AppendValues([]int32{1, 2, 3}, nil)
   i1 := ib.NewInt32Array()
   defer i1.Release()

   ib.AppendValues([]int32{4, 5, 6, 7, 8, 9, 10}, nil)
   i2 := ib.NewInt32Array()
   defer i2.Release()

   c := arrow.NewChunked(
    arrow.PrimitiveTypes.Int32,
    []arrow.Array{i1, i2},
   )
   return c
  }()
  defer chunk.Release()

  return arrow.NewColumn(schema.Field(0), chunk)
 }()
 defer col1.Release()

 col2 := func() *arrow.Column {
  chunk := func() *arrow.Chunked {
   fb := array.NewFloat64Builder(memory.DefaultAllocator)
   defer fb.Release()

   fb.AppendValues([]float64{1.1, 2.2, 3.3, 4.4, 5.5}, nil)
   f1 := fb.NewFloat64Array()
   defer f1.Release()

   fb.AppendValues([]float64{6.6, 7.7}, nil)
   f2 := fb.NewFloat64Array()
   defer f2.Release()

   fb.AppendValues([]float64{8.8, 9.9, 10.0}, nil)
   f3 := fb.NewFloat64Array()
   defer f3.Release()

   c := arrow.NewChunked(
    arrow.PrimitiveTypes.Float64,
    []arrow.Array{f1, f2, f3},
   )
   return c
  }()
  defer chunk.Release()

  return arrow.NewColumn(schema.Field(1), chunk)
 }()
 defer col2.Release()

 col3 := func() *arrow.Column {
  chunk := func() *arrow.Chunked {
   sb := array.NewStringBuilder(memory.DefaultAllocator)
   defer sb.Release()

   sb.AppendValues([]string{"s1", "s2"}, nil)
   s1 := sb.NewStringArray()
   defer s1.Release()

   sb.AppendValues([]string{"s3", "s4"}, nil)
   s2 := sb.NewStringArray()
   defer s2.Release()

   sb.AppendValues([]string{"s5", "s6", "s7", "s8", "s9", "s10"}, nil)
   s3 := sb.NewStringArray()
   defer s3.Release()

   c := arrow.NewChunked(
    arrow.BinaryTypes.String,
    []arrow.Array{s1, s2, s3},
   )
   return c
  }()
  defer chunk.Release()

  return arrow.NewColumn(schema.Field(2), chunk)
 }()
 defer col3.Release()

 var tbl arrow.Table
 tbl = array.NewTable(schema, []arrow.Column{*col1, *col2, *col3}, -1)
 defer tbl.Release()

 dumpTable(tbl)
}

func dumpTable(tbl arrow.Table) {
 s := tbl.Schema()
 fmt.Println(s)
 fmt.Println("------")

 fmt.Println("the count of table columns=", tbl.NumCols())
 fmt.Println("the count of table rows=", tbl.NumRows())
 fmt.Println("------")

 for i := 0; i < int(tbl.NumCols()); i++ {
  col := tbl.Column(i)
  fmt.Printf("arrays in column(%s):\n", col.Name())
  chunk := col.Data()
  for _, arr := range chunk.Chunks() {
   fmt.Println(arr)
  }
  fmt.Println("------")
 }
}

我们看到:table创建之前,我们需要准备一个schema,以及各个column。每个column则是一个chunked array。

运行上述代码,我们得到如下结果:

$go run table.go
schema:
  fields: 3
    - col1: type=int32
    - col2: type=float64
    - col3: type=utf8
------
the count of table columns= 3
the count of table rows= 10
------
arrays in column(col1):
[1 2 3]
[4 5 6 7 8 9 10]
------
arrays in column(col2):
[1.1 2.2 3.3 4.4 5.5]
[6.6 7.7]
[8.8 9.9 10]
------
arrays in column(col3):
["s1" "s2"]
["s3" "s4"]
["s5" "s6" "s7" "s8" "s9" "s10"]
------

table还支持schema变更,我们可以基于上述代码为table增加一列:

// table_schema_change.go

func main() {
 schema := arrow.NewSchema(
  []arrow.Field{
   {Name: "col1", Type: arrow.PrimitiveTypes.Int32},
   {Name: "col2", Type: arrow.PrimitiveTypes.Float64},
   {Name: "col3", Type: arrow.BinaryTypes.String},
  },
  nil,
 )

 col1 := func() *arrow.Column {
  chunk := func() *arrow.Chunked {
   ib := array.NewInt32Builder(memory.DefaultAllocator)
   defer ib.Release()

   ib.AppendValues([]int32{1, 2, 3}, nil)
   i1 := ib.NewInt32Array()
   defer i1.Release()

   ib.AppendValues([]int32{4, 5, 6, 7, 8, 9, 10}, nil)
   i2 := ib.NewInt32Array()
   defer i2.Release()

   c := arrow.NewChunked(
    arrow.PrimitiveTypes.Int32,
    []arrow.Array{i1, i2},
   )
   return c
  }()
  defer chunk.Release()

  return arrow.NewColumn(schema.Field(0), chunk)
 }()
 defer col1.Release()

 col2 := func() *arrow.Column {
  chunk := func() *arrow.Chunked {
   fb := array.NewFloat64Builder(memory.DefaultAllocator)
   defer fb.Release()

   fb.AppendValues([]float64{1.1, 2.2, 3.3, 4.4, 5.5}, nil)
   f1 := fb.NewFloat64Array()
   defer f1.Release()

   fb.AppendValues([]float64{6.6, 7.7}, nil)
   f2 := fb.NewFloat64Array()
   defer f2.Release()

   fb.AppendValues([]float64{8.8, 9.9, 10.0}, nil)
   f3 := fb.NewFloat64Array()
   defer f3.Release()

   c := arrow.NewChunked(
    arrow.PrimitiveTypes.Float64,
    []arrow.Array{f1, f2, f3},
   )
   return c
  }()
  defer chunk.Release()

  return arrow.NewColumn(schema.Field(1), chunk)
 }()
 defer col2.Release()

 col3 := func() *arrow.Column {
  chunk := func() *arrow.Chunked {
   sb := array.NewStringBuilder(memory.DefaultAllocator)
   defer sb.Release()

   sb.AppendValues([]string{"s1", "s2"}, nil)
   s1 := sb.NewStringArray()
   defer s1.Release()

   sb.AppendValues([]string{"s3", "s4"}, nil)
   s2 := sb.NewStringArray()
   defer s2.Release()

   sb.AppendValues([]string{"s5", "s6", "s7", "s8", "s9", "s10"}, nil)
   s3 := sb.NewStringArray()
   defer s3.Release()

   c := arrow.NewChunked(
    arrow.BinaryTypes.String,
    []arrow.Array{s1, s2, s3},
   )
   return c
  }()
  defer chunk.Release()

  return arrow.NewColumn(schema.Field(2), chunk)
 }()
 defer col3.Release()

 var tbl arrow.Table
 tbl = array.NewTable(schema, []arrow.Column{*col1, *col2, *col3}, -1)
 defer tbl.Release()

 dumpTable(tbl)

 col4 := func() *arrow.Column {
  chunk := func() *arrow.Chunked {
   sb := array.NewStringBuilder(memory.DefaultAllocator)
   defer sb.Release()

   sb.AppendValues([]string{"ss1", "ss2"}, nil)
   s1 := sb.NewStringArray()
   defer s1.Release()

   sb.AppendValues([]string{"ss3", "ss4", "ss5"}, nil)
   s2 := sb.NewStringArray()
   defer s2.Release()

   sb.AppendValues([]string{"ss6", "ss7", "ss8", "ss9", "ss10"}, nil)
   s3 := sb.NewStringArray()
   defer s3.Release()

   c := arrow.NewChunked(
    arrow.BinaryTypes.String,
    []arrow.Array{s1, s2, s3},
   )
   return c
  }()
  defer chunk.Release()

  return arrow.NewColumn(arrow.Field{Name: "col4", Type: arrow.BinaryTypes.String}, chunk)
 }()
 defer col4.Release()

 tbl, err := tbl.AddColumn(
  3,
  arrow.Field{Name: "col4", Type: arrow.BinaryTypes.String},
  *col4,
 )
 if err != nil {
  panic(err)
 }

 dumpTable(tbl)
}

运行上述示例,输出如下:

$go run table_schema_change.go
schema:
  fields: 3
    - col1: type=int32
    - col2: type=float64
    - col3: type=utf8
------
the count of table columns= 3
the count of table rows= 10
------
arrays in column(col1):
[1 2 3]
[4 5 6 7 8 9 10]
------
arrays in column(col2):
[1.1 2.2 3.3 4.4 5.5]
[6.6 7.7]
[8.8 9.9 10]
------
arrays in column(col3):
["s1" "s2"]
["s3" "s4"]
["s5" "s6" "s7" "s8" "s9" "s10"]
------
schema:
  fields: 4
    - col1: type=int32
    - col2: type=float64
    - col3: type=utf8
    - col4: type=utf8
------
the count of table columns= 4
the count of table rows= 10
------
arrays in column(col1):
[1 2 3]
[4 5 6 7 8 9 10]
------
arrays in column(col2):
[1.1 2.2 3.3 4.4 5.5]
[6.6 7.7]
[8.8 9.9 10]
------
arrays in column(col3):
["s1" "s2"]
["s3" "s4"]
["s5" "s6" "s7" "s8" "s9" "s10"]
------
arrays in column(col4):
["ss1" "ss2"]
["ss3" "ss4" "ss5"]
["ss6" "ss7" "ss8" "ss9" "ss10"]
------

这种对schema变更操作的支持在实际开发中也是非常有用的。

4. 小结

本文讲解了基于array type的三个高级数据结构:Record Batch、Chunked Array和Table。其中Record Batch是Arrow Columnar Format中的结构,可以被所有实现arrow的编程语言所支持;Chunked Array和Table则是在一些编程语言的实现中创建的。

三个概念容易混淆,这里给出简单记法:

  • Record Batch: schema + 长度相同的多个array

  • Chunked Array: []array

  • Table: schema + 总长度相同的多个Chunked Array

注:本文涉及的源代码在这里[8]可以下载。

5. 参考资料

  • Apache Arrow Glossary[9] - https://arrow.apache.org/docs/format/Glossary.html


“Gopher部落”知识星球[10]旨在打造一个精品Go学习和进阶社群!高品质首发Go技术文章,“三天”首发阅读权,每年两期Go语言发展现状分析,每天提前1小时阅读到新鲜的Gopher日报,网课、技术专栏、图书内容前瞻,六小时内必答保证等满足你关于Go语言生态的所有需求!2023年,Gopher部落将进一步聚焦于如何编写雅、地道、可读、可测试的Go代码,关注代码质量并深入理解Go核心技术,并继续加强与星友的互动。欢迎大家加入!

401ea98b2ecb40f052ee5a7ff3d98487.png

e39c7366745e117b1232ea0602faa45c.png

010d3fd267ba302234612f5acfeb3ae2.png

0fdadad55400c337b0a9b3d982dfbd2a.jpeg

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址[11]:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻)归档仓库 - https://github.com/bigwhite/gopherdaily

我的联系方式:

  • 微博(暂不可用):https://weibo.com/bigwhite20xx

  • 微博2:https://weibo.com/u/6484441286

  • 博客:tonybai.com

  • github: https://github.com/bigwhite

7e4a4e84a829a483c545716cb9bde887.jpeg

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

参考资料

[1] 

《Arrow数据类型》: https://tonybai.com/2023/06/25/a-guide-of-using-apache-arrow-for-gopher-part1

[2] 

《Arrow Go实现的内存管理》: https://tonybai.com/2023/06/30/a-guide-of-using-apache-arrow-for-gopher-part2

[3] 

Record Batch: https://arrow.apache.org/docs/format/Glossary.html#term-record-batch

[4] 

《In-Memory Analytics with Apache Arrow》: https://book.douban.com/subject/35954154/

[5] 

《Go语言第一课》: http://gk.link/a/10AVZ

[6] 

《In-Memory Analytics with Apache Arrow》: https://book.douban.com/subject/35954154/

[7] 

这里: https://arrow.apache.org/docs/format/Glossary.html#term-table

[8] 

这里: https://github.com/bigwhite/experiments/blob/master/arrow/advanced-datastructure

[9] 

Apache Arrow Glossary: https://arrow.apache.org/docs/format/Glossary.html

[10] 

“Gopher部落”知识星球: https://wx.zsxq.com/dweb2/index/group/51284458844544

[11] 

链接地址: https://m.do.co/c/bff6eed92687

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/736406.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[SWPUCTF 2021 新生赛]jicao

点进去后是一段php代码 <?php highlight_file(index.php); include("flag.php"); $id$_POST[id]; $jsonjson_decode($_GET[json],true); if ($id"wllmNB"&&$json[x]"wllm") {echo $flag;} ?> 包含了flag.php文件&#xff0c;设定…

数据结构关键路径问题:下面是一个有10个活动的AOE图,时间余量最大的活动是()

关键路径问题 名人说&#xff1a;莫听穿林打叶声&#xff0c;何妨吟啸且徐行。—— 苏轼《定风波莫听穿林打叶声》 本篇笔记整理&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 关键路径问题〇、概念说明1、AOE网2、关键路…

4-软件错误(BUG)

目录 1.什么是bug? 2.如何描述一个bug? ①发现问题的版本 ②问题出现的环境 ③错误重现的步骤 ④预期行为的描述 ⑤错误行为的描述 ⑥其他 ⑦不要把多个bug放到一起 PS&#xff1a;案例1 PS&#xff1a;案例2 3.如何定义bug的级别&#xff1f; ①Blocker&#x…

FFmpeg5.0源码阅读—— avcodec_send_packetavcodec_receive_frame

摘要&#xff1a;本文主要描述了FFmpeg中用于解码的接口的具体调用流程&#xff0c;详细描述了该接口被调用时所作的具体工作。   关键字&#xff1a;ffmpeg、avcodec_send_packet、avcodec_receive_frame   读者须知&#xff1a;读者需要了解FFmpeg的基本使用流程&#xf…

CUDA C编程及GPU基本知识【二】

文章目录 1、CPU和GPU的架构2、CPUs: 延迟导向设计和GPUs: 吞吐导向设计2.1 CPUs: 延迟导向设计2.2 GPUs: 吞吐导向设计2.3 GPU&CPU特点2.4 GPU编程&#xff1a;什么样的问题适合GPU 3、GPU编程与CUDA3.1 CUDA编程并行计算整体流程3.2 CUDA编程术语3.2.1 硬件3.2.2 内存模型…

Hive分桶

分桶的概述 为什么要分桶 数据分区可能导致有些分区数据过多&#xff0c;有些分区数据极少。分桶是将数据集分解为若干部分(数据文件)的另一种技术。分区和分桶其实都是对数据更细粒度的管理。当单个分区或者表中的数据越来越大&#xff0c;分区不能细粒度的划分数据时&#x…

阐述说明NLP发展历史,以及 NLP与chatgpt的关系

自然语言处理&#xff08;Natural Language Processing&#xff0c;NLP&#xff09;是人工智能&#xff08;AI&#xff09;领域的一个重要分支&#xff0c;关注计算机与人类&#xff08;自然&#xff09;语言之间的交互。NLP的目标是使计算机能够理解、生成和解释自然语言&…

心法利器[89] | 实用文本生成中的解码方法

心法利器 本栏目主要和大家一起讨论近期自己学习的心得和体会&#xff0c;与大家一起成长。具体介绍&#xff1a;仓颉专项&#xff1a;飞机大炮我都会&#xff0c;利器心法我还有。 2022年新一版的文章合集已经发布&#xff0c;累计已经60w字了&#xff0c;获取方式看这里&…

[CVPR‘23] PanoHead: Geometry-Aware 3D Full-Head Synthesis in 360 deg

论文&#xff5c;项目 总结&#xff1a; 任务&#xff1a;3D human head synthesis现有问题&#xff1a;GANs无法在「in-the-wild」「single-view」的图片情况下&#xff0c;生成360度人像解决方案&#xff1a;1&#xff09;提出了two-stage self-adaptive image alignment&am…

C++ 设计模式之策略模式

文章目录 一、简介二、场景三、举个栗子四、小结参考资料 一、简介 策略模式的定义很简单&#xff1a;即创建一系列的算法,把它们一个个封装起来 , 并且使它们可相互替换&#xff08;用扩展的方式来面对未来变化&#xff09;。在GoF一书中将其定位为一种“对象行为式模式”&…

vs code insiders 配置c语言

vs code insiders 配置c语言 1.下载插件 2.再配置代码 &#xff08;1&#xff09;launch.json {// Use IntelliSense to learn about possible attributes.// Hover to view descriptions of existing attributes.// For more information, visit: https://go.microsoft.com/…

操作系统的可扩展访问控制

访问控制是操作系统安全的基石&#xff0c;当前的操作系统已部署了很多访问控制的模型&#xff1a;Unix和Windows NT多用户安全&#xff1b;SELinux中的类型执行&#xff1b;反恶意软件产品&#xff1b;Apple OS X&#xff0c;Apple iOS和Google Android中的应用沙盒&#xff1…

RNN介绍

时间序列的表示 [seq_len, batch_size, vec ] seq_len表示一个句子通常有多少个单词或者一个序列有多少个时间段,batch_size表示同时多个样本,vec表示单词的编码长度 请问rnn和lstm中batchsize和timestep的区别是什么? - 知乎 (zhihu.com) import torch import torch.nn …

MYSQL05高级_查看修改存储引擎、InnoDB和MyISAM对比、其他存储引擎介绍

文章目录 ①. 查看、修改存储引擎②. InnoDB和MyISAM对比③. Archive引擎 - 归档④. Blackhole引擎丢数据⑤. CSV - 引擎⑥. Memory引擎 - 内存表⑦. Federated引擎 - 访问远程表⑧. Merge引擎 - 管理多个MyISAM⑨. NDB引擎 - 集群专用 ①. 查看、修改存储引擎 ①. 查看mysql提…

Spring Boot原理分析(一):项目启动(上)——@SpringBootApplication

文章目录 〇、准备工作一、SpringBootApplication.java源码解析1.源码2.自定义注解3.组合注解4.注解ComponentScan过滤器 5.注解SpringBootConfigurationConfiguration 6.注解EnableAutoConfiguration 本文章是Spring Boot源码解读与原理分析系列博客的第一篇&#xff0c;将会介…

Mac(M1Pro)下运行ChatGLM2

最近很多人都尝试在M1/M2芯片下跑chatglm/chatglm2&#xff0c;结果都不太理想&#xff0c;或者是说要32G内存才可以运行。本文使用cpu基于chatglm-cpp运行chatglm2的int4版本。开了多个网页及应用的情况下&#xff08;包括chatglm2)&#xff0c;总体内存占用9G左右。chatglm2可…

PYTHON+YOLOV5+OPENCV,实现数字仪表自动读数,并将读数结果进行输出显示和保存

最近完成了一个项目&#xff0c;利用pythonyolov5实现数字仪表的自动读数&#xff0c;并将读数结果进行输出和保存&#xff0c;现在完成的7788了&#xff0c;写个文档记录一下&#xff0c;若需要数据集和源代码可以私信。 最后实现的结果如下&#xff1a; 项目过程 首先查阅文…

从单体到SpringBoot/SpringCloud微服务架构无感升级的最佳实践

目录导读 从单体到SpringBoot/SpringCloud微服务架构无感升级的最佳实践1. 业务背景2. 当前问题3. 升级方案3.1 架构设计4. 详细设计4.1 迁移阻碍4.2 解决思路 5. 实现过程5.1 认证兼容改造5.2 抽象业务流程5.2.1 抽象业务的思路5.2.2 抽象业务的抽象编码5.2.3 抽象业务的具体实…

BFF网关模式开发指南

BFF是近些年新衍生出来的一种开发模式&#xff0c;或者说是一种适配模式的系统&#xff0c;BFF全称为Backend OF Front意为后端的前端&#xff0c;为了适配微服务模式下前端后端系统接口调用混乱而出现的。在如今微服务盛行的趋势下&#xff0c;大型系统中划分出了数十个服务模…

前端优化的一些方向

对于浏览器来说&#xff0c;加载网页的过程可以分为两部分&#xff0c;下载文档并响应&#xff08;5%左右&#xff09;&#xff0c;下载各种组件&#xff08;95%左右&#xff09;。 而对比大部分优秀网页来说下载文档&#xff08;10%~ 20%&#xff09;&#xff0c;下载组件&…