Share via


數據隱私權防火牆的幕後

注意

Power Platform 數據流目前無法使用隱私權等級,但產品小組正致力於啟用這項功能。

如果您已使用 Power Query 很長一段時間,您可能已體驗過它。 當您突然收到任何在線搜尋、查詢調整或鍵盤抨擊可以補救的錯誤時,您就會查詢。 錯誤,例如:

Formula.Firewall: Query 'Query1' (step 'Source') references other queries or steps, so it may not directly access a data source. Please rebuild this data combination.

或者:

Formula.Firewall: Query 'Query1' (step 'Source') is accessing data sources that have privacy levels which cannot be used together. Please rebuild this data combination.

這些 Formula.Firewall 錯誤是Power Query的數據隱私權防火牆(也稱為防火牆)的結果,有時可能只是為了挫敗世界各地的數據分析師。 不過,相信防火牆是重要的用途。 在本文中,我們將深入探討其運作方式。 有了更深入的瞭解,您有望在未來更妥善地診斷和修正防火牆錯誤。

這是什麼?

數據隱私權防火牆的用途很簡單:它的存在是為了防止 Power Query 在來源之間意外洩漏數據。

為何需要這個? 我的意思是,您當然可以撰寫一些 M,將 SQL 值傳遞至 OData 摘要。 但這將會是刻意的數據外洩。 混搭作者會(或至少應該)知道他們這樣做。 為什麼需要保護以防止意外的數據外洩?

答案? 摺疊。

摺疊?

折疊 是指將 M 中的運算式(例如篩選、重新命名、聯結等)轉換成原始數據源的作業(例如 SQL、OData 等等)。 Power Query 的強大功能來自於 PQ 可以透過使用者介面將使用者透過使用者介面執行的作業轉換成複雜的 SQL 或其他後端數據源語言,而不需要使用者知道上述語言。 使用者可取得原生數據源作業的效能優勢,並輕鬆地使用UI,讓所有數據源都可以使用一組通用命令來轉換。

在折疊時,PQ 有時可能會判斷執行指定混搭的最有效率方式是從一個來源擷取數據,並將其傳遞至另一個來源。 例如,如果您要將小型 CSV 檔案聯結至大型 SQL 數據表,您可能不希望 PQ 讀取 CSV 檔案、讀取整個 SQL 數據表,然後將它們聯結在本機電腦上。 您可能想要 PQ 將 CSV 資料內嵌到 SQL 語句中,並要求 SQL 資料庫執行聯結。

這是意外的數據外洩如何發生。

想像一下,如果您聯結包含員工社會安全號碼的 SQL 數據與外部 OData 摘要的結果,您突然發現 SQL 中的社會安全號碼已傳送至 OData 服務。 壞消息, 對吧?

這是防火牆要防止的案例類型。

如何運作?

防火牆存在以防止某個來源的數據意外傳送至另一個來源。 很簡單。

那麼,它如何完成這項任務?

其方式是將您的 M 查詢分成稱為分割區的內容,然後強制執行下列規則:

  • 分割區可以存取相容的數據源,或參考其他分割區,但不能同時參考兩者。

簡單。。。然而令人困惑。 什麼是分割區? 是什麼讓兩個數據源「相容」? 為什麼防火牆應該關心分割區是否想要存取數據源並參考數據分割?

讓我們一次細分一個規則並查看上述規則。

什麼是分割區?

