다음을 통해 공유


데이터 흐름을 사용하여 데이터 매핑

Important

이 페이지에는 미리 보기 상태인 Kubernetes 배포 매니페스트를 사용하여 Azure IoT Operations 구성 요소를 관리하기 위한 지침이 포함되어 있습니다. 이 기능은 몇 가지 제한 사항을 제공하며 프로덕션 워크로드에 사용하면 안 됩니다.

베타, 미리 보기로 제공되거나 아직 일반 공급으로 릴리스되지 않은 Azure 기능에 적용되는 약관은 Microsoft Azure 미리 보기에 대한 추가 사용 약관을 참조하세요.

데이터 흐름 매핑 언어를 사용하여 Azure IoT 작업에서 데이터를 변환합니다. 구문은 데이터를 한 형식에서 다른 형식으로 변환하는 매핑을 정의하는 단순하면서도 강력한 방법입니다. 이 문서에서는 데이터 흐름 매핑 언어와 주요 개념에 대해 간략하게 설명합니다.

매핑을 사용하면 데이터를 한 형식에서 다른 형식으로 변환할 수 있습니다. 다음 입력 레코드를 고려합니다.

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

출력 레코드와 비교합니다.

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

출력 레코드에서 입력 레코드 데이터에 다음과 같은 변경 내용이 적용됩니다.

  • 필드 이름이 바뀌었습니다. 이제 Date of Birth필드 Birth Date 가 .입니다.
  • 필드가 재구성됨: 둘 다 NameDate of Birth Employee 범주 아래에 그룹화됩니다.
  • 필드 삭제됨: Place of birth 필드가 출력에 없으므로 제거됩니다.
  • 필드가 추가됨: 필드 Base Salary 가 범주의 새 필드입니다 Employment .
  • 필드 값이 변경되거나 병합됨: Position 출력의 필드는 입력의 Position 필드와 Office 필드를 결합합니다.

변환은 일반적으로 다음과 같은 매핑을 통해 수행됩니다.

  • 입력 정의: 사용되는 입력 레코드의 필드를 식별합니다.
  • 출력 정의: 출력 레코드에서 입력 필드가 어디에 어떻게 구성되는지 지정합니다.
  • 변환(선택 사항): 출력 필드에 맞게 입력 필드를 수정합니다. expression 은 여러 입력 필드를 단일 출력 필드로 결합할 때 필요합니다.

다음 매핑은 예제입니다.

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

맵 예:

  • 일대일 매핑: BirthDate 변환 없이 직접 매핑됩니다 Employee.DateOfBirth .
  • 다대일 매핑: PositionOffice를 단일 Employment.Position 필드로 결합합니다. 변환 수식($1 + ", " + $2)은 이러한 필드를 형식이 지정된 문자열로 병합합니다.
  • 컨텍스트 데이터: BaseSalary 라는 position컨텍스트 데이터 세트에서 추가 됩니다.

필드 참조

필드 참조는 점 표기법을 Employee.DateOfBirth 사용하거나 컨텍스트 데이터 세트 $context(position)의 데이터에 액세스하여 입력 및 출력의 경로를 지정하는 방법을 보여 줍니다.

MQTT 및 Kafka 메타데이터 속성

MQTT 또는 Kafka를 원본 또는 대상으로 사용하는 경우 매핑 언어의 다양한 메타데이터 속성에 액세스할 수 있습니다. 이러한 속성은 입력 또는 출력에 매핑될 수 있습니다.

메타데이터 속성

  • 항목: MQTT와 Kafka 모두에서 작동합니다. 여기에는 메시지가 게시된 문자열이 포함됩니다. 예: $metadata.topic
  • 사용자 속성: MQTT에서 MQTT 메시지가 전달할 수 있는 자유 형식 키/값 쌍을 나타냅니다. 예를 들어 MQTT 메시지가 키 "우선 순위"와 값이 "높 $metadata.user_property.priority 음"인 사용자 속성과 함께 게시된 경우 참조는 값 "high"를 유지합니다. 사용자 속성 키는 임의의 문자열일 수 있으며 이스케이프가 $metadata.user_property."weird key" 필요할 수 있습니다. 키 "이상한 키"(공백 포함)를 사용합니다.
  • 시스템 속성: 이 용어는 사용자 속성이 아닌 모든 속성에 사용됩니다. 현재 MQTT 메시지의 콘텐츠 형식 속성을 읽는 단일 시스템 속성만 지원 $metadata.system_property.content_type됩니다(설정된 경우).
  • 헤더: MQTT 사용자 속성에 해당하는 Kafka입니다. Kafka는 키에 대해 모든 이진 값을 사용할 수 있지만 데이터 흐름은 UTF-8 문자열 키만 지원합니다. 예: $metadata.header.priority 이 기능은 사용자 속성과 유사합니다.

