簡介#
Apache Arrow 的誕生源於對表格資料表示法和系統間交換的一組標準的需求。採用這些標準降低了資料序列化/反序列化的計算成本,以及跨不同程式語言實作的系統的實作成本。
Apache Arrow 規範可以用任何程式語言實作,但許多語言都有官方實作。實作包括使用該語言提供的結構和常見的記憶體內資料處理演算法(例如,切片和串連)的格式定義。使用者可以擴充並使用 Apache Arrow 實作在其選擇的程式語言中提供的工具。一些實作更先進,並具有用於記憶體內分析資料處理的大量演算法。關於實作差異的更多詳細資訊可以在狀態頁面上找到。
除了最初的願景外,Arrow 也發展成為一個多語言程式庫集合,用於解決與記憶體內分析資料處理相關的問題。這涵蓋了以下主題:
零複製共享記憶體和基於 RPC 的資料移動
讀取和寫入檔案格式(如 CSV、Apache ORC 和 Apache Parquet)
記憶體內分析和查詢處理
Arrow 欄狀格式#
Apache Arrow 專注於表格資料。舉例來說,假設我們有可以組織成表格的資料
表格資料結構的圖表。#
表格資料可以在記憶體中使用基於列的格式或基於行的格式表示。基於行的格式逐行儲存資料,這意味著行在電腦記憶體中是相鄰的
表格資料以逐行方式儲存在記憶體中。#
在欄狀格式中,資料改為逐欄組織。這種組織使分析操作(如篩選、分組、彙總等)由於記憶體區域性而更有效率。在處理資料時,CPU 存取的記憶體位置往往彼此靠近。透過保持資料在記憶體中連續,它還可以實現計算的向量化。大多數現代 CPU 都有 SIMD 指令(一次對多個值運算的單一指令),可以使用單一 CPU 指令對向量資料實現平行處理和運算執行。
Apache Arrow 正在解決這個確切的問題。它是使用欄狀佈局的規範。
相同的表格資料以逐欄方式儲存在記憶體中。#
每一欄在 Arrow 術語中都稱為 陣列 (Array)。陣列可以是不同的資料類型,並且它們的值在記憶體中的儲存方式在資料類型之間有所不同。這些值在記憶體中排列方式的規範就是我們所稱的 實體記憶體佈局 (physical memory layout)。儲存陣列資料的一個連續記憶體區域稱為 緩衝區 (Buffer)。一個陣列由一個或多個緩衝區組成。
接下來的章節將簡要介紹 Arrow 欄狀格式,解釋不同的實體佈局。格式的完整規範可以在 Arrow 欄狀格式 中找到。
支援空值 (Null Values)#
Arrow 支援所有資料類型的遺失值或「空值」:陣列中的任何值在語義上都可能是空值,無論是基本類型還是巢狀資料類型。
在 Arrow 中,一個專用的緩衝區(稱為有效性(或「空值」)位元圖)與資料一起使用,指示陣列中的每個值是否為空值:值為 1 表示該值為非空值(「有效」),而值為 0 表示該值為空值。
此有效性位元圖是選用的:如果陣列中沒有遺失值,則不需要分配緩衝區(如下圖中的第 1 欄範例)。
基本佈局 (Primitive Layouts)#
固定大小基本佈局 (Fixed Size Primitive Layout)#
基本欄代表一個值陣列,其中每個值都具有相同的實體大小(以位元組為單位)。使用固定大小基本佈局的資料類型範例包括:帶號和無號整數資料類型、浮點數、布林值、十進位和時間資料類型。
基本資料類型的實體佈局圖。#
注意
Arrow 也有空值資料類型的概念,其中所有值都是空值。在這種情況下,不會分配任何緩衝區。
可變長度二進位和字串 (Variable length binary and string)#
與固定大小基本佈局相反,可變長度佈局允許表示一個陣列,其中每個元素可以具有可變的位元組大小。此佈局用於二進位和字串資料。
二進位或字串欄中所有元素的位元組都連續地儲存在單個緩衝區或記憶體區域中。為了知道欄中每個元素的開始和結束位置,實體佈局還包括整數偏移量。偏移量緩衝區始終比陣列長一個元素。最後兩個偏移量定義了最後一個二進位/字串元素的開始和結束位置。
二進位和字串資料類型共享相同的實體佈局。它們之間唯一的區別在於,字串類型陣列被假定為包含有效的 UTF-8 字串資料。
二進位/字串與大型二進位/字串之間的區別在於偏移量資料類型。在第一種情況下,它是 int32,在第二種情況下,它是 int64。
使用 32 位元偏移量的資料類型的限制是它們每個陣列的最大大小為 2GB。仍然可以使用非大型變體來處理更大的資料,但那時需要多個區塊。
可變長度字串資料類型的實體佈局圖。#
可變長度二進位和字串視圖 (Variable length binary and string view)#
此佈局是可變長度二進位佈局的替代方案,並改編自慕尼黑工業大學 (TU Munich) 的 UmbraDB,並且類似於 DuckDB 和 Velox 中使用的字串佈局(有時也稱為「German strings」)。
與傳統二進位和字串佈局的主要區別在於視圖緩衝區。它包括字串的長度,然後是內嵌顯示的字元(對於小字串)或僅字串的前 4 個位元組以及到可能多個資料緩衝區之一的偏移量。由於它使用偏移量和長度來引用資料緩衝區,因此所有元素的位元組不需要連續地儲存在單個緩衝區中。這使得能夠對陣列中的可變長度元素進行亂序寫入。
這些屬性對於高效的字串處理非常重要。前綴啟用了字串比較的有利快速路徑,字串比較通常在前四個位元組內確定。選擇元素是對固定寬度視圖緩衝區的簡單「收集」操作,不需要重寫值緩衝區。
可變長度字串視圖資料類型的實體佈局圖。#
巢狀佈局 (Nested Layouts)#
巢狀資料類型引入了父陣列和子陣列的概念。它們表達巢狀資料類型結構中實體值陣列之間的關係。
巢狀資料類型取決於一個或多個其他子資料類型。例如,List 是一種巢狀資料類型(父類型),它有一個子類型(列表中值的資料類型)。
List#
list 資料類型可以表示一個陣列,其中每個元素都是相同資料類型元素的序列。佈局類似於可變大小的二進位或字串佈局,因為它有一個偏移量緩衝區來定義每個元素的數值序列的開始和結束位置,所有值都連續儲存在值子陣列中。
list 資料類型中的偏移量是 int32,而 large list 中的偏移量是 int64。
可變大小 list 資料類型的實體佈局圖。#
固定大小 List (Fixed Size List)#
固定大小 list 是可變大小 list 的一種特殊情況,其中每個欄位插槽都包含固定大小的序列,這意味著所有 list 的大小都相同,因此不再需要偏移量緩衝區。
固定大小 list 資料類型的實體佈局圖。#
List View#
與 list 類型相反,list view 類型除了偏移量緩衝區外,還有大小緩衝區。偏移量繼續指示每個元素的開始位置,但大小現在儲存在單獨的大小緩衝區中。這允許亂序偏移量,因為大小不再從連續偏移量中衍生而來。
可變大小 list view 資料類型的實體佈局圖。#
Struct#
struct 是一種巢狀資料類型,由欄位的有序序列(資料類型和名稱)參數化。
每個欄位都有一個子陣列
子陣列是獨立的,不需要在記憶體中彼此相鄰。它們只需要具有相同的長度。
可以將個別的 struct 欄位視為鍵值對,其中鍵是欄位名稱,子陣列是其值。欄位(鍵)儲存在結構描述中,特定欄位(鍵)的值儲存在子陣列中。
struct 資料類型的實體佈局圖。#
Map#
Map 資料類型表示巢狀資料,其中每個值都是可變數量的鍵值對。它的實體表示法與 {key, value}
struct 的 list 相同。
struct 和 map 資料類型之間的區別在於,struct 將鍵保存在結構描述中,要求鍵為字串,而值儲存在子陣列中,每個欄位一個子陣列。可以有多個鍵,因此有多個子陣列。另一方面,map 有一個子陣列,其中包含所有不同的鍵(因此所有鍵都需要是相同的資料類型,但不一定是字串),以及第二個子陣列,其中包含所有值。值需要是相同的資料類型;但是,資料類型不必與鍵的資料類型相符。
此外,map 將 struct 儲存在 list 中,並且由於 list 是可變形狀,因此需要偏移量。
map 資料類型的實體佈局圖。#
Union#
union 是一種巢狀資料類型,其中 union 中的每個插槽都具有從可能的 Arrow 資料類型子集中選擇的資料類型的值。這表示 union 陣列代表混合類型陣列。與其他資料類型不同,union 沒有自己的有效性位元圖,空值由子陣列決定。
Arrow 定義了兩種不同的 union 資料類型:「dense」和「sparse」。
Dense Union#
Dense Union 為混合類型陣列中存在的每種資料類型都有一個子陣列,並且有兩個自己的緩衝區
類型緩衝區: 保存陣列每個插槽的資料類型 ID。資料類型 ID 通常是子陣列的索引;但是,資料類型 ID 和子索引之間的關係是資料類型的參數。
偏移量緩衝區: 保存每個陣列插槽相對於各自子陣列的偏移量。
dense union 資料類型的實體佈局圖。#
Sparse union#
sparse union 的結構與 dense union 相同,只是省略了偏移量緩衝區。在這種情況下,子陣列的長度都等於 union 的長度。
sparse union 資料類型的實體佈局圖。#
字典編碼佈局 (Dictionary Encoded Layout)#
當資料具有許多重複值時,字典編碼可能很有效。這些值由引用字典的整數表示,字典通常由唯一值組成。
字典資料類型的實體佈局圖。#
行程長度編碼佈局 (Run-End Encoded Layout)#
行程長度編碼非常適合表示包含相同值序列的資料。這些序列稱為行程。行程長度編碼陣列沒有自己的緩衝區,但有兩個子陣列
行程結束陣列: 保存每個行程結束時在陣列中的索引。行程結束的數量與其父陣列的長度相同。
值陣列: 沒有重複的實際值(以及空值)。
請注意,父陣列的空值嚴格地在值陣列中表示。
行程長度編碼資料類型的實體佈局圖。#
另請參閱
所有 Arrow 資料類型 的表格。
Arrow 術語概述 (Overview of Arrow Terminology)#
實體佈局 一種用於表示記憶體中陣列值的規範。
緩衝區 一個連續的記憶體區域,具有給定的位元組長度。緩衝區用於儲存陣列的資料。有時我們使用緩衝區中元素數量的概念,只有在我們知道封裝此特定緩衝區的陣列的資料類型時才能使用。
陣列 一個連續的、一維的值序列,具有已知的長度,其中所有值都具有相同的資料類型。一個陣列由零個或多個緩衝區組成。
區塊陣列 (Chunked Array) 一個不連續的、一維的值序列,具有已知的長度,其中所有值都具有相同的資料類型。由零個或多個陣列(「區塊」)組成。
注意
區塊陣列是 Arrow C++ 和 PyArrow 等特定實作的概念。
記錄批次 (RecordBatch) 一個連續的、二維的資料結構,由相同長度的陣列的有序集合組成。
結構描述 (Schema) 欄位的有序集合,用於傳達物件(如記錄批次或表格)的所有資料類型。結構描述可以包含選用的鍵/值中繼資料。
欄位 (Field) 欄位包括欄位名稱、資料類型、空值性標誌和記錄批次中特定欄的選用鍵值中繼資料。
表格 (Table) 一個不連續的、二維的資料區塊,由區塊陣列的有序集合組成。所有區塊陣列都具有相同的長度,但可能具有不同的類型。不同的欄可能會以不同的方式分區塊。
注意
表格是 Arrow C++ 和 PyArrow 等特定實作的概念。例如,在 Java 實作中,表格不是區塊陣列的集合,而是記錄批次的集合。
另請參閱
如需更多術語,請參閱詞彙表。
擴充類型 (Extension Types)#
如果系統或應用程式需要使用自訂語義擴充標準 Arrow 資料類型,則可以透過定義擴充類型來實現。
擴充類型可以透過使用自訂類型名稱和選用的序列化表示法(Field 中繼資料結構中的 'ARROW:extension:name'
和 'ARROW:extension:metadata'
鍵)註釋任何內建 Arrow 資料類型(「儲存類型」)來定義。
另請參閱
請參閱擴充類型 文件。
標準擴充類型 (Canonical Extension Types)#
共享眾所周知的擴充類型的定義是有益的,以提高整合 Arrow 欄狀資料的不同系統之間的互通性。因此,標準擴充類型在 Arrow 本身中定義。
另請參閱
請參閱標準擴充類型 文件。
社群擴充類型 (Community Extension Types)#
這些是 Arrow 擴充類型,已在特定領域內確立為標準。
範例
GeoArrow:用於表示向量幾何圖形的 Arrow 擴充類型集合