在最基本的層級,分割區只是一或多個查詢步驟的集合。 最細微的數據分割可能(至少在目前的實作中)是單一步驟。 最大的分割區有時可以包含多個查詢。 (稍後再進一步瞭解這一點。

如果您不熟悉步驟,您可以在選取查詢之後,於 [套用的步驟] 窗格中,於 [Power Query 編輯器] 視窗右側檢視它們。 步驟會追蹤您所做的一切,以將數據轉換成其最終形狀。

參考其他數據分割的分割區

使用防火牆評估查詢時,防火牆會將查詢及其所有相依性分割成分割區(也就是步驟群組)。 每當某個分割區參考另一個分割區中的某個專案時,防火牆會以呼叫稱為 Value.Firewall的特殊函式來取代參考。 換句話說,防火牆不允許分割區直接存取彼此。 所有參考都會修改為通過防火牆。 將防火牆視為守門員。 參考另一個數據分割的分割區必須取得防火牆的許可權,防火牆會控制是否允許參考的數據進入分割區。

這一切看起來都相當抽象,因此讓我們看看一個範例。

假設您有一個稱為 Employees 的查詢,它會從 SQL 資料庫提取一些數據。 假設您也有另一個查詢 (EmployeesReference),其只會參考 Employees。

shared Employees = let
    Source = Sql.Database(…),
    EmployeesTable = …
in
    EmployeesTable;

shared EmployeesReference = let
    Source = Employees
in
    Source;

這些查詢最終會分成兩個分割區:一個用於 Employees 查詢,另一個用於 EmployeesReference 查詢(這會參考 Employees 數據分割)。 使用防火牆評估時,這些查詢會重新撰寫如下:

shared Employees = let
    Source = Sql.Database(…),
    EmployeesTable = …
in
    EmployeesTable;

shared EmployeesReference = let
    Source = Value.Firewall("Section1/Employees")
in
    Source;

請注意,Employees 查詢的簡單參考已由呼叫 Value.Firewall取代,其提供 Employees 查詢的完整名稱。

評估 EmployeesReference 時,防火牆會攔截對 Value.Firewall("Section1/Employees") 的呼叫,現在有機會控制要求的數據是否會流入 EmployeesReference 數據分割。 它可以執行任意數目的事情:拒絕要求、緩衝要求的數據(這可防止任何進一步折疊至其原始數據源),等等。

這是防火牆如何維持對分割區之間數據流的控制。

直接存取數據源的數據分割

假設您使用一個步驟來定義查詢 Query1(請注意,此單一步驟查詢對應至一個防火牆分割區),而這個單一步驟會存取兩個數據源:SQL 資料庫數據表和 CSV 檔案。 防火牆如何處理此動作,因為沒有數據分割參考,因此不會呼叫 Value.Firewall 它來攔截? 讓我們檢閱稍早所述的規則:

  • 分割區可以存取相容的數據源,或參考其他分割區,但不能同時參考兩者。

為了讓允許執行單一數據分割但兩個數據源查詢,其兩個數據源必須「相容」。 換句話說,數據必須雙向共用。 這表示這兩個來源的隱私權層級都必須是公用,或兩者都是組織,因為這些是只允許雙向共用的兩種組合。 如果這兩個來源都標示為私人,或一個標示為公用,另一個標示為[組織],或是使用某些其他隱私權層級組合來標示,則不允許雙向共用,因此無法安全地在相同的分割區中評估兩者。 這樣做表示可能會發生不安全的數據外泄(因為折疊),防火牆將無法防止它。

如果您嘗試存取相同分割區中的不相容數據源,會發生什麼事?

Formula.Firewall: Query 'Query1' (step 'Source') is accessing data sources that have privacy levels which cannot be used together. Please rebuild this data combination.

希望您現在能進一步瞭解本文開頭所列的其中一個錯誤訊息。

請注意,此 相容性 需求僅適用於指定的分割區。 如果分割區參考其他分割區,則來自參考數據分割的數據源不一定彼此相容。 這是因為防火牆可以緩衝處理數據,這可防止對原始數據源進一步折疊。 數據會載入記憶體,並視為來自無處。

為什麼不是兩者?

假設您使用一個步驟來定義查詢(這再次對應至一個數據分割),以存取另外兩個查詢(也就是另外兩個分割區)。 如果您想要在同一個步驟中直接存取 SQL 資料庫,該怎麼辦? 為什麼分割區無法參考其他分割區,並直接存取相容的數據源?

如您先前所見,當某個分割區參考另一個分割區時,防火牆會做為流入數據分割之所有數據的網關守衛。 若要這樣做,它必須能夠控制允許的數據。 如果分割區內有數據源正在存取,而且從其他分割區流入的數據,則會失去其成為網關守衛的能力,因為流入的數據可能會外泄至其中一個內部存取的數據源,而不知道該數據源。 因此,防火牆可防止存取其他數據分割的分割區無法直接存取任何數據源。

那麼,如果分割區嘗試參考其他分割區,也直接存取數據源,會發生什麼事?

Formula.Firewall: Query 'Query1' (step 'Source') references other queries or steps, so it may not directly access a data source. Please rebuild this data combination.

現在,您希望進一步瞭解本文開頭所列的其他錯誤訊息。

深入分割區

您可能會從上述資訊中猜測,如何分割查詢最終變得非常重要。 如果您有一些參考其他查詢的步驟,以及存取數據源的其他步驟,您現在希望能夠辨識在某些地方繪製分割區界限會造成防火牆錯誤,而在其他位置繪製它們時,可讓查詢正常執行。

那麼,查詢如何進行分割?

本節對於瞭解您看到防火牆錯誤的原因,以及瞭解如何解決防火牆錯誤(可能的話)而言,可能是最重要的一節。

以下是數據分割邏輯的高階摘要。

  • 初始數據分割
    • 為每個查詢中的每個步驟建立數據分割
  • 靜態階段
    • 此階段不相依於評估結果。 相反地,它會依賴查詢的結構。
      • 參數修剪
        • 修剪參數-esque 分割區,也就是下列任一數據分割:
          • 不會參考任何其他數據分割
          • 不包含任何函式調用
          • 不是週期性 (也就是說, 它不指自己)
        • 請注意,「移除」分割區實際上包含在任何其他數據分割中參考它。
        • 修剪參數分割可讓數據源函數調用中使用的參數參考運作 Web.Contents(myUrl),而不是擲回「數據分割無法參考數據源和其他步驟」錯誤。
      • 群組 (靜態)
        • 數據分割會以上層相依性順序合併。 在產生的合併分割區中,下列專案將會是分開的:
          • 不同查詢中的數據分割
          • 未參考其他資料分割的資料分割(因此允許存取資料來源)
          • 參考其他資料分割的資料分割(因此禁止存取資料來源)
  • 動態階段
    • 此階段取決於評估結果,包括各種分割區所存取數據源的相關信息。
    • 修剪
      • 修剪符合下列所有需求的分割區:
        • 不會存取任何數據源
        • 不會參考任何存取數據源的數據分割
        • 不迴圈
    • 群組 (動態)
      • 現在已修剪不必要的分割區,請嘗試建立盡可能大的來源分割區。 這可藉由使用上述靜態群組階段中所述的相同規則合併分割區來完成。

這是什麼意思?

讓我們逐步解說一個範例,說明上述複雜邏輯的運作方式。

以下是範例案例。 這是文本檔 (Contacts) 與 SQL 資料庫 (Employees) 相當直接的合併,其中 SQL Server 是參數 (DbServer)。

三個查詢

以下是此範例中使用的三個查詢的 M 程序代碼。

shared DbServer = "montegoref6" meta [IsParameterQuery=true, Type="Text", IsParameterQueryRequired=true];
shared Contacts = let

    Source = Csv.Document(File.Contents("C:\contacts.txt"),[Delimiter="   ", Columns=15, Encoding=1252, QuoteStyle=QuoteStyle.None]),

    #"Promoted Headers" = Table.PromoteHeaders(Source, [PromoteAllScalars=true]),

    #"Changed Type" = Table.TransformColumnTypes(#"Promoted Headers",{{"ContactID", Int64.Type}, {"NameStyle", type logical}, {"Title", type text}, {"FirstName", type text}, {"MiddleName", type text}, {"LastName", type text}, {"Suffix", type text}, {"EmailAddress", type text}, {"EmailPromotion", Int64.Type}, {"Phone", type text}, {"PasswordHash", type text}, {"PasswordSalt", type text}, {"AdditionalContactInfo", type text}, {"rowguid", type text}, {"ModifiedDate", type datetime}})

in

    #"Changed Type";
shared Employees = let

    Source = Sql.Databases(DbServer),

    AdventureWorks = Source{[Name="AdventureWorks"]}[Data],

    HumanResources_Employee = AdventureWorks{[Schema="HumanResources",Item="Employee"]}[Data],

    #"Removed Columns" = Table.RemoveColumns(HumanResources_Employee,{"HumanResources.Employee(EmployeeID)", "HumanResources.Employee(ManagerID)", "HumanResources.EmployeeAddress", "HumanResources.EmployeeDepartmentHistory", "HumanResources.EmployeePayHistory", "HumanResources.JobCandidate", "Person.Contact", "Purchasing.PurchaseOrderHeader", "Sales.SalesPerson"}),

    #"Merged Queries" = Table.NestedJoin(#"Removed Columns",{"ContactID"},Contacts,{"ContactID"},"Contacts",JoinKind.LeftOuter),

    #"Expanded Contacts" = Table.ExpandTableColumn(#"Merged Queries", "Contacts", {"EmailAddress"}, {"EmailAddress"})

in

    #"Expanded Contacts";

以下是較高層級的檢視,其中顯示相依性。

查詢相依性對話框。

讓我們分割

讓我們放大一下,並包含圖片中的步驟,並開始逐步執行數據分割邏輯。 以下是三個查詢的圖表,以綠色顯示初始防火牆分割區。 請注意,每個步驟都會在自己的分割區中啟動。

初始防火牆分割區。

接下來,我們會修剪參數分割區。 因此,DbServer 會隱含地包含在來源分割區中。

修剪的防火牆分割區。

現在我們會執行靜態群組。 這會在個別查詢中維護分割區之間的區隔(例如,員工的最後兩個步驟不會與聯繫人的步驟分組),以及在參考其他分割區的數據分割之間(例如員工的最後兩個步驟),以及那些沒有 (例如員工的前三個步驟) 的數據分割之間。

張貼靜態群組防火牆分割區。

現在,我們進入動態階段。 在此階段中,會評估上述靜態分割區。 不會存取任何數據源的數據分割會修剪。 然後,分割區會分組,以建立盡可能大的源數據分割。 不過,在此範例案例中,所有剩餘的數據分割都會存取數據源,而且沒有任何進一步的群組可以完成。 因此,在此階段,範例中的分割區不會變更。

讓我們假裝

不過,為了圖解,讓我們看看如果聯繫人查詢不是來自文本檔,而是硬式編碼在 M 中(也許透過 [輸入數據 ] 對話框)。

在此情況下,聯繫人查詢不會存取任何數據源。 因此,它會在動態階段的第一個部分進行修剪。

動態階段修剪之後的防火牆分割區。

拿掉 [聯繫人] 數據分割后,[員工] 的最後兩個步驟將不再參考任何數據分割,但包含 [員工] 前三個步驟的分割區除外。 因此,這兩個分割區會分組。

產生的分割區看起來會像這樣。

最後的防火牆分割區。

範例:將數據從某個數據源傳遞至另一個數據源

好吧,足夠的抽象解釋。 讓我們看看您可能會遇到防火牆錯誤的常見案例,以及解決其步驟。

假設您想要從 Northwind OData 服務查閱公司名稱,然後使用公司名稱來執行 Bing 搜尋。

首先,您會建立 公司 查詢來擷取公司名稱。

let
    Source = OData.Feed("https://services.odata.org/V4/Northwind/Northwind.svc/", null, [Implementation="2.0"]),
    Customers_table = Source{[Name="Customers",Signature="table"]}[Data],
    CHOPS = Customers_table{[CustomerID="CHOPS"]}[CompanyName]
in
    CHOPS

接下來,您會建立參考 Company 的搜尋查詢,並將它傳遞至 Bing。

let
    Source = Text.FromBinary(Web.Contents("https://www.bing.com/search?q=" & Company))
in
    Source

此時,您遇到麻煩。 評估 搜尋 會產生防火牆錯誤。

Formula.Firewall: Query 'Search' (step 'Source') references other queries or steps, so it may not directly access a data source. Please rebuild this data combination.

這是因為搜尋[來源] 步驟會參考數據源 (bing.com),同時也參考另一個查詢/分割區 (Company)。 它違反上述規則(「分割區可能存取相容的數據源,或參考其他分割區,但不能同時參考」)。

怎麼辦? 其中一個選項是完全停用防火牆(透過標示 為忽略隱私權等級並可能改善效能的隱私權選項)。 但是,如果您想要讓防火牆保持啟用,該怎麼辦?

若要在不停用防火牆的情況下解決錯誤,您可以將公司與搜尋合併成單一查詢,如下所示:

let
    Source = OData.Feed("https://services.odata.org/V4/Northwind/Northwind.svc/", null, [Implementation="2.0"]),
    Customers_table = Source{[Name="Customers",Signature="table"]}[Data],
    CHOPS = Customers_table{[CustomerID="CHOPS"]}[CompanyName],
    Search = Text.FromBinary(Web.Contents("https://www.bing.com/search?q=" & CHOPS))
in
    Search

所有項目現在都發生在單一數據分割內。 假設這兩個數據源的隱私權層級相容,防火牆現在應該會很高興,而且您不會再收到錯誤。

這是包裝

雖然在本主題上可以說得更多,但這個簡介文章已經足夠長了。 希望您可以進一步瞭解防火牆,並協助您在未來遇到防火牆錯誤時瞭解並修正防火牆錯誤。