Megosztás a következőn keresztül:


Az adatvédelmi tűzfal színfalak mögött

Feljegyzés

Az adatvédelmi szintek jelenleg nem érhetők el a Power Platform adatfolyamaiban, de a termékcsapat dolgozik a funkció engedélyezésén.

Ha bármilyen ideig használta a Power Queryt, valószínűleg tapasztalta azt. Itt van, lekérdezés el, amikor hirtelen kap egy hibát, hogy nincs mennyiségű online keresés, lekérdezés csípés, vagy a billentyűzet bashing lehet orvosolni. Egy hiba, például:

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.

Vagy talán:

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

Ezek a Formula.Firewall hibák a Power Query adatvédett tűzfalának (más néven tűzfalnak) az eredménye, amely időnként úgy tűnhet, hogy csak azért létezik, hogy meghiúsítsa az adatelemzőket a világon. Hiszi vagy sem, a tűzfal azonban fontos célt szolgál. Ebben a cikkben a motorháztető alá ásunk, hogy jobban megértsük, hogyan működik. A nagyobb megértéssel felvértezve remélhetőleg a jövőben jobban diagnosztizálhatja és kijavíthatja a tűzfalhibákat.

Mi ez?

Az adatvédelmi tűzfal célja egyszerű: létezik, hogy megakadályozza, hogy a Power Query véletlenül kiszivárogtasson adatokat a források között.

Miért van erre szükség? Úgy értem, akkor biztosan szerző néhány M, amely át egy SQL-értéket egy OData feed. De ez szándékos adatszivárgás lenne. A mashup szerző (vagy legalábbis kellene) tudni, hogy csinálták ezt. Miért van szükség a véletlen adatszivárgás elleni védelemre?

A válasz? Összecsukható.

Összecsukható?

A hajtogatás egy olyan kifejezés, amely az M-ben lévő kifejezések (például szűrők, átnevezések, illesztések stb.) nyers adatforráson (például SQL, OData stb.) végzett műveletekké alakítására vonatkozik. A Power Query teljesítményének nagy része abból fakad, hogy a PQ a felhasználói felületén keresztül összetett SQL- vagy más háttéradatforrás-nyelvekké alakítja át a felhasználó által végrehajtott műveleteket anélkül, hogy a felhasználónak ismernie kellene az említett nyelveket. A felhasználók a natív adatforrásműveletek teljesítménybeli előnyeit élvezhetik, és könnyen használhatják a felhasználói felületet, ahol az összes adatforrás átalakítható egy közös parancskészlettel.

Az összecsukás részeként a PQ néha azt is megállapíthatja, hogy egy adott összecsukás végrehajtásának leghatékonyabb módja az adatok egyik forrásból való átvétele és átadása egy másiknak. Ha például egy kis CSV-fájlt csatlakoztat egy hatalmas SQL-táblához, akkor valószínűleg nem szeretné, hogy a PQ beolvassa a CSV-fájlt, olvassa el a teljes SQL-táblát, majd csatlakoztassa őket a helyi számítógépen. Valószínűleg azt szeretné, hogy a PQ egy SQL-utasításba ágyazza be a CSV-adatokat, és kérje meg az SQL-adatbázist az illesztés végrehajtására.

Így fordulhat elő véletlen adatszivárgás.

Tegyük fel, hogy olyan SQL-adatokhoz csatlakozik, amelyek egy külső OData-hírcsatorna eredményeivel tartalmazzák az alkalmazottak társadalombiztosítási számát, és hirtelen rájött, hogy az SQL-ből származó társadalombiztosítási számok az OData szolgáltatásba lettek küldve. Rossz hír, igaz?

Ez az a fajta forgatókönyv, amelyet a tűzfalnak meg kell akadályoznia.

Hogyan működik?

A tűzfal azért létezik, hogy megakadályozza, hogy az egyik forrásból származó adatok véletlenül egy másik forrásnak legyenek elküldve. Elég egyszerű.

És hogyan hajtja végre ezt a küldetést?