메타데이터 속성 매핑

입력 매핑

다음 예제에서 MQTT topic 속성은 출력의 origin_topic 필드에 매핑됩니다.

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

MQTT 메시지에 사용자 속성 priority 이 있는 경우 다음 예제에서는 출력 필드에 매핑하는 방법을 보여 줍니다.

inputs: [
  '$metadata.user_property.priority'
]
output: 'priority'
출력 매핑

메타데이터 속성을 출력 헤더 또는 사용자 속성에 매핑할 수도 있습니다. 다음 예제에서 MQTT topic 는 출력의 사용자 속성에 있는 필드에 매핑됩니다 origin_topic .

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

들어오는 페이로드에 필드가 priority 포함된 경우 다음 예제에서는 MQTT 사용자 속성에 매핑하는 방법을 보여 줍니다.

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

Kafka에 대한 동일한 예제:

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

컨텍스트화 데이터 세트 선택기

이러한 선택기를 사용하면 매핑이 컨텍스트화 데이터 세트라고 하는 외부 데이터베이스의 추가 데이터를 통합할 수 있습니다.

레코드 필터링

레코드 필터링은 어떤 레코드를 처리하거나 삭제할지 선택하기 위한 조건을 설정하는 것을 포함합니다.

점 표기법

점 표기법은 재귀적으로도 필드를 참조하기 위해 컴퓨터 과학에서 널리 사용됩니다. 프로그래밍에서 필드 이름은 일반적으로 문자와 숫자로 구성됩니다. 표준 점 표기법 샘플은 다음 예제와 같습니다.

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

데이터 흐름에서 점 표기법으로 설명된 경로에는 이스케이프 없이 문자열 및 일부 특수 문자가 포함될 수 있습니다.

inputs: [
  'Person.Date of Birth'
]

이스케이프가 필요한 경우도 있습니다.

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

이전 예제에서는 다른 특수 문자 중에서 필드 이름 내에 점을 포함합니다. 이스케이프하지 않으면 필드 이름은 점 표기법 자체에서 구분 기호로 작동합니다.

데이터 흐름이 경로를 구문 분석하는 동안 두 문자만 특수 문자로 처리합니다.

  • 점(.)은 필드 구분 기호 역할을 합니다.
  • 작은따옴표는 세그먼트의 시작 또는 끝에 배치될 때 점이 필드 구분 기호로 처리되지 않는 이스케이프된 섹션을 시작합니다.

다른 문자는 필드 이름의 일부로 처리됩니다. 이러한 유연성은 필드 이름이 임의의 문자열일 수 있는 JSON과 같은 형식에서 유용합니다.

