TripPin bölüm 6 - Şema
Bu çok bölümlü öğretici, Power Query için yeni bir veri kaynağı uzantısı oluşturmayı kapsar. Öğreticinin sırayla yapılması amaçlanır; her ders önceki derslerde oluşturulan bağlayıcı üzerinde oluşturulur ve bağlayıcınıza artımlı olarak yeni özellikler ekler.
Bu derste şunları yapacaksınız:
- REST API için sabit şema tanımlama
- Sütunlar için veri türlerini dinamik olarak ayarlama
- Eksik sütunlardan kaynaklanan dönüştürme hatalarını önlemek için tablo yapısını zorunlu kılma
- Sonuç kümesindeki sütunları gizleme
OData hizmetinin standart REST API'ye kıyasla en büyük avantajlarından biri, $metadata tanımıdır. $metadata belge, tüm Varlıkları (Tablolar) ve Alanlar (Sütunlar) şeması dahil olmak üzere bu hizmette bulunan verileri açıklar. OData.Feed
İşlev, veri türü bilgilerini otomatik olarak ayarlamak için bu şema tanımını kullanır; bu nedenle tüm metin ve sayı alanlarını almak yerine (sizin gibiJson.Document
), son kullanıcılar tarihleri, tam sayıları, saatleri vb. alır ve daha iyi bir genel kullanıcı deneyimi sağlar.
Birçok REST API'sinde şemalarını program aracılığıyla belirlemenin bir yolu yoktur. Bu gibi durumlarda bağlayıcınıza şema tanımları eklemeniz gerekir. Bu derste, tablolarınızın her biri için basit, sabit kodlanmış bir şema tanımlayacak ve hizmetten okuduğunuz veriler üzerinde şemayı zorlayacaksınız.
Not
Burada açıklanan yaklaşım birçok REST hizmeti için işe yaramalıdır. Gelecekteki dersler , yapılandırılmış sütunlarda (kayıt, liste, tablo) şemaları yinelemeli olarak zorunlu kılarak ve CSDL veya JSON Şeması belgelerinden program aracılığıyla şema tablosu oluşturabilen örnek uygulamalar sağlayarak bu yaklaşıma dayalı olarak oluşturulur.
Genel olarak, bağlayıcınız tarafından döndürülen veriler üzerinde bir şema zorlamanın aşağıdakiler gibi birden çok avantajı vardır:
- Doğru veri türlerini ayarlama
- Son kullanıcılara gösterilmesi gerekmeyen sütunları kaldırma (iç kimlikler veya durum bilgileri gibi)
- Yanıtta eksik olabilecek sütunları ekleyerek her veri sayfasının aynı şekle sahip olduğundan emin olma (REST API'lerinin alanın null olması gerektiğini belirtmenin yaygın bir yolu)
Table.Schema ile mevcut şemayı görüntüleme
Önceki derste oluşturulan bağlayıcı TripPin hizmetinden üç tablo görüntüler:Airlines
, Airports
ve People
. Tabloyu görüntülemek için aşağıdaki sorguyu Airlines
çalıştırın:
let
source = TripPin.Contents(),
data = source{[Name="Airlines"]}[Data]
in
data
Sonuçlarda dört sütun döndürülür:
- @odata.id
- @odata.editLink
- AirlineCode
- Veri Akışı Adı
"@odata.*" sütunları OData protokolünün bir parçasıdır ve bağlayıcınızın son kullanıcılarına gösterilmesini isteyeceğiniz veya göstermeniz gereken bir şey değildir. AirlineCode
ve Name
tutmak istediğiniz iki sütun. Tablonun şemasına bakarsanız (kullanışlı Table.Schema işlevini kullanarak), tablodaki tüm sütunların veri türüne Any.Type
sahip olduğunu görebilirsiniz.
let
source = TripPin.Contents(),
data = source{[Name="Airlines"]}[Data]
in
Table.Schema(data)
Table.Schema , tablodaki sütunlar hakkında adlar, konumlar, tür bilgileri ve Precision, Scale ve MaxLength gibi birçok gelişmiş özellik gibi birçok meta veri döndürür.
Gelecekteki dersler bu gelişmiş özellikleri ayarlamak için tasarım desenleri sağlayacaktır, ancak şimdilik yalnızca atfedilen tür (TypeName
), ilkel tür (Kind
) ve sütun değerinin null (IsNullable
) olup olmadığıyla ilgilenmeniz yeterlidir.
Basit bir şema tablosu tanımlama
Şema tablonuz iki sütundan oluşur:
Sütun | Ayrıntılar |
---|---|
Veri Akışı Adı | Sütunun adı. Bu, hizmet tarafından döndürülen sonuçlardaki adla eşleşmelidir. |
Tür | Ayarlayacağımız M veri türü. Bu ilkel bir tür (text , number , datetime vb.) veya atfedilen bir tür (Int64.Type , Currency.Type vb.) olabilir. |
Tablonun sabit kodlanmış şema tablosu Airlines
ve Name
sütunlarını AirlineCode
olarak text
ayarlar ve şöyle görünür:
Airlines = #table({"Name", "Type"}, {
{"AirlineCode", type text},
{"Name", type text}
});
Tabloda Airports
tutmak istediğiniz dört alan vardır (türünden record
biri dahil):
Airports = #table({"Name", "Type"}, {
{"IcaoCode", type text},
{"Name", type text},
{"IataCode", type text},
{"Location", type record}
});
Son olarak, People
tabloda listeler (, AddressInfo
), null atanabilir sütun (Emails
) ve atfedilen türe (Gender
Concurrency
) sahip bir sütun da dahil olmak üzere yedi alan vardır.
People = #table({"Name", "Type"}, {
{"UserName", type text},
{"FirstName", type text},
{"LastName", type text},
{"Emails", type list},
{"AddressInfo", type list},
{"Gender", type nullable text},
{"Concurrency", Int64.Type}
})
SchemaTransformTable yardımcı işlevi
SchemaTransformTable
Aşağıda açıklanan yardımcı işlevi, verilerinizde şemaları zorunlu kılmak için kullanılır. Aşağıdaki parametreleri alır:
Parametre | Tür | Açıklama |
---|---|---|
table | table | Şemanızı zorunlu kılmak istediğiniz veri tablosu. |
schema | table | Sütun bilgilerini okumak için aşağıdaki türdeki şema tablosu: type table [Name = text, Type = type] . |
enforceSchema | Numara | (isteğe bağlı) İşlevin davranışını denetleen bir sabit listesi. Varsayılan değer ( EnforceSchema.Strict = 1 ), çıkış tablosunun eksik sütunları ekleyerek ve ek sütunları kaldırarak sağlanan şema tablosuyla eşleşmesini sağlar. Bu EnforceSchema.IgnoreExtraColumns = 2 seçenek, sonuçtaki ek sütunları korumak için kullanılabilir. Kullanıldığında EnforceSchema.IgnoreMissingColumns = 3 , hem eksik sütunlar hem de ek sütunlar yoksayılır. |
Bu işlevin mantığı şuna benzer:
- Kaynak tabloda eksik sütun olup olmadığını belirleyin.
- Fazladan sütun olup olmadığını belirleyin.
- Yapılandırılmış sütunları (
list
türü ,record
ve ) vetable
olarak ayarlanmış sütunları yoksayıntype any
. - Her sütun türünü ayarlamak için Table.TransformColumnTypes kullanın.
- Şema tablosunda göründükleri sırayla sütunları yeniden sıralar.
- Value.ReplaceType kullanarak tablonun kendisinde türü ayarlayın.
Not
Tablo türünü ayarlamaya yönelik son adım, power query kullanıcı arabiriminin sorgu düzenleyicisinde sonuçları görüntülerken tür bilgilerini çıkarsama gereksinimini ortadan kaldırır. Bu, önceki öğreticinin sonunda gördüğünüz çift istek sorununu kaldırır.
Aşağıdaki yardımcı kod kopyalanabilir ve uzantınıza yapıştırılabilir:
EnforceSchema.Strict = 1; // Add any missing columns, remove extra columns, set table type
EnforceSchema.IgnoreExtraColumns = 2; // Add missing columns, do not remove extra columns
EnforceSchema.IgnoreMissingColumns = 3; // Do not add or remove columns
SchemaTransformTable = (table as table, schema as table, optional enforceSchema as number) as table =>
let
// Default to EnforceSchema.Strict
_enforceSchema = if (enforceSchema <> null) then enforceSchema else EnforceSchema.Strict,
// Applies type transforms to a given table
EnforceTypes = (table as table, schema as table) as table =>
let
map = (t) => if Type.Is(t, type list) or Type.Is(t, type record) or t = type any then null else t,
mapped = Table.TransformColumns(schema, {"Type", map}),
omitted = Table.SelectRows(mapped, each [Type] <> null),
existingColumns = Table.ColumnNames(table),
removeMissing = Table.SelectRows(omitted, each List.Contains(existingColumns, [Name])),
primativeTransforms = Table.ToRows(removeMissing),
changedPrimatives = Table.TransformColumnTypes(table, primativeTransforms)
in
changedPrimatives,
// Returns the table type for a given schema
SchemaToTableType = (schema as table) as type =>
let
toList = List.Transform(schema[Type], (t) => [Type=t, Optional=false]),
toRecord = Record.FromList(toList, schema[Name]),
toType = Type.ForRecord(toRecord, false)
in
type table (toType),
// Determine if we have extra/missing columns.
// The enforceSchema parameter determines what we do about them.
schemaNames = schema[Name],
foundNames = Table.ColumnNames(table),
addNames = List.RemoveItems(schemaNames, foundNames),
extraNames = List.RemoveItems(foundNames, schemaNames),
tmp = Text.NewGuid(),
added = Table.AddColumn(table, tmp, each []),
expanded = Table.ExpandRecordColumn(added, tmp, addNames),
result = if List.IsEmpty(addNames) then table else expanded,
fullList =
if (_enforceSchema = EnforceSchema.Strict) then
schemaNames
else if (_enforceSchema = EnforceSchema.IgnoreMissingColumns) then
foundNames
else
schemaNames & extraNames,
// Select the final list of columns.
// These will be ordered according to the schema table.
reordered = Table.SelectColumns(result, fullList, MissingField.Ignore),
enforcedTypes = EnforceTypes(reordered, schema),
withType = if (_enforceSchema = EnforceSchema.Strict) then Value.ReplaceType(enforcedTypes, SchemaToTableType(schema)) else enforcedTypes
in
withType;
TripPin bağlayıcısını güncelleştirme
Şimdi yeni şema zorlama kodunu kullanmak için bağlayıcınızda aşağıdaki değişiklikleri yapacaksınız.
- Tüm şema tanımlarınızı barındıran bir ana şema tablosu (
SchemaTable
) tanımlayın. - parametresini
TripPin.Feed
kabulschema
etmek için ,GetPage
veGetAllPagesByNextLink
güncelleştirme. - içinde şemanızı
GetPage
zorunlu kılma. - Her tabloyu yeni bir işleve (
GetEntity
) yapılan bir çağrıyla sarmalayacak şekilde gezinti tablosu kodunuzu güncelleştirin; bu, gelecekte tablo tanımlarını işlemek için daha fazla esneklik sağlar.
Ana şema tablosu
Şimdi şema tanımlarınızı tek bir tabloda birleştirip bir varlık adına (örneğin, GetSchemaForEntity("Airlines")
) göre tanımı aramanıza olanak tanıyan bir yardımcı işlev (GetSchemaForEntity
) ekleyeceksiniz.
SchemaTable = #table({"Entity", "SchemaTable"}, {
{"Airlines", #table({"Name", "Type"}, {
{"AirlineCode", type text},
{"Name", type text}
})},
{"Airports", #table({"Name", "Type"}, {
{"IcaoCode", type text},
{"Name", type text},
{"IataCode", type text},
{"Location", type record}
})},
{"People", #table({"Name", "Type"}, {
{"UserName", type text},
{"FirstName", type text},
{"LastName", type text},
{"Emails", type list},
{"AddressInfo", type list},
{"Gender", type nullable text},
{"Concurrency", Int64.Type}
})}
});
GetSchemaForEntity = (entity as text) as table => try SchemaTable{[Entity=entity]}[SchemaTable] otherwise error "Couldn't find entity: '" & entity &"'";
Veri işlevlerine şema desteği ekleme
Şimdi , ve işlevlerine TripPin.Feed
isteğe bağlı schema
bir parametre ekleyeceksiniz.GetAllPagesByNextLink
GetPage
Bu, şemayı (istediğiniz zaman) hizmetten geri alınan sonuçlara uygulanacağı disk belleği işlevlerine geçirmenizi sağlar.
TripPin.Feed = (url as text, optional schema as table) as table => ...
GetPage = (url as text, optional schema as table) as table => ...
GetAllPagesByNextLink = (url as text, optional schema as table) as table => ...
Ayrıca şemayı doğru bir şekilde geçirdiğinizden emin olmak için bu işlevlere yapılan tüm çağrıları güncelleştireceksiniz.
Şemayı zorlama
Gerçek şema zorlama işlevinizde GetPage
yapılır.
GetPage = (url as text, optional schema as table) as table =>
let
response = Web.Contents(url, [ Headers = DefaultRequestHeaders ]),
body = Json.Document(response),
nextLink = GetNextLink(body),
data = Table.FromRecords(body[value]),
// enforce the schema
withSchema = if (schema <> null) then SchemaTransformTable(data, schema) else data
in
withSchema meta [NextLink = nextLink];
Not
Bu GetPage
uygulama, JSON yanıtında kayıt listesini tabloya dönüştürmek için Table.FromRecords kullanır.
Table.FromRecords kullanmanın önemli bir dezavantajı, listedeki tüm kayıtların aynı alan kümesine sahip olduğunu varsaymaktır.
Bu, TripPin hizmeti için çalışır, çünkü OData kayıtları aynı alanları içerecek şekilde garanti edilir, ancak tüm REST API'leri için böyle olmayabilir.
Daha sağlam bir uygulama Table.FromList ve Table.ExpandRecordColumn birleşimini kullanır.
Sonraki öğreticiler, JSON'dan M'ye çeviri sırasında hiçbir sütunun kaybolmamasını veya eksik olmasını sağlayarak şema tablosundan sütun listesini almak için uygulamayı değiştirir.
GetEntity işlevini ekleme
İşlev, GetEntity
Çağrınızı TripPin.Feed'e sarmalar.
Varlık adına göre bir şema tanımı arar ve tam istek URL'sini oluşturur.
GetEntity = (url as text, entity as text) as table =>
let
fullUrl = Uri.Combine(url, entity),
schemaTable = GetSchemaForEntity(entity),
result = TripPin.Feed(fullUrl, schemaTable)
in
result;
Ardından işlevinizi TripPinNavTable
, tüm çağrıları satır içinde yapmak yerine çağrısı GetEntity
yapacak şekilde güncelleştireceksiniz.
Bunun temel avantajı, gezinti tablosu mantığınıza dokunmanıza gerek kalmadan varlık oluşturma kodunuzu değiştirmeye devam etmenizi sağlayacak olmasıdır.
TripPinNavTable = (url as text) as table =>
let
entitiesAsTable = Table.FromList(RootEntities, Splitter.SplitByNothing()),
rename = Table.RenameColumns(entitiesAsTable, {{"Column1", "Name"}}),
// Add Data as a calculated column
withData = Table.AddColumn(rename, "Data", each GetEntity(url, [Name]), type table),
// Add ItemKind and ItemName as fixed text values
withItemKind = Table.AddColumn(withData, "ItemKind", each "Table", type text),
withItemName = Table.AddColumn(withItemKind, "ItemName", each "Table", type text),
// Indicate that the node should not be expandable
withIsLeaf = Table.AddColumn(withItemName, "IsLeaf", each true, type logical),
// Generate the nav table
navTable = Table.ToNavigationTable(withIsLeaf, {"Name"}, "Name", "Data", "ItemKind", "ItemName", "IsLeaf")
in
navTable;
Hepsini bir araya getirme
Tüm kod değişiklikleri yapıldıktan sonra Airlines tablosunu çağıran Table.Schema
test sorgusunu derleyin ve yeniden çalıştırın.
let
source = TripPin.Contents(),
data = source{[Name="Airlines"]}[Data]
in
Table.Schema(data)
Artık Airlines tablonuzda yalnızca şemasında tanımladığınız iki sütunun bulunduğunu görürsünüz:
Kişiler tablosunda aynı kodu çalıştırırsanız...
let
source = TripPin.Contents(),
data = source{[Name="People"]}[Data]
in
Table.Schema(data)
Kullandığınız (Int64.Type
) atfedilen türün de doğru ayarlandığını göreceksiniz.
Dikkat edilmesi gereken önemli bir nokta, bu uygulamasının SchemaTransformTable
ve record
sütunlarının türlerini değiştirmemesi, ancak Emails
ve AddressInfo
sütunlarının list
yine olarak list
yazıldığıdır. Bunun nedeni Json.Document
, JSON dizilerini M listelerine ve JSON nesnelerini M kayıtlarına doğru şekilde eşleyecektir. Power Query'de liste veya kayıt sütununu genişletirseniz, tüm genişletilmiş sütunların herhangi bir türde olacağını görürsünüz. Gelecekteki öğreticiler, iç içe karmaşık türler için tür bilgilerini özyinelemeli olarak ayarlamak üzere uygulamayı geliştirecektir.
Sonuç
Bu öğreticide, REST hizmetinden döndürülen JSON verilerinde şema zorlamaya yönelik örnek bir uygulama sağlanmıştır. Bu örnek basit bir sabit kodlanmış şema tablosu biçimi kullansa da, JSON şema dosyası veya veri kaynağı tarafından kullanıma sunulan meta veri hizmeti/uç noktası gibi başka bir kaynaktan dinamik olarak şema tablosu tanımı oluşturularak yaklaşım genişletilebilir.
Sütun türlerini (ve değerlerini) değiştirmenin yanı sıra kodunuz da tablonun kendisinde doğru tür bilgilerini ayarlar. Kullanıcı deneyimi her zaman son kullanıcıya doğru kullanıcı arabirimi kuyruklarını görüntülemek için tür bilgilerini çıkarsamaya çalıştığından ve çıkarım çağrıları temel alınan veri API'lerine yönelik diğer çağrıları tetikleyene kadar bu tür bilgisinin ayarlanması Power Query'nin içinde çalışırken performans açısından avantaj sağlar.
Önceki dersten TripPin bağlayıcısını kullanarak Kişiler tablosunu görüntülerseniz, tüm sütunların bir 'herhangi birini yazın' simgesi (liste içeren sütunlar bile) olduğunu görürsünüz:
Bu dersten TripPin bağlayıcısıyla aynı sorguyu çalıştırdığınızda artık tür bilgilerinin doğru görüntülendiğini göreceksiniz.