Ezt úgy teszi, hogy az M-lekérdezéseket egy úgynevezett partícióra osztja, majd kényszeríti a következő szabályt:

  • A partíciók hozzáférhetnek a kompatibilis adatforrásokhoz, vagy hivatkozhatnak más partíciókra, de mindkettőre nem.

Egyszerű... még zavaró. Mi az a partíció? Mi teszi "kompatibilissé" két adatforrást? És miért kell a tűzfalnak gondoskodnia, ha egy partíció egy adatforráshoz szeretne hozzáférni, és hivatkozni szeretne egy partícióra?

Bontsuk le ezt, és nézzük meg a fenti szabályt egyenként.

Mi az a partíció?

A partíció a legalapvetőbb szintjén csak egy vagy több lekérdezési lépésből álló gyűjtemény. A lehető legrészletesebb partíció (legalábbis a jelenlegi implementációban) egyetlen lépés. A legnagyobb partíciók néha több lekérdezést is tartalmazhatnak. (Erről később olvashat bővebben.)

Ha nem ismeri a lépéseket, megtekintheti őket a Power Query-szerkesztő ablak jobb oldalán, miután kiválasztott egy lekérdezést, az Alkalmazott lépések panelen. A lépések nyomon követnek mindent, amit az adatok végleges formájává alakítása érdekében végzett.

Más partíciókra hivatkozó partíciók

Amikor egy lekérdezést kiértékel a tűzfal, a tűzfal partíciókra (azaz lépéscsoportokra) osztja a lekérdezést és annak összes függőségét. Ha egy partíció hivatkozik valamire egy másik partícióban, a tűzfal lecseréli a hivatkozást egy speciális, úgynevezett Value.Firewallfüggvény hívására. Más szóval a tűzfal nem teszi lehetővé, hogy a partíciók közvetlenül elérhessék egymást. Minden hivatkozás módosul a tűzfalon való áthaladás érdekében. Gondoljon úgy a tűzfalra, mint egy kapuőrre. Egy másik partícióra hivatkozó partíciónak rendelkeznie kell a tűzfal engedélyével, és a tűzfal szabályozza, hogy a hivatkozott adatok engedélyezve lesznek-e a partíción.

Ez az egész elég absztraktnak tűnhet, ezért nézzünk meg egy példát.

Tegyük fel, hogy van egy Alkalmazottak nevű lekérdezése, amely adatokat kér le egy SQL-adatbázisból. Tegyük fel, hogy van egy másik lekérdezése is (EmployeesReference), amely egyszerűen az Alkalmazottakra hivatkozik.

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

shared EmployeesReference = let
    Source = Employees
in
    Source;

Ezek a lekérdezések két partícióra lesznek felosztva: egy az Alkalmazottak lekérdezéshez, egy pedig az EmployeesReference lekérdezéshez (amely az Alkalmazottak partícióra hivatkozik). Amikor a tűzfal ki van értékelve, a rendszer az alábbihoz hasonlóan újraírja ezeket a lekérdezéseket:

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

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

Figyelje meg, hogy az Alkalmazottak lekérdezésre való egyszerű hivatkozást egy hívás Value.Firewallváltotta fel, amely az Alkalmazottak lekérdezés teljes nevét adja meg.

Az EmployeesReference kiértékelésekor a tűzfal elfogja a hívásokat Value.Firewall("Section1/Employees") , amely mostantól szabályozhatja, hogy a kért adatok befolynak-e (és hogyan) az EmployeesReference partícióba. Számos dolgot elvégezhet: megtagadhatja a kérést, pufferelheti a kért adatokat (ami megakadályozza az eredeti adatforrás további összecsukását), és így tovább.

A tűzfal így felügyeli a partíciók közötti adatfolyamokat.

Adatforrásokhoz közvetlenül hozzáférő partíciók

