Import

Azure SQL 倉庫 - 數據攝取 - 將巨大的固定寬度(帶逗號)文件轉換為分隔文件

  • December 29, 2016

我什至不確定我是否正確地提出了這個問題,但我會嘗試 - 我有一堆從 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 功能強大,但並不那麼複雜,因此無法處理這種奇怪的格式。在我看來,您有三個選擇:

  1. 更正源文件格式。不要使用固定寬度和分隔文件格式的奇怪組合,而是使用標准文件格式,例如 .csv。這種格式的列分隔符是輸入符或逗號,我認為這真的很奇怪。有什麼工具可以輕鬆閱讀嗎?這是您工作的常見格式嗎?
  2. 將指定其中一個分隔符的文件導入一行,然後根據另一個分隔符將其分解。我開始用你的樣本數據嘗試這個,但沒有走得很遠。不同的行真的有不同的列數嗎?在您的範例數據中,第 1 行有 24 列,第 2 行有 17 列。請提供一個小樣本文件,例如通過gist準確表示您的數據。
  3. 編寫一個高度定制的導入常式。使用標準數據交換格式(如 csv、製表符分隔、管道分隔、XML、JSON 等)的要點是,您不必在每次要導入某些數據時都編寫高度自定義的常式。但是,如果您無法從源頭更改文件或分階段導入文件,這可能是一種選擇。我最近一直在使用 Azure Data Lake Analytics (ADLA) 和 U-SQL,這也許可以做到這一點。

請嘗試回答我上面的問題並提供範例文件,我會盡力提供幫助。

根據十六進制編輯器,您的範例文件具有用於某些行結尾的單換行符 (0A) 和兩個換行符作為行之間的分隔符:

範例文件的十六進制視圖

U-SQL 自定義提取器可能能夠處理此文件,但我想知道我們是否會遇到完整的 30GB 文件的問題。

指示

  1. 如果您還沒有Azure Data Lake Analytics (ADLA) 帳戶,請設置一個。
  2. 在 Visual Studio 中創建一個新的 U-SQL 項目 - 您將需要ADLA 工具
  3. 添加 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;

           }
       }
   }
}
}
  1. 使用自定義提取器處理文件:
@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 導入它:

多基結果

祝你好運!

引用自:https://dba.stackexchange.com/questions/158883