Import
Azure SQL 倉庫 - 數據攝取 - 將巨大的固定寬度(帶逗號)文件轉換為分隔文件
我什至不確定我是否正確地提出了這個問題,但我會嘗試 - 我有一堆從 Linux 系統上的 Oracle 導出生成的巨大文本文件。每個文件大小約為 30 GB,我有大約 50 個。
目標是將此數據導出到 Azure SQL 數據倉庫。在這種情況下,考慮到數據的大小,BCP 不是正確的方法,所以我不得不使用 Polybase。
從 ASCII 轉換為 UTF8 編碼後,我在查詢外部表時遇到了問題。Polybase 不能很好地處理固定寬度的文本文件,每行都有換行符。
文本文件如下所示:
101,102,103,104,105,106,107 108,108,109,110,111,112,113 114,115,116,117,118,119,120 121,122,123 --這裡什麼都沒有,只有一個空行 201,202,203,204,205,206,207 208,209,210,211,212,213,214 215,216,217
Polybase 嘗試處理從 101 到 107 的錯誤,並抱怨此文件中沒有足夠的列來處理。
這是我認為正在發生的事情:固定寬度和換行符使其將換行符視為行分隔符。
如何將此文件轉換為如下所示:
101,102,103,104,105,106,107,108,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123{CR}{LF} 201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217{CR}{LF}
編輯:這是來自文件的範例數據。我在 Windows VM 上的 git bash 中打開它。
這些文件應該有 167 列
,
作為列分隔符。問題是,由於每一行產生多行,因此很難從 Polybase 外部表中處理它們。
Polybase 功能強大,但並不那麼複雜,因此無法處理這種奇怪的格式。在我看來,您有三個選擇:
- 更正源文件格式。不要使用固定寬度和分隔文件格式的奇怪組合,而是使用標准文件格式,例如 .csv。這種格式的列分隔符是輸入符或逗號,我認為這真的很奇怪。有什麼工具可以輕鬆閱讀嗎?這是您工作的常見格式嗎?
- 將指定其中一個分隔符的文件導入一行,然後根據另一個分隔符將其分解。我開始用你的樣本數據嘗試這個,但沒有走得很遠。不同的行真的有不同的列數嗎?在您的範例數據中,第 1 行有 24 列,第 2 行有 17 列。請提供一個小樣本文件,例如通過gist準確表示您的數據。
- 編寫一個高度定制的導入常式。使用標準數據交換格式(如 csv、製表符分隔、管道分隔、XML、JSON 等)的要點是,您不必在每次要導入某些數據時都編寫高度自定義的常式。但是,如果您無法從源頭更改文件或分階段導入文件,這可能是一種選擇。我最近一直在使用 Azure Data Lake Analytics (ADLA) 和 U-SQL,這也許可以做到這一點。
請嘗試回答我上面的問題並提供範例文件,我會盡力提供幫助。
根據十六進制編輯器,您的範例文件具有用於某些行結尾的單換行符 (0A) 和兩個換行符作為行之間的分隔符:
U-SQL 自定義提取器可能能夠處理此文件,但我想知道我們是否會遇到完整的 30GB 文件的問題。
指示
- 如果您還沒有Azure Data Lake Analytics (ADLA) 帳戶,請設置一個。
- 在 Visual Studio 中創建一個新的 U-SQL 項目 - 您將需要ADLA 工具。
- 添加 U-SQL 腳本並將以下文本添加到 U-SQL 程式碼隱藏文件中:
using System.Collections.Generic; using System.IO; using System.Text; using Microsoft.Analytics.Interfaces; namespace Utilities { [SqlUserDefinedExtractor(AtomicFileProcessing = true)] public class MyExtractor : IExtractor { //Contains the row private readonly Encoding _encoding; private readonly byte[] _row_delim; private readonly char _col_delim; public MyExtractor() { _encoding = Encoding.UTF8; _row_delim = _encoding.GetBytes("\n\n"); _col_delim = '|'; } public override IEnumerable<IRow> Extract(IUnstructuredReader input, IUpdatableRow output) { string s = string.Empty; string x = string.Empty; foreach (var current in input.Split(_row_delim)) { using (System.IO.StreamReader streamReader = new StreamReader(current, this._encoding)) { while ((s = streamReader.ReadLine()) != null) { //Strip any line feeds //s = s.Replace("/n", ""); // Concatenate the lines x += s; } //Create the output output.Set<string>(0, x); yield return output.AsReadOnly(); // Reset x = string.Empty; } } } } }
- 使用自定義提取器處理文件:
@input = EXTRACT col string FROM "/input/input42_2.txt" USING new Utilities.MyExtractor(); // Output the file OUTPUT @input TO "/output/output.txt" USING Outputters.Tsv(quoting : false);
這產生了一個清理文件,我可以使用 Polybase 導入它:
祝你好運!