Tegyük fel, hogy egy lépéssel definiál egy lekérdezési lekérdezést1 (vegye figyelembe, hogy ez az egylépéses lekérdezés egy tűzfalpartíciónak felel meg), és hogy ez az egyetlen lépés két adatforráshoz fér hozzá: egy SQL-adatbázistáblához és egy CSV-fájlhoz. Hogyan kezeli ezt a tűzfal, mivel nincs partícióhivatkozás, és így nincs rá hívás Value.Firewall , hogy elfogja? Tekintsük át a korábban említett szabályt:

  • A partíciók hozzáférhetnek a kompatibilis adatforrásokhoz, vagy hivatkozhatnak más partíciókra, de mindkettőre nem.

Az egypartíciós, de két adatforrásból álló lekérdezés futtatásához a két adatforrásnak "kompatibilisnek" kell lennie. Más szóval nem szabad, hogy az adatok kétirányúan legyenek megosztva közöttük. Ez azt jelenti, hogy mindkét forrás adatvédelmi szintjének nyilvánosnak kell lennie, vagy mindkettőnek szervezetinek kell lennie, mivel ez az egyetlen két kombináció, amely lehetővé teszi a megosztást mindkét irányban. Ha mindkét forrás privátként van megjelölve, vagy az egyik nyilvános, a másik pedig szervezeti, vagy az adatvédelmi szintek valamilyen más kombinációjával van megjelölve, akkor a kétirányú megosztás nem engedélyezett, így nem biztonságos, hogy mindkettőt ugyanabban a partícióban értékelje ki. Ez azt jelentené, hogy nem biztonságos adatszivárgás fordulhat elő (összecsukás miatt), és a tűzfalnak nincs módja annak megelőzésére.

Mi történik, ha ugyanabban a partícióban próbál inkompatibilis adatforrásokat elérni?

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

Remélhetőleg most már jobban megértheti a cikk elején felsorolt hibaüzenetek egyikét.

Vegye figyelembe, hogy ez a kompatibilitási követelmény csak egy adott partíción belül érvényes. Ha egy partíció más partíciókra hivatkozik, a hivatkozott partíciók adatforrásainak nem kell kompatibilisnek lenniük egymással. Ennek az az oka, hogy a tűzfal pufferelheti az adatokat, ami megakadályozza az eredeti adatforrással való további összecsukást. Az adatok betöltve lesznek a memóriába, és úgy lesznek kezelve, mintha a semmiből származnak.

Miért ne csináld mindkettőt?

Tegyük fel, hogy egy olyan lekérdezést határoz meg egy lépéssel (amely ismét egy partíciónak felel meg), amely két másik lekérdezéshez (azaz két másik partícióhoz) fér hozzá. Mi a teendő, ha ugyanabban a lépésben közvetlenül is hozzá szeretne férni egy SQL-adatbázishoz? Miért nem hivatkozhat egy partíció más partíciókra, és miért nem fér hozzá közvetlenül a kompatibilis adatforrásokhoz?

Ahogy korábban láthatta, amikor az egyik partíció egy másik partícióra hivatkozik, a tűzfal a partícióba áramló összes adat kapuőreként működik. Ehhez képesnek kell lennie szabályozni, hogy milyen adatok legyenek engedélyezve. Ha a partíción belül vannak adatforrások, és más partíciókból származó adatok áramlanak be, elveszíti a kapuőri képességét, mivel a beáramló adatok kiszivároghatnak az egyik belsőleg elérhető adatforrásba anélkül, hogy tudnák róla. Így a tűzfal megakadályozza, hogy a más partíciókhoz hozzáférő partíciók közvetlenül hozzáférjenek az adatforrásokhoz.

Mi történik akkor, ha egy partíció más partíciókra próbál hivatkozni, és közvetlenül is hozzáfér az adatforrásokhoz?

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.

Most remélhetőleg jobban megérti a cikk elején felsorolt másik hibaüzenetet.

Partíciók részletes

