Mapování dat pomocí toků dat
Důležité
Tato stránka obsahuje pokyny ke správě komponent operací Azure IoT pomocí manifestů nasazení Kubernetes, které jsou ve verzi Preview. Tato funkce je poskytována s několika omezeními a neměla by se používat pro produkční úlohy.
Právní podmínky, které platí pro funkce Azure, které jsou ve verzi beta, verzi Preview nebo které zatím nejsou veřejně dostupné, najdete v Dodatečných podmínkách použití pro Microsoft Azure verze Preview.
K transformaci dat v operacích Azure IoT použijte jazyk mapování toku dat. Syntaxe je jednoduchý, ale výkonný způsob, jak definovat mapování, která transformují data z jednoho formátu do druhého. Tento článek obsahuje přehled jazyka mapování toku dat a klíčových konceptů.
Mapování umožňuje transformovat data z jednoho formátu do druhého. Zvažte následující vstupní záznam:
{
"Name": "Grace Owens",
"Place of birth": "London, TX",
"Birth Date": "19840202",
"Start Date": "20180812",
"Position": "Analyst",
"Office": "Kent, WA"
}
Porovnejte ho s výstupním záznamem:
{
"Employee": {
"Name": "Grace Owens",
"Date of Birth": "19840202"
},
"Employment": {
"Start Date": "20180812",
"Position": "Analyst, Kent, WA",
"Base Salary": 78000
}
}
Ve výstupním záznamu se u vstupních dat záznamu provádějí následující změny:
- Pole byla přejmenována: Pole
Birth Date
je nyníDate of Birth
. - Pole jsou restrukturovaná: Obě
Name
aDate of Birth
jsou seskupeny do novéEmployee
kategorie. - Odstraněné pole: Pole
Place of birth
se odebere, protože ve výstupu není. - Přidáno pole: Pole
Base Salary
je nové pole vEmployment
kategorii. - Změněné nebo sloučené hodnoty polí: Pole
Position
ve výstupu kombinujePosition
pole aOffice
pole ze vstupu.
Transformace se provádějí prostřednictvím mapování, což obvykle zahrnuje:
- Definice vstupu: Identifikace polí ve vstupních záznamech, které se používají.
- Definice výstupu: Určuje, kde a jak jsou vstupní pole uspořádána do výstupních záznamů.
- Převod (volitelné): Úprava vstupních polí tak, aby se vešla do výstupních polí.
expression
je vyžadována, pokud se do jednoho výstupního pole zkombinuje více vstupních polí.
Příkladem je následující mapování:
{
inputs: [
'BirthDate'
]
output: 'Employee.DateOfBirth'
}
{
inputs: [
'Position' // - - - - $1
'Office' // - - - - $2
]
output: 'Employment.Position'
expression: '$1 + ", " + $2'
}
{
inputs: [
'$context(position).BaseSalary'
]
output: 'Employment.BaseSalary'
}
Ukázkové mapy:
- Mapování 1:1:
BirthDate
je přímo namapováno bezEmployee.DateOfBirth
převodu. - Mapování M:1: Kombinuje
Position
doOffice
jednohoEmployment.Position
pole. Vzorec převodu ($1 + ", " + $2
) sloučí tato pole do formátovaného řetězce. - Kontextová data:
BaseSalary
je přidána z kontextové datové sady s názvemposition
.
Odkazy na pole
Odkazy na pole ukazují, jak zadat cesty ve vstupu a výstupu pomocí zápisu tečky, jako Employee.DateOfBirth
je nebo přistupovat k datům z kontextové datové sady prostřednictvím $context(position)
.
Vlastnosti metadat MQTT a Kafka
Pokud jako zdroj nebo cíl používáte MQTT nebo Kafka, můžete přistupovat k různým vlastnostem metadat v jazyku mapování. Tyto vlastnosti lze mapovat ve vstupu nebo výstupu.
Vlastnosti metadat
- Téma: Funguje pro MQTT i Kafka. Obsahuje řetězec, ve kterém byla zpráva publikována. Příklad:
$metadata.topic
. - Vlastnost uživatele: V MQTT to odkazuje na páry klíč/hodnota volného formuláře, které může zpráva MQTT přenášet. Například pokud byla zpráva MQTT publikována s vlastností uživatele s klíčem "priority" a hodnotou "vysoká", pak
$metadata.user_property.priority
odkaz uchovává hodnotu "high". Klíče vlastností uživatele můžou být libovolné řetězce a můžou vyžadovat escaping:$metadata.user_property."weird key"
používá klíč "divný klíč" (s mezerou). - Systémová vlastnost: Tento termín se používá pro každou vlastnost, která není vlastností uživatele. V současné době je podporována pouze jedna systémová vlastnost:
$metadata.system_property.content_type
, která čte vlastnost typu obsahu zprávy MQTT (pokud je nastavena). - Hlavička: Toto je ekvivalent Kafka vlastnosti uživatele MQTT. Kafka může pro klíč použít libovolnou binární hodnotu, ale tok dat podporuje pouze řetězcové klíče UTF-8. Příklad:
$metadata.header.priority
. Tato funkce je podobná vlastnostem uživatele.
Mapování vlastností metadat
Mapování vstupu
V následujícím příkladu se vlastnost MQTT topic
mapuje na origin_topic
pole ve výstupu:
inputs: [
'$metadata.topic'
]
output: 'origin_topic'
Pokud vlastnost uživatele priority
je přítomna ve zprávě MQTT, následující příklad ukazuje, jak ji mapovat na výstupní pole:
inputs: [
'$metadata.user_property.priority'
]
output: 'priority'
Mapování výstupu
Vlastnosti metadat můžete také mapovat na výstupní hlavičku nebo vlastnost uživatele. V následujícím příkladu se MQTT topic
mapuje na origin_topic
pole ve vlastnosti uživatele výstupu:
inputs: [
'$metadata.topic'
]
output: '$metadata.user_property.origin_topic'
Pokud příchozí datová část obsahuje priority
pole, následující příklad ukazuje, jak ji mapovat na vlastnost uživatele MQTT:
inputs: [
'priority'
]
output: '$metadata.user_property.priority'
Stejný příklad pro Kafka:
inputs: [
'priority'
]
output: '$metadata.header.priority'
Selektory kontextové datové sady
Tyto selektory umožňují mapování pro integraci dalších dat z externích databází, které se označují jako kontextové datové sady.
Filtrování záznamů
Filtrování záznamů zahrnuje nastavení podmínek pro výběr záznamů, které mají být zpracovány nebo vynechány.
Zápis tečky
Zápis tečky se běžně používá v počítačových vědách k odkazování na pole, a to i rekurzivně. V programování se názvy polí obvykle skládají z písmen a číslic. Standardní ukázka zápisu tečky může vypadat jako v tomto příkladu:
inputs: [
'Person.Address.Street.Number'
]
V toku dat může cesta popsaná tečkou obsahovat řetězce a některé speciální znaky bez nutnosti odvozování:
inputs: [
'Person.Date of Birth'
]
V jiných případech je nutné eskapitulace:
inputs: [
'Person."Tag.10".Value'
]
Předchozí příklad kromě jiných speciálních znaků obsahuje tečky v názvu pole. Bez zapouzdření by název pole sloužil jako oddělovač v samotném zápisu tečky.
I když tok dat analyzuje cestu, považuje za speciální pouze dva znaky:
- Tečky (
.
) fungují jako oddělovače polí. - Při umístění na začátek nebo na konec segmentu začněte uvozovkami, kde tečky nejsou považovány za oddělovače polí.
Všechny ostatní znaky se považují za součást názvu pole. Tato flexibilita je užitečná ve formátech, jako je JSON, kde názvy polí můžou být libovolné řetězce.
V bicep jsou všechny řetězce uzavřeny do jednoduchých uvozovek ('
). Příklady správného uvozování v YAML pro Kubernetes se nevztahují.
Unikající
Primární funkcí escapingu v cestě s tečkami je použít tečky, které jsou součástí názvů polí místo oddělovačů:
inputs: [
'Payload."Tag.10".Value'
]
V tomto příkladu se cesta skládá ze tří segmentů: Payload
, Tag.10
a Value
.
Pravidla zapouzdření v zápisu tečky
Jednotlivé segmenty uvozujte zvlášť: Pokud více segmentů obsahuje tečky, musí být tyto segmenty uzavřeny do dvojitých uvozovek. Další segmenty mohou být také citovány, ale neovlivňují interpretaci cesty:
inputs: [ 'Payload."Tag.10".Measurements."Vibration.$12".Value' ]
Správné použití dvojitých uvozovek: Dvojité uvozovky musí otevřít a zavřít řídicí segment. Všechny uvozovky uprostřed segmentu se považují za součást názvu pole:
inputs: [ 'Payload.He said: "Hello", and waved' ]
Tento příklad definuje dvě pole: Payload
a He said: "Hello", and waved
. Když se za těchto okolností zobrazí tečka, bude sloužit jako oddělovač:
inputs: [
'Payload.He said: "No. It is done"'
]
V tomto případě je cesta rozdělena do segmentů Payload
, He said: "No
a It is done"
(počínaje mezerou).
Algoritmus segmentace
- Pokud je prvním znakem segmentu uvozovka, analyzátor vyhledá další uvozovky. Řetězec uzavřený mezi těmito uvozovkami se považuje za jeden segment.
- Pokud segment nezačíná uvozovkami, analyzátor identifikuje segmenty vyhledáním další tečky nebo konce cesty.
Divoká karta
V mnoha scénářích se výstupní záznam velmi podobá vstupnímu záznamu a vyžaduje se pouze menší úpravy. Při práci se záznamy, které obsahují mnoho polí, může být ruční zadání mapování pro každé pole zdlouhavé. Zástupné dokumentace zjednodušují tento proces tím, že umožňují generalizované mapování, která se můžou automaticky použít u více polí.
Pojďme se podívat na základní scénář, který vám umožní pochopit použití hvězdičky v mapováních:
inputs: [
'*'
]
output: '*'
Tato konfigurace ukazuje základní mapování, ve kterém je každé pole ve vstupu přímo namapované na stejné pole ve výstupu bez jakýchkoli změn. Hvězdička (*
) slouží jako zástupný znak, který odpovídá libovolnému poli ve vstupním záznamu.
Tady je postup, jak hvězdička (*
) funguje v tomto kontextu:
- Porovnávání vzorů: Hvězdička může odpovídat jednomu segmentu nebo více segmentům cesty. Slouží jako zástupný symbol pro všechny segmenty v cestě.
- Porovnávání polí: Během procesu mapování algoritmus vyhodnocuje každé pole ve vstupním záznamu podle vzoru zadaného v objektu
inputs
. Hvězdička v předchozím příkladu odpovídá všem možným cestám a efektivně přizpůsobí každé jednotlivá pole ve vstupu. - Zachycený segment: Část cesty, kterou hvězdička odpovídá, se označuje jako
captured segment
. - Mapování výstupu: Ve výstupní konfiguraci
captured segment
se nachází hvězdička. To znamená, že struktura vstupu se zachová ve výstupu scaptured segment
vyplněním zástupného symbolu poskytnutého hvězdičkou.
Další příklad ukazuje, jak se dají zástupné cardy použít ke shodě pododdílů a jejich přesouvání. Tento příklad efektivně zploštěluje vnořené struktury v rámci objektu JSON.
Původní JSON:
{
"ColorProperties": {
"Hue": "blue",
"Saturation": "90%",
"Brightness": "50%",
"Opacity": "0.8"
},
"TextureProperties": {
"type": "fabric",
"SurfaceFeel": "soft",
"SurfaceAppearance": "matte",
"Pattern": "knitted"
}
}
Konfigurace mapování, která používá zástupné kóty:
{
inputs: [
'ColorProperties.*'
]
output: '*'
}
{
inputs: [
'TextureProperties.*'
]
output: '*'
}
Výsledný JSON:
{
"Hue": "blue",
"Saturation": "90%",
"Brightness": "50%",
"Opacity": "0.8",
"type": "fabric",
"SurfaceFeel": "soft",
"SurfaceAppearance": "matte",
"Pattern": "knitted"
}
Umístění zástupných znaků
Když umístíte zástupný znak, musíte postupovat podle těchto pravidel:
- Jedna hvězdička na odkaz na data: V rámci jednoho odkazu na data je povolena pouze jedna hvězdička (
*
). - Úplná shoda segmentů: Hvězdička musí vždy odpovídat celému segmentu cesty. Nedá se použít k porovnávání pouze části segmentu, například
path1.partial*.path3
. - Umístění: Hvězdička může být umístěna v různých částech odkazu na data:
- Na začátku:
*.path2.path3
- Zde hvězdička odpovídá libovolnému segmentu, který vede až kpath2.path3
. - Uprostřed:
path1.*.path3
- V této konfiguraci hvězdička odpovídá libovolnému segmentu mezipath1
apath3
. - Na konci:
path1.path2.*
- Hvězdička na konci odpovídá libovolnému segmentu, který následuje zapath1.path2
.
- Na začátku:
- Cesta obsahující hvězdičku musí být uzavřena do jednoduchých uvozovek (
'
).
Zástupné kóty s více vstupy
Původní JSON:
{
"Saturation": {
"Max": 0.42,
"Min": 0.67,
},
"Brightness": {
"Max": 0.78,
"Min": 0.93,
},
"Opacity": {
"Max": 0.88,
"Min": 0.91,
}
}
Konfigurace mapování, která používá zástupné kóty:
inputs: [
'*.Max' // - $1
'*.Min' // - $2
]
output: 'ColorProperties.*'
expression: '($1 + $2) / 2'
Výsledný JSON:
{
"ColorProperties" : {
"Saturation": 0.54,
"Brightness": 0.85,
"Opacity": 0.89
}
}
Pokud používáte zástupné kóty s více vstupy, hvězdička (*
) musí konzistentně reprezentovat stejné Captured Segment
napříč všemi vstupy. Například při *
zachycení v modelu *.Max
očekává algoritmus mapování odpovídající shody Saturation.Min
se vzorem *.Min
Saturation
. *
Zde je nahrazen Captured Segment
z prvního vstupu, který vede porovnávání pro následné vstupy.
Podívejte se na tento podrobný příklad:
Původní JSON:
{
"Saturation": {
"Max": 0.42,
"Min": 0.67,
"Mid": {
"Avg": 0.51,
"Mean": 0.56
}
},
"Brightness": {
"Max": 0.78,
"Min": 0.93,
"Mid": {
"Avg": 0.81,
"Mean": 0.82
}
},
"Opacity": {
"Max": 0.88,
"Min": 0.91,
"Mid": {
"Avg": 0.89,
"Mean": 0.89
}
}
}
Počáteční konfigurace mapování, která používá zástupné kóty:
inputs: [
'*.Max' // - $1
'*.Min' // - $2
'*.Avg' // - $3
'*.Mean' // - $4
]
Toto počáteční mapování se pokusí vytvořit pole (například : Opacity
[0.88, 0.91, 0.89, 0.89]
). Tato konfigurace selže, protože:
- První vstup
*.Max
zachycuje segment jakoSaturation
. - Mapování očekává, že následující vstupy budou přítomny na stejné úrovni:
Saturation.Max
Saturation.Min
Saturation.Avg
Saturation.Mean
Protože Avg
a Mean
jsou vnořené v rámci Mid
, hvězdička v počátečním mapování tyto cesty správně nezachytí.
Opravená konfigurace mapování:
inputs: [
'*.Max' // - $1
'*.Min' // - $2
'*.Mid.Avg' // - $3
'*.Mid.Mean' // - $4
]
Toto revidované mapování přesně zachycuje potřebná pole. Správně určuje cesty, které mají zahrnovat vnořený Mid
objekt, což zajišťuje efektivní fungování asterisek napříč různými úrovněmi struktury JSON.
Druhé pravidlo vs. specializace
Pokud použijete předchozí příklad ze zástupných znaků s více vstupy, zvažte následující mapování, která generují dvě odvozené hodnoty pro každou vlastnost:
{
inputs: [
'*.Max' // - $1
'*.Min' // - $2
]
output: 'ColorProperties.*.Avg'
expression: '($1 + $2) / 2'
}
{
inputs: [
'*.Max' // - $1
'*.Min' // - $2
]
output: 'ColorProperties.*.Diff'
expression: '$1 - $2'
}
Toto mapování je určeno k vytvoření dvou samostatných výpočtů (Avg
a Diff
) pro každou vlastnost v části ColorProperties
. Tento příklad ukazuje výsledek:
{
"ColorProperties": {
"Saturation": {
"Avg": 0.54,
"Diff": 0.25
},
"Brightness": {
"Avg": 0.85,
"Diff": 0.15
},
"Opacity": {
"Avg": 0.89,
"Diff": 0.03
}
}
}
Tady druhá definice mapování stejných vstupů funguje jako druhé pravidlo pro mapování.
Teď zvažte scénář, ve kterém konkrétní pole potřebuje jiný výpočet:
{
inputs: [
'*.Max' // - $1
'*.Min' // - $2
]
output: 'ColorProperties.*'
expression: '($1 + $2) / 2'
}
{
inputs: [
'Opacity.Max' // - $1
'Opacity.Min' // - $2
]
output: 'ColorProperties.OpacityAdjusted'
expression: '($1 + $2 + 1.32) / 2'
}
V tomto případě Opacity
má pole jedinečný výpočet. Existují dvě možnosti pro zpracování tohoto překrývajícího se scénáře:
- Zahrňte obě mapování pro
Opacity
. Vzhledem k tomu, že se výstupní pole v tomto příkladu liší, nepřepíšou se navzájem. - Použijte konkrétnější pravidlo pro
Opacity
a odeberte obecnější pravidlo.
Zvažte zvláštní případ pro stejná pole, která vám pomůžou rozhodnout o správné akci:
{
inputs: [
'*.Max' // - $1
'*.Min' // - $2
]
output: 'ColorProperties.*'
expression: '($1 + $2) / 2'
}
{
inputs: [
'Opacity.Max' // - $1
'Opacity.Min' // - $2
]
output: ''
}
Prázdné output
pole v druhé definici znamená, že nezapisuje pole ve výstupním záznamu (efektivně odstraňuje Opacity
). Toto nastavení je více Specialization
než .Second Rule
Řešení překrývajících se mapování podle toků dat:
- Vyhodnocení postupuje od horního pravidla v definici mapování.
- Pokud se nové mapování přeloží na stejná pole jako předchozí pravidlo, platí následující podmínky:
- Pro každý vyřešený vstup se vypočítá A
Rank
na základě počtu segmentů zachycených zástupnými znamény. Pokud jsou napříkladCaptured Segments
Properties.Opacity
,Rank
je 2. Pokud je to jenomOpacity
,Rank
je to 1. Mapování bez zástupných znaků máRank
0. Rank
Pokud je druhé pravidlo stejné nebo vyšší než předchozí pravidlo, tok dat s ním pracuje jako sSecond Rule
.- V opačném případě tok dat zachází s konfigurací jako s
Specialization
.
- Pro každý vyřešený vstup se vypočítá A
Například mapování, které směruje Opacity.Max
a Opacity.Min
do prázdného výstupu má Rank
0. Vzhledem k tomu, že druhé pravidlo má nižší Rank
než předchozí pravidlo, považuje se za specializace a přepíše předchozí pravidlo, které by vypočítalo hodnotu pro Opacity
.
Zástupné cardy v datových sadách kontextové konfigurace
Teď se podíváme, jak se dají datové sady kontextových dat používat se zástupnými cardy prostřednictvím příkladu. Představte si datovou sadu s názvem position
, která obsahuje následující záznam:
{
"Position": "Analyst",
"BaseSalary": 70000,
"WorkingHours": "Regular"
}
V předchozím příkladu jsme použili konkrétní pole z této datové sady:
inputs: [
'$context(position).BaseSalary'
]
output: 'Employment.BaseSalary'
Toto mapování zkopíruje BaseSalary
z kontextové datové sady přímo do Employment
části výstupního záznamu. Pokud chcete proces automatizovat a zahrnout všechna pole z datové sady do oddílu position
Employment
, můžete použít zástupné cardy:
inputs: [
'$context(position).*'
]
output: 'Employment.*'
Tato konfigurace umožňuje dynamické mapování, ve kterém se každé pole v datové position
sadě zkopíruje do Employment
části výstupního záznamu:
{
"Employment": {
"Position": "Analyst",
"BaseSalary": 70000,
"WorkingHours": "Regular"
}
}
Poslední známá hodnota
Můžete sledovat poslední známou hodnotu vlastnosti. Příponou vstupního pole ? $last
zachytíte poslední známou hodnotu pole. Pokud vlastnost chybí hodnota v následné vstupní datové části, poslední známá hodnota je namapována na výstupní datovou část.
Představte si například následující mapování:
inputs: [
'Temperature ? $last'
]
output: 'Thermostat.Temperature'
V tomto příkladu se sleduje poslední známá hodnota Temperature
. Pokud následující vstupní datová část neobsahuje Temperature
hodnotu, použije se ve výstupu poslední známá hodnota.