Bicep에서 모든 문자열은 작은따옴표(')로 묶입니다. Kubernetes용 YAML에서 적절한 따옴표에 대한 예제는 적용되지 않습니다.

이스케이프

점으로 표기된 경로에서 이스케이프하는 주요 함수는 구분 기호가 아닌 필드 이름의 일부인 점을 사용하도록 수용하는 것입니다.

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

이 예제에서 경로는 세 세그먼트, 즉 , Tag.10Value세 개의 세그먼트로 구성됩니다Payload.

점 표기법의 이스케이프 규칙

  • 각 세그먼트를 개별적으로 이스케이프: 여러 세그먼트에 점이 포함된 경우 해당 세그먼트를 큰따옴표로 묶어야 합니다. 다른 세그먼트도 인용할 수 있지만 경로 해석에는 영향을 미치지 않습니다.

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

  • 큰따옴표의 적절한 사용: 큰따옴표는 이스케이프된 세그먼트를 열고 닫아야 합니다. 세그먼트 중간에 있는 모든 따옴표는 필드 이름의 일부로 간주됩니다.

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

이 예제에서는 두 개의 필드를 Payload He said: "Hello", and waved정의합니다. 이러한 상황에서 점이 나타나면 구분 기호로 계속 작동합니다.

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

이 경우 경로는 Payload, He said: "No, It is done"(공백으로 시작) 세그먼트로 분할됩니다.

구분 알고리즘

  • 세그먼트의 첫 번째 문자가 따옴표이면 파서는 다음 따옴표를 검색합니다. 이러한 따옴표 사이에 묶인 문자열은 단일 세그먼트로 간주됩니다.
  • 세그먼트가 따옴표로 시작하지 않으면 파서는 다음 점 또는 경로의 끝을 검색하여 세그먼트를 식별합니다.

와일드카드

많은 경우, 출력 레코드는 입력 레코드와 매우 유사하며, 약간의 수정만 필요합니다. 여러 필드가 포함된 레코드를 처리할 때 각 필드에 대한 매핑을 수동으로 지정하면 번지게 될 수 있습니다. 와일드카드를 사용하면 여러 필드에 자동으로 적용할 수 있는 일반화된 매핑이 가능해져 이러한 프로세스가 간소화됩니다.

매핑에서 별표를 사용하는 방법을 이해하기 위해 기본 시나리오를 고려해 보겠습니다.

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

이 구성은 입력의 모든 필드가 변경되지 않고 출력의 동일한 필드에 직접 매핑되는 기본 매핑을 보여줍니다. 별표(*)는 입력 레코드의 모든 필드와 일치하는 와일드카드 역할을 합니다.

이 컨텍스트에서 별표(*)가 작동하는 방식은 다음과 같습니다.

  • 패턴 일치: 별표는 경로의 단일 세그먼트 또는 여러 세그먼트와 일치할 수 있습니다. 이는 경로의 모든 세그먼트에 대한 자리 표시자 역할을 합니다.
  • 필드 일치: 매핑 프로세스 중에 알고리즘은 입력 레코드의 각 필드를 지정된 패턴에 inputs대해 평가합니다. 이전 예의 별표는 모든 가능한 경로와 일치하며, 입력의 모든 필드에 효과적으로 맞습니다.
  • 캡처된 세그먼트: 별표가 일치하는 captured segment경로의 부분을 입니다.
  • 출력 매핑: 출력 구성 captured segment 에서 별표가 나타나는 위치에 배치됩니다. 이는 captured segment가 별표로 제공된 자리 표시자를 채우면서 입력 구조가 출력에서 ​​유지된다는 것을 의미합니다.

또 다른 예는 와일드카드를 사용하여 하위 섹션을 일치시키고 함께 옮길 수 있는 방법을 보여 줍니다. 이 예는 JSON 개체 내의 중첩된 구조를 효과적으로 평면화합니다.

원래 JSON:

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

와일드카드를 사용하는 매핑 구성:

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

결과 JSON:

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

와일드카드 배치

와일드카드를 배치하는 경우 다음 규칙을 따라야 합니다.

  • 데이터 참조당 단일 별표: 단일 데이터 참조 내에서 하나의 별표(*)만 허용됩니다.
  • 전체 세그먼트 일치: 별표는 항상 경로의 전체 세그먼트와 일치해야 합니다. path1.partial*.path3과 같이 세그먼트의 일부만 일치시키는 데 사용할 수 없습니다.
  • 위치 지정: 별표는 데이터 참조의 다양한 부분에 배치할 수 있습니다.
    • 시작: *.path2.path3 - 여기서 별표는 다음으로 이어지는 모든 세그먼트와 일치합니다 path2.path3.
    • 중간: path1.*.path3 - 이 구성에서 별표는 사이의 path1 세그먼트와 path3.
    • 끝: path1.path2.* - 끝의 별표는 뒤에 있는 모든 세그먼트와 일치합니다 path1.path2.
  • 별표를 포함하는 경로는 작은따옴표(')로 묶어야 합니다.

다중 입력 와일드카드

원래 JSON:

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

와일드카드를 사용하는 매핑 구성:

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

결과 JSON:

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

다중 입력 와일드카드를 사용하는 경우 별표(*)는 모든 입력에서 Captured Segment 동일하게 일관되게 표시되어야 합니다. 예를 들어, *이 패턴 *.Max에서 Saturation을 캡처하는 경우 매핑 알고리즘은 해당 Saturation.Min이 패턴 *.Min과 일치할 것으로 예상합니다. 여기서 *은 첫 번째 입력의 Captured Segment로 대체되어 후속 입력에 대한 매칭을 안내합니다.

다음의 자세한 예를 살펴봅니다.

원래 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
    }
  }
}

와일드카드를 사용하는 초기 매핑 구성:

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

이 초기 매핑은 배열을 빌드하려고 합니다(예: <a0/>Opacity). 다음으로 인해 이 구성이 실패합니다.

  • 첫 번째 입력 *.MaxSaturation과 같은 세그먼트를 캡처합니다.
  • 매핑에서는 후속 입력이 동일한 수준에 있어야 한다고 예상합니다.
    • Saturation.Max
    • Saturation.Min
    • Saturation.Avg
    • Saturation.Mean