Ahogy a fenti információkból is sejtheti, a lekérdezések particionálása rendkívül fontos lesz. Ha van néhány lépése, amely más lekérdezésekre hivatkozik, és más, adatforrásokhoz hozzáférő lépések, akkor remélhetőleg felismeri, hogy a partícióhatárok bizonyos helyeken történő megrajzolása tűzfalhibákat fog okozni, míg más helyeken való rajzolás lehetővé teszi a lekérdezés megfelelő futtatását.

Tehát pontosan hogyan történik a lekérdezések particionálása?

Ez a szakasz talán a legfontosabb annak megértéséhez, hogy miért jelenik meg a tűzfalhibák, és hogyan lehet megoldani őket (ahol lehetséges).

Íme a particionálási logika magas szintű összefoglalása.

  • Kezdeti particionálás
    • Partíciót hoz létre az egyes lekérdezések minden lépéséhez
  • Statikus fázis
    • Ez a fázis nem függ a kiértékelési eredményektől. Ehelyett a lekérdezések strukturáltságán alapul.
      • Paraméter vágása
        • Levágja a paraméteres partíciókat, vagyis azokat, amelyek:
          • Nem hivatkozik más partíciókra
          • Nem tartalmaz függvényhívásokat
          • Nem ciklikus (vagyis nem hivatkozik magára)
        • Vegye figyelembe, hogy a partíciók "eltávolítása" gyakorlatilag magában foglalja azt bármely más partícióra hivatkozva.
        • A paraméterpartíciók vágása lehetővé teszi, hogy az adatforrásfüggvény-hívásokban használt paraméterhivatkozások (például Web.Contents(myUrl)) működjenek, ahelyett, hogy "a partíció nem hivatkozhat adatforrásokra és egyéb lépésekre" hibaüzeneteket eredményez.
      • Csoportosítás (statikus)
        • A partíciók alulról felfelé lévő függőségi sorrendben egyesülnek. Az eredményül kapott egyesített partíciókban a következők lesznek különek:
          • Partíciók különböző lekérdezésekben
          • Olyan partíciók, amelyek nem hivatkoznak más partíciókra (és így engedélyezettek egy adatforrás elérésére)
          • Más partíciókra hivatkozó partíciók (és így nem érhetők el adatforrásokhoz)
  • Dinamikus fázis
    • Ez a fázis a kiértékelési eredményektől függ, beleértve a különböző partíciók által elért adatforrásokra vonatkozó információkat is.
    • Vágás
      • Az alábbi követelményeknek megfelelő partíciókat vágja ki:
        • Nem fér hozzá adatforrásokhoz
        • Nem hivatkozik adatforrásokhoz hozzáférő partíciókra
        • Nem ciklikus
    • Csoportosítás (dinamikus)
      • Most, hogy a szükségtelen partíciókat levágták, próbáljon meg olyan forráspartíciókat létrehozni, amelyek a lehető legnagyobbak. Ez úgy történik, hogy a partíciókat a fenti statikus csoportosítási fázisban ismertetett szabályokkal egyesítjük.

Mit jelent mindez?

Tekintsünk át egy példát, amely bemutatja, hogyan működik a fent leírt összetett logika.

Íme egy példaforgatókönyv. Ez egy szöveges fájl (Névjegyek) meglehetősen egyszerű egyesítése egy SQL-adatbázissal (Employees), ahol az SQL Server egy paraméter (DbServer).

A három lekérdezés

A példában használt három lekérdezés M-kódja.

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";

Íme egy magasabb szintű nézet, amely a függőségeket mutatja.

Lekérdezésfüggőségek párbeszédpanel.

Partíció

Nagyítsunk egy kicsit, és vegyük bele a lépéseket a képbe, és kezdjük el végigjárni a particionálási logikát. Íme egy diagram a három lekérdezésről, amelyek a kezdeti tűzfalpartíciókat zöld színnel jelenítik meg. Figyelje meg, hogy minden lépés a saját partíciójában kezdődik.

Kezdeti tűzfalpartíciók.

Ezután levágjuk a paraméterpartíciókat. Így a DbServer implicit módon bekerül a forráspartícióba.

Levágott tűzfalpartíciók.

