Dela via


Mappa data med hjälp av dataflöden

Viktigt!

Den här sidan innehåller instruktioner för att hantera Azure IoT Operations-komponenter med hjälp av Kubernetes-distributionsmanifest, som finns i förhandsversion. Den här funktionen har flera begränsningar och bör inte användas för produktionsarbetsbelastningar.

Juridiska villkor för Azure-funktioner i betaversion, förhandsversion eller som av någon annan anledning inte har gjorts allmänt tillgängliga ännu finns i kompletterande användningsvillkor för Microsoft Azure-förhandsversioner.

Använd dataflödesmappningsspråket för att transformera data i Azure IoT Operations. Syntaxen är ett enkelt men kraftfullt sätt att definiera mappningar som transformerar data från ett format till ett annat. Den här artikeln innehåller en översikt över dataflödesmappningsspråket och nyckelbegreppen.

Med mappning kan du omvandla data från ett format till ett annat. Överväg följande indatapost:

{
  "Name": "Grace Owens",
  "Place of birth": "London, TX",
  "Birth Date": "19840202",
  "Start Date": "20180812",
  "Position": "Analyst",
  "Office": "Kent, WA"
}

Jämför den med utdataposten:

{
  "Employee": {
    "Name": "Grace Owens",
    "Date of Birth": "19840202"
  },
  "Employment": {
    "Start Date": "20180812",
    "Position": "Analyst, Kent, WA",
    "Base Salary": 78000
  }
}

I utdataposten görs följande ändringar i indatapostens data:

  • Fälten har bytt namn: Fältet Birth Date är nu Date of Birth.
  • Omstrukturerade fält: Båda Name och Date of Birth grupperas under den nya Employee kategorin.
  • Fältet har tagits bort: Fältet Place of birth tas bort eftersom det inte finns i utdata.
  • Fältet har lagts till: Fältet Base Salary är ett nytt fält i Employment kategorin.
  • Fältvärden har ändrats eller sammanfogats: Fältet Position i utdata kombinerar fälten Position och Office från indata.

Omvandlingarna uppnås genom mappning, vilket vanligtvis omfattar:

  • Indatadefinition: Identifiera fälten i de indataposter som används.
  • Utdatadefinition: Ange var och hur indatafälten ska ordnas i utdataposterna.
  • Konvertering (valfritt): Ändra indatafälten så att de passar in i utdatafälten. expression krävs när flera indatafält kombineras till ett enda utdatafält.

Följande mappning är ett exempel:

{
  inputs: [
    'BirthDate'
  ]
  output: 'Employee.DateOfBirth'
}
{
  inputs: [
    'Position'  // - - - - $1
    'Office'    // - - - - $2
  ]
  output: 'Employment.Position'
  expression: '$1 + ", " + $2'
}
{
  inputs: [
    '$context(position).BaseSalary'
  ]
  output: 'Employment.BaseSalary'
}

Exemplet mappar:

  • En-till-en-mappning: BirthDate mappas direkt till Employee.DateOfBirth utan konvertering.
  • Många-till-en-mappning: Kombinerar Position och Office till ett enda Employment.Position fält. Konverteringsformeln ($1 + ", " + $2) sammanfogar dessa fält till en formaterad sträng.
  • Kontextuella data: BaseSalary läggs till från en kontextbaserad datauppsättning med namnet position.

Fältreferenser

Fältreferenser visar hur du anger sökvägar i indata och utdata med hjälp av punkt notation som Employee.DateOfBirth eller åtkomst till data från en kontextuell datauppsättning via $context(position).

Egenskaper för MQTT- och Kafka-metadata

När du använder MQTT eller Kafka som källa eller mål kan du komma åt olika metadataegenskaper i mappningsspråket. Dessa egenskaper kan mappas i indata eller utdata.