Mean 내에 중첩되어 Mid있으므로 Avg 초기 매핑의 별표가 이러한 경로를 올바르게 캡처하지 않습니다.

수정된 매핑 구성:

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

이 수정된 매핑은 필요한 필드를 정확하게 캡처합니다. 중첩된 Mid 개체를 포함할 경로를 올바르게 지정하여 별표가 JSON 구조의 여러 수준에서 효과적으로 작동하도록 합니다.

두 번째 규칙 및 특수화

다중 입력 와일드카드에서 이전 예제를 사용하는 경우 각 속성에 대해 두 개의 파생 값을 생성하는 다음 매핑을 고려합니다.

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

이 매핑은 ColorProperties 아래의 각 속성에 대해 두 개의 별도 계산(AvgDiff)을 만들기 위한 것입니다. 이 예제에서는 결과를 보여줍니다.

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

여기서 동일한 입력에 대한 두 번째 매핑 정의는 매핑을 위한 두 번째 규칙 역할을 합니다.

이제 특정 필드에 다른 계산이 필요한 시나리오를 고려해 보겠습니다.

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

이 경우 Opacity 필드에는 고유한 계산이 있습니다. 이러한 중복 시나리오를 처리하는 두 가지 옵션은 다음과 같습니다.

  • Opacity에 대한 두 매핑을 모두 포함합니다. 이 예제에서는 출력 필드가 다르므로 서로 재정의하지 않습니다.
  • Opacity에 대해 더 구체적인 규칙을 사용하고 더 일반적인 규칙을 제거합니다.

올바른 작업을 결정하는 데 도움이 되는 동일한 필드에 대한 특별한 경우를 고려합니다.

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

두 번째 정의에서 빈 output 필드는 출력 레코드에 필드를 쓰지 않음을 의미합니다(실제로는 Opacity를 제거함). 이 설정은 Second Rule보다는 Specialization에 더 가깝습니다.

데이터 흐름에 의한 중복 매핑의 해결:

  • 평가는 매핑 정의의 최상위 규칙부터 진행됩니다.
  • 새 매핑이 이전 규칙과 동일한 필드로 확인되면 다음 조건이 적용됩니다.
    • 와일드카드가 캡처한 세그먼트 수를 기준으로 해결된 각 입력에 대해 Rank가 계산됩니다. 예를 들어, Captured SegmentsProperties.Opacity이면 Rank는 2입니다. 이 값만 OpacityRank 있는 경우 1입니다. 와일드카드가 없는 매핑의 Rank는 0입니다.
    • 후자 규칙의 Rank가 이전 규칙보다 같거나 높으면 데이터 흐름은 이를 Second Rule로 처리합니다.
    • 그렇지 않으면 데이터 흐름은 구성을 .로 Specialization처리합니다.

예를 들어 빈 출력으로의 매핑 Opacity.Max 은 0입니다Rank.Opacity.Min 두 번째 규칙은 이전 규칙보다 낮 Rank 기 때문에 특수화로 간주되고 이전 규칙을 재정의하여 값을 Opacity계산합니다.

컨텍스트화 데이터 세트의 와일드카드

이제 예제를 통해 와일드카드와 함께 컨텍스트화 데이터 세트를 사용하는 방법을 살펴보겠습니다. 다음 레코드를 포함하는 position이라는 데이터 세트를 고려합니다.

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

이전 예에서는 이 데이터 세트의 특정 필드를 사용했습니다.

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

이 매핑은 BaseSalary 컨텍스트 데이터 세트에서 출력 레코드의 Employment 섹션으로 직접 복사됩니다. 프로세스를 자동화하고 데이터 세트의 모든 필드를 섹션에 position Employment 포함하려는 경우 와일드카드를 사용할 수 있습니다.

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

이 구성을 사용하면 position 데이터 세트 내의 모든 필드가 출력 레코드의 Employment 섹션에 복사되는 동적 매핑이 가능합니다.

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

마지막으로 알려진 값

속성의 마지막으로 알려진 값을 추적할 수 있습니다. 입력 필드를 접미사로 ? $last 사용하여 필드의 마지막으로 알려진 값을 캡처합니다. 속성에 후속 입력 페이로드의 값이 누락되면 마지막으로 알려진 값이 출력 페이로드에 매핑됩니다.

예를 들어 다음 매핑을 고려합니다.

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

이 예제에서는 마지막으로 알려진 값이 Temperature 추적됩니다. 후속 입력 페이로드에 값이 Temperature 포함되어 있지 않으면 마지막으로 알려진 값이 출력에 사용됩니다.