從 Avro 檔案取得架構
一、簡介
在本教程中,我們將探討如何從 Java 中的 Apache Avro 檔案中提取架構。此外,我們還將介紹如何從 Avro 檔案讀取資料。這是大數據處理系統的常見要求。
Apache Avro 是一個資料序列化框架,提供緊湊、快速的二進位資料格式。因此,它在大數據生態系統中很受歡迎,尤其是 Apache Hadoop。因此,了解如何使用 Avro 檔案對於涉及資料處理的任務至關重要。
2.Maven依賴
為了讓 Avro 在 Java 中啟動並運行,我們需要將Avro 核心庫新增至我們的 Maven 專案:
<dependency>
<groupId>org.apache.avro</groupId>
<artifactId>avro</artifactId>
<version>1.12.0</version>
</dependency>
出於測試目的,我們將使用 JUnit Jupiter。如果我們使用 Spring Boot Starter Test 依賴項,則不必新增 JUnit 相依性。該模組自動帶來它。附帶說明一下,模組還帶來了 Mockito 框架。
對於 JUnit,我們使用最新的可用版本:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.2</version>
<scope>test</scope>
</dependency>
每當我們開始一個新專案時,最好確保我們使用各個依賴項的最新穩定版本。
3. 理解並提取Avro Schema
在深入研究提取模式的程式碼之前,讓我們先簡單回顧一下 Avro 檔案的結構:
- 文件頭 –包含有關文件的元數據,包括架構。
- 資料塊-實際的序列化資料。
- 檔案頁尾 –包含附加元資料和同步標記。
Avro 檔案的架構描述了其中資料的結構。此外,資料以 JSON 格式存儲,包括有關欄位、欄位名稱和資料類型的資訊。
現在,讓我們編寫一個方法來從 Avro 檔案中提取架構:
public static Schema extractSchema(String avroFilePath) throws IOException {
File avroFile = new File(avroFilePath);
DatumReader<GenericRecord> datumReader = new GenericDatumReader<>();
try (DataFileReader<GenericRecord> dataFileReader = new DataFileReader<>(avroFile, datumReader)) {
return dataFileReader.getSchema();
}
}
首先,我們建立一個代表 Avro 檔案的File
物件。接下來,我們實例化一個GenericDatumReader.
在不指定模式的情況下實例化此類允許它讀取任何 Avro 檔案。
接下來,我們使用 Avro 檔案和GenericDatumReader
作為參數來建立一個DataFileReader
。
我們使用DataFileReader
的getSchema()
方法來擷取模式。 DataFileReader
包裝在 try-with-resources 區塊中,以確保正確的資源管理。
這種方法允許我們提取模式,而無需事先知道其結構。這樣,它就成為處理各種 Avro 檔案的通用選項。
4.從Avro檔案讀取數據
一旦我們獲得了 schema,我們就可以從 Avro 檔案中讀取資料。
我們來寫一個讀取方法:
public static List<GenericRecord> readAvroData(String avroFilePath) throws IOException {
File avroFile = new File(avroFilePath);
DatumReader<GenericRecord> datumReader = new GenericDatumReader<>();
List<GenericRecord> records = new ArrayList<>();
try (DataFileReader<GenericRecord> dataFileReader = new DataFileReader<>(avroFile, datumReader)) {
GenericRecord record = null;
while (dataFileReader.hasNext()) {
record = dataFileReader.next(record);
records.add(record);
}
}
return records;
}
首先,我們從 avroFilePath 建立一個File
avroFilePath.
接下來,我們建立一個GenericDatumReader
對象,用於讀取 Avro 資料。透過在不指定架構的情況下創建它,它可以在不事先知道架構的情況下讀取任何 Avro 檔案。
然後,我們建立一個DataFileReader
,這是我們用來從 Avro 檔案中提取資訊的主要工具。最後,我們使用hasNext()
和next()
方法迭代文件,並將記錄新增到列表中。
此外,值得注意的是,我們在next()
方法呼叫中重複使用了GenericRecord
物件。這是一項有助於減少物件創建和垃圾收集開銷的最佳化。
5. 測試
為了確保我們的程式碼正常運作,讓我們編寫一些單元測試。首先我們建立一個tempDir.
使用@TempDir
註釋 Junit 會自動建立一個臨時目錄以供測試使用。
因此,這對於在測試期間建立臨時檔案非常有用,而無需擔心清理。 JUnit 在測試運行之前創建它並在測試運行之後刪除它:
@TempDir
Path tempDir;
private File avroFile;
private Schema schema;
接下來,我們將在每次測試之前設定一些東西:
@BeforeEach
void setUp() throws IOException {
schema = new Schema.Parser().parse("""
{
"type": "record",
"name": "User",
"fields": [
{"name": "name", "type": "string"},
{"name": "age", "type": "int"}
]
}
""");
avroFile = tempDir.resolve("test.avro").toFile();
GenericRecord user1 = new GenericData.Record(schema);
user1.put("name", "John Doe");
user1.put("age", 30);
try (DataFileWriter<GenericRecord> dataFileWriter =
new DataFileWriter<>(new GenericDatumWriter<>(schema))) {
dataFileWriter.create(schema, avroFile);
dataFileWriter.append(user1);
}
}
最後,讓我們測試一下我們的功能:
@Test
void whenSchemaIsExistent_thenItIsExtractedCorrectly() throws IOException {
Schema extractedSchema = AvroSchemaExtractor.extractSchema(avroFile.getPath());
assertEquals(schema, extractedSchema);
}
@Test
void whenAvroFileHasContent_thenItIsReadCorrectly() throws IOException {
List<GenericRecord> records = AvroSchemaExtractor.readAvroData(avroFile.getPath());
assertEquals("John Doe", records.get(0).get(0).toString());
}
這些測試會建立一個包含範例架構和資料的臨時 Avro 檔案。然後,他們驗證我們的方法是否正確提取模式並讀取資料。
六、結論
在本文中,我們探討如何從 Avro 檔案中提取架構並使用 Java 讀取其資料。此外,我們也示範如何使用GenericDatumReader
和DataFileReader
來處理 Avro 文件,而無需事先了解架構。
此外,這些技術對於在各種 Java 應用程式(例如資料分析或大數據處理)中使用 Avro 至關重要。透過應用這些方法,我們可以靈活地管理 Avro 文件。
最後,我們應該記住在專案中正確處理異常並正確管理資源。這樣,我們將能夠以有效的方式處理序列化數據,特別是在以 Avro 為中心的生態系統中。
與往常一樣,程式碼可以在 GitHub 上取得。