Metadataegenskaper

  • Ämne: Fungerar för både MQTT och Kafka. Den innehåller strängen där meddelandet publicerades. Exempel: $metadata.topic.
  • Användaregenskap: I MQTT refererar detta till de nyckel-/värdepar med fritt format som ett MQTT-meddelande kan innehålla. Om till exempel MQTT-meddelandet publicerades med en användaregenskap med nyckeln "prioritet" och värdet "hög" så innehåller referensen $metadata.user_property.priority värdet "hög". Användaregenskapsnycklar kan vara godtyckliga strängar och kan kräva att de tas bort: $metadata.user_property."weird key" använder nyckeln "konstig nyckel" (med ett blanksteg).
  • Systemegenskap: Den här termen används för varje egenskap som inte är en användaregenskap. För närvarande stöds endast en enda systemegenskap: $metadata.system_property.content_type, som läser innehållstypegenskapen för MQTT-meddelandet (om den anges).
  • Rubrik: Det här är Kafka-motsvarigheten till MQTT-användaregenskapen. Kafka kan använda valfritt binärt värde för en nyckel, men dataflödet stöder endast UTF-8-strängnycklar. Exempel: $metadata.header.priority. Den här funktionen liknar användaregenskaper.

Mappa metadataegenskaper

Indatamappning

I följande exempel mappas MQTT-egenskapen topic till fältet origin_topic i utdata:

inputs: [
  '$metadata.topic'
]
output: 'origin_topic'

Om användaregenskapen priority finns i MQTT-meddelandet visar följande exempel hur du mappar den till ett utdatafält:

inputs: [
  '$metadata.user_property.priority'
]
output: 'priority'
Utdatamappning

Du kan också mappa metadataegenskaper till ett utdatahuvud eller en användaregenskap. I följande exempel mappas MQTT topic till origin_topic fältet i utdatans användaregenskap:

inputs: [
  '$metadata.topic'
]
output: '$metadata.user_property.origin_topic'

Om den inkommande nyttolasten innehåller ett priority fält visar följande exempel hur du mappar den till en MQTT-användaregenskap:

inputs: [
  'priority'
]
output: '$metadata.user_property.priority'

Samma exempel för Kafka:

inputs: [
  'priority'
]
output: '$metadata.header.priority'

Väljare för kontextualiseringsdatauppsättningar

Dessa väljare tillåter mappningar att integrera extra data från externa databaser, som kallas kontextualiseringsdatauppsättningar.

Postfiltrering

Postfiltrering omfattar inställningsvillkor för att välja vilka poster som ska bearbetas eller tas bort.

Punkt notation

Punkt notation används ofta i datavetenskap för att referera till fält, även rekursivt. I programmering består fältnamn vanligtvis av bokstäver och siffror. Ett standardexempel för punkt notation kan se ut som i det här exemplet:

inputs: [
  'Person.Address.Street.Number'
]

I ett dataflöde kan en sökväg som beskrivs av punkt notation innehålla strängar och vissa specialtecken utan att behöva fly:

inputs: [
  'Person.Date of Birth'
]

I andra fall är det nödvändigt att fly:

inputs: [
  'Person."Tag.10".Value'
]

I föregående exempel, bland andra specialtecken, finns punkter i fältnamnet. Utan att fly skulle fältnamnet fungera som avgränsare i själva punkt notationen.

Även om ett dataflöde parsar en sökväg behandlar det bara två tecken som specialtecken:

  • Punkter (.) fungerar som fältavgränsare.
  • Enkla citattecken, när de placeras i början eller slutet av ett segment, startar ett undantaget avsnitt där punkter inte behandlas som fältavgränsare.

Andra tecken behandlas som en del av fältnamnet. Den här flexibiliteten är användbar i format som JSON, där fältnamn kan vara godtyckliga strängar.