Most elvégezzük a statikus csoportosítást. Ez fenntartja a partíciók elkülönítését a külön lekérdezésekben (például az Alkalmazottak utolsó két lépése nem lesz csoportosítva a partnerek lépéseivel), valamint a más partíciókra (például az Alkalmazottak utolsó két lépésére) hivatkozó partíciók és a nem megfelelő partíciók (például az Alkalmazottak első három lépése) között.

Statikus csoportosítású tűzfalpartíciók közzététele.

Most belépünk a dinamikus fázisba. Ebben a fázisban a fenti statikus partíciók kiértékelése történik. Az adatforrásokhoz nem hozzáférő partíciókat a rendszer levágja. A partíciók ezután a lehető legnagyobb méretű forráspartíciók létrehozásához vannak csoportosítva. Ebben a mintaforgatókönyvben azonban az összes többi partíció hozzáfér az adatforrásokhoz, és nincs további csoportosítás, amely elvégezhető. A mintánk partíciói így ebben a fázisban nem változnak.

Tegyünk úgy, mintha

Az illusztráció kedvéért azonban nézzük meg, mi történne, ha a Névjegyek lekérdezés nem szöveges fájlból származna, hanem az M-ben (talán az Adatok megadása párbeszédpanelen keresztül).

Ebben az esetben a Névjegyek lekérdezés nem fér hozzá adatforrásokhoz. Így a dinamikus fázis első részében levágják.

Tűzfalpartíció a dinamikus fázisok levágása után.

Ha a Névjegyek partíció el lett távolítva, az Alkalmazottak utolsó két lépése már nem hivatkozik semmilyen partícióra, kivéve azt, amely az Alkalmazottak első három lépését tartalmazza. Így a két partíció csoportosítva lesz.

Az eredményként kapott partíció így nézne ki.

Végleges tűzfalpartíciók.

Példa: Adatok továbbítása egyik adatforrásból a másikba

Oké, elég absztrakt magyarázat. Tekintsünk meg egy gyakori forgatókönyvet, amelyben valószínűleg tűzfalhiba lép fel, és a megoldás lépéseit.

Tegyük fel, hogy fel szeretne keresni egy vállalatnevet a Northwind OData szolgáltatásból, majd a cégnév használatával szeretne Bing-keresést végezni.

Először létre kell hoznia egy Vállalati lekérdezést a vállalat nevének lekéréséhez.

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

Ezután létrehoz egy keresési lekérdezést, amely a Vállalatra hivatkozik, és átadja azt a Bingnek.

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

Ezen a ponton bajba kerülsz. A keresés kiértékelése tűzfalhibát okoz.

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.

Ennek az az oka, hogy a Keresés forrás lépése egy adatforrásra (bing.com) hivatkozik, és egy másik lekérdezésre/partícióra (Céges) hivatkozik. Ez sérti a fent említett szabályt ("a partíciók vagy kompatibilis adatforrásokhoz férhetnek hozzá, vagy hivatkozhatnak más partíciókra, de mindkettőre nem").

Mi a teendő? Az egyik lehetőség a tűzfal teljes letiltása (az adatvédelmi szintek figyelmen kívül hagyása és a teljesítmény javítása) feliratú adatvédelmi beállításon keresztül. De mi a teendő, ha engedélyezni szeretné a tűzfalat?

Ha a hibát a tűzfal letiltása nélkül szeretné elhárítani, egyetlen lekérdezésben kombinálhatja a Vállalat és a Keresés parancsot, például a következőt:

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

Most minden egyetlen partíción belül történik. Feltételezve, hogy a két adatforrás adatvédelmi szintjei kompatibilisek, a tűzfalnak boldognak kell lennie, és többé nem fog hibaüzenetet kapni.

Ez egy sortörés.

Bár ennél sokkal többről lehet szó ebben a témakörben, ez a bevezető cikk már elég hosszú. Remélhetőleg jobb ismereteket kap a tűzfalról, és segít megérteni és kijavítani a tűzfalhibákat, amikor a jövőben találkozik velük.