I Bicep omges alla strängar av enkla citattecken ('). Exemplen om korrekt citat i YAML för Kubernetes använder gäller inte.

Fly

Den primära funktionen för att fly i en punkt noterad sökväg är att hantera användningen av punkter som ingår i fältnamn i stället för avgränsare:

inputs: [
  'Payload."Tag.10".Value'
]

I det här exemplet består sökvägen av tre segment: Payload, Tag.10och Value.

Undantag från regler i punkt notation

  • Undvik varje segment separat: Om flera segment innehåller punkter måste dessa segment omges av dubbla citattecken. Andra segment kan också citeras, men det påverkar inte vägtolkningen:

    inputs: [
      'Payload."Tag.10".Measurements."Vibration.$12".Value'
    ]
    

  • Korrekt användning av dubbla citattecken: Dubbla citattecken måste öppna och stänga ett undantaget segment. Citattecken i mitten av segmentet betraktas som en del av fältnamnet:

    inputs: [
      'Payload.He said: "Hello", and waved'
    ]
    

I det här exemplet definieras två fält: Payload och He said: "Hello", and waved. När en punkt visas under dessa omständigheter fortsätter den att fungera som avgränsare:

inputs: [
  'Payload.He said: "No. It is done"'
]

I det här fallet delas sökvägen upp i segmenten Payload, He said: "Nooch It is done" (börjar med ett blanksteg).

Segmenteringsalgoritm

  • Om det första tecknet i ett segment är ett citattecken söker parsern efter nästa citattecken. Strängen som omges av dessa citattecken betraktas som ett enda segment.
  • Om segmentet inte börjar med ett citattecken identifierar parsern segment genom att söka efter nästa punkt eller slutet av sökvägen.

Jokertecken

I många scenarier liknar utdataposten indataposten, med endast mindre ändringar som krävs. När du hanterar poster som innehåller flera fält kan det bli omständligt att manuellt ange mappningar för varje fält. Jokertecken förenklar den här processen genom att tillåta generaliserade mappningar som automatiskt kan tillämpas på flera fält.

Låt oss överväga ett grundläggande scenario för att förstå användningen av asterisker i mappningar:

inputs: [
  '*'
]
output: '*'

Den här konfigurationen visar en grundläggande mappning där varje fält i indata mappas direkt till samma fält i utdata utan några ändringar. Asterisken (*) fungerar som ett jokertecken som matchar alla fält i indataposten.

Så här fungerar asterisken (*) i den här kontexten:

  • Mönstermatchning: Asterisken kan matcha ett enskilt segment eller flera segment i en sökväg. Den fungerar som platshållare för alla segment i sökvägen.
  • Fältmatchning: Under mappningsprocessen utvärderar algoritmen varje fält i indataposten mot det mönster som anges i inputs. Asterisken i föregående exempel matchar alla möjliga sökvägar och passar effektivt varje enskilt fält i indata.
  • Insamlat segment: Den del av sökvägen som asterisken matchar kallas .captured segment
  • Utdatamappning: I utdatakonfigurationen captured segment placeras den plats där asterisken visas. Det innebär att strukturen för indata bevaras i utdata, med fyllningen captured segment av platshållaren som tillhandahålls av asterisken.

Ett annat exempel illustrerar hur jokertecken kan användas för att matcha underavsnitt och flytta dem tillsammans. Det här exemplet plattar effektivt ut kapslade strukturer i ett JSON-objekt.

Ursprunglig JSON:

{
  "ColorProperties": {
    "Hue": "blue",
    "Saturation": "90%",
    "Brightness": "50%",
    "Opacity": "0.8"
  },
  "TextureProperties": {
    "type": "fabric",
    "SurfaceFeel": "soft",
    "SurfaceAppearance": "matte",
    "Pattern": "knitted"
  }
}

Mappningskonfiguration som använder jokertecken:

{
  inputs: [
    'ColorProperties.*'
  ]
  output: '*'
}
{
  inputs: [
    'TextureProperties.*'
  ]
  output: '*'
}

Resulterande JSON:

{
  "Hue": "blue",
  "Saturation": "90%",
  "Brightness": "50%",
  "Opacity": "0.8",
  "type": "fabric",
  "SurfaceFeel": "soft",
  "SurfaceAppearance": "matte",
  "Pattern": "knitted"
}

Placering av jokertecken

När du placerar ett jokertecken måste du följa dessa regler:

  • Enkel asterisk per datareferens: Endast en asterisk (*) tillåts inom en enda datareferens.
  • Fullständig segmentmatchning: Asterisken måste alltid matcha ett helt segment av sökvägen. Det kan inte användas för att bara matcha en del av ett segment, till exempel path1.partial*.path3.
  • Positionering: Asterisken kan placeras i olika delar av en datareferens:
    • I början: *.path2.path3 – Här matchar asterisken alla segment som leder upp till path2.path3.
    • I mitten: path1.*.path3 – I den här konfigurationen matchar asterisken alla segment mellan path1 och path3.
    • I slutet: path1.path2.* – Asterisken i slutet matchar alla segment som följer efter path1.path2.
  • Sökvägen som innehåller asterisken måste omges av enkla citattecken (').

Jokertecken med flera indata

Ursprunglig JSON:

{
  "Saturation": {
    "Max": 0.42,
    "Min": 0.67,
  },
  "Brightness": {
    "Max": 0.78,
    "Min": 0.93,
  },
  "Opacity": {
    "Max": 0.88,
    "Min": 0.91,
  }
}

Mappningskonfiguration som använder jokertecken:

inputs: [
  '*.Max'  // - $1
  '*.Min'  // - $2
]
output: 'ColorProperties.*'
expression: '($1 + $2) / 2'

Resulterande JSON:

{
  "ColorProperties" : {
    "Saturation": 0.54,
    "Brightness": 0.85,
    "Opacity": 0.89 
  }    
}

Om du använder jokertecken med flera indata måste asterisken (*) konsekvent representera samma Captured Segment för varje indata. När till exempel * avbildningar i mönstret *.Maxförväntar sig mappningsalgoritmen Saturation att motsvarande Saturation.Min matchar mönstret *.Min. * Här ersätts med Captured Segment från den första indatan, som vägleder matchningen för efterföljande indata.

Tänk dig det här detaljerade exemplet:

Ursprunglig 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
    }
  }
}

Inledande mappningskonfiguration som använder jokertecken:

inputs: [
  '*.Max'    // - $1
  '*.Min'    // - $2
  '*.Avg'    // - $3
  '*.Mean'   // - $4
]

Den här första mappningen försöker skapa en matris (till exempel för Opacity: [0.88, 0.91, 0.89, 0.89]). Den här konfigurationen misslyckas eftersom:

  • Den första indatan *.Max samlar in ett segment som Saturation.
  • Mappningen förväntar sig att efterföljande indata ska finnas på samma nivå:
    • Saturation.Max
    • Saturation.Min
    • Saturation.Avg
    • Saturation.Mean

Eftersom Avg och Mean är kapslade i Midsamlar asterisken i den första mappningen inte in dessa sökvägar korrekt.

Korrigerad mappningskonfiguration:

inputs: [
  '*.Max'        // - $1
  '*.Min'        // - $2
  '*.Mid.Avg'    // - $3
  '*.Mid.Mean'   // - $4
]

Den här reviderade mappningen samlar in de nödvändiga fälten korrekt. Den anger korrekt sökvägarna för att inkludera det kapslade Mid objektet, vilket säkerställer att asterisker fungerar effektivt på olika nivåer i JSON-strukturen.

Andra regeln jämfört med specialisering

När du använder föregående exempel från jokertecken med flera indata bör du överväga följande mappningar som genererar två härledda värden för varje egenskap:

{
  inputs: [
    '*.Max'   // - $1
    '*.Min'   // - $2
  ]
  output: 'ColorProperties.*.Avg'
  expression: '($1 + $2) / 2'
}
{
  inputs: [
    '*.Max'   // - $1
    '*.Min'   // - $2
  ]
  output: 'ColorProperties.*.Diff'
  expression: '$1 - $2'
}

Den här mappningen är avsedd att skapa två separata beräkningar (Avg och Diff) för varje egenskap under ColorProperties. Det här exemplet visar resultatet:

{
  "ColorProperties": {
    "Saturation": {
      "Avg": 0.54,
      "Diff": 0.25
    },
    "Brightness": {
      "Avg": 0.85,
      "Diff": 0.15
    },
    "Opacity": {
      "Avg": 0.89,
      "Diff": 0.03
    }
  }
}

Här fungerar den andra mappningsdefinitionen för samma indata som en andra regel för mappning.

Tänk dig nu ett scenario där ett visst fält behöver en annan beräkning:

{
  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'
}

I det här fallet har fältet Opacity en unik beräkning. Två alternativ för att hantera det här överlappande scenariot är:

  • Inkludera båda mappningarna för Opacity. Eftersom utdatafälten skiljer sig åt i det här exemplet skulle de inte åsidosätta varandra.
  • Använd den mer specifika regeln för Opacity och ta bort den mer allmänna regeln.

Överväg ett specialfall för samma fält för att avgöra rätt åtgärd:

{
  inputs: [
    '*.Max'   // - $1
    '*.Min'   // - $2
  ]
  output: 'ColorProperties.*'
  expression: '($1 + $2) / 2'
}
{
  inputs: [
    'Opacity.Max'   // - $1
    'Opacity.Min'   // - $2
  ]
  output: ''
}

Ett tomt output fält i den andra definitionen innebär att du inte skriver fälten i utdataposten (tar effektivt bort Opacity). Den här konfigurationen är mer än en Specialization Second Rule.

Lösning av överlappande mappningar efter dataflöden:

  • Utvärderingen fortsätter från den översta regeln i mappningsdefinitionen.
  • Om en ny mappning matchar samma fält som en tidigare regel gäller följande villkor:
    • A Rank beräknas för varje matchad indata baserat på antalet segment som jokertecknet fångar upp. Till exempel, om Captured Segments är Properties.Opacity, Rank är är 2. Om det bara Opacityär är Rank är 1. En mappning utan jokertecken har Rank 0.
    • Om den Rank senare regeln är lika med eller högre än den tidigare regeln behandlar ett dataflöde den som en Second Rule.
    • Annars behandlar dataflödet konfigurationen som en Specialization.

Mappningen som dirigerar Opacity.Max och Opacity.Min till tomma utdata har Rank till exempel 0. Eftersom den andra regeln har en lägre Rank regel än den tidigare anses den vara en specialisering och åsidosätter den tidigare regeln, vilket skulle beräkna ett värde för Opacity.

Jokertecken i kontextualiseringsdatauppsättningar

Nu ska vi se hur kontextualiseringsdatauppsättningar kan användas med jokertecken via ett exempel. Överväg en datauppsättning med namnet position som innehåller följande post:

{
  "Position": "Analyst",
  "BaseSalary": 70000,
  "WorkingHours": "Regular"
}

I ett tidigare exempel använde vi ett specifikt fält från den här datamängden:

inputs: [
  '$context(position).BaseSalary'
]
output: 'Employment.BaseSalary'

Den här mappningen kopierar BaseSalary från kontextdatauppsättningen Employment direkt till avsnittet i utdataposten. Om du vill automatisera processen och inkludera alla fält från datauppsättningen position Employment i avsnittet kan du använda jokertecken:

inputs: [
  '$context(position).*'
]
output: 'Employment.*'

Den här konfigurationen möjliggör en dynamisk mappning där varje fält i datamängden position kopieras till Employment avsnittet i utdataposten:

{
    "Employment": {      
      "Position": "Analyst",
      "BaseSalary": 70000,
      "WorkingHours": "Regular"
    }
}

Senast kända värde

Du kan spåra det senast kända värdet för en egenskap. Suffixet indatafältet med ? $last för att avbilda det senast kända värdet för fältet. När en egenskap saknar ett värde i en efterföljande indatanyttolast mappas det senast kända värdet till utdatanyttolasten.

Tänk till exempel på följande mappning:

inputs: [
  'Temperature ? $last'
]
output: 'Thermostat.Temperature'

I det här exemplet spåras det senast kända värdet Temperature för. Om en efterföljande indatanyttolast inte innehåller något Temperature värde används det senast kända värdet i utdata.