문서 검증을 위한 CEL 언어

Document AI 검증 및 수정은 Common Expression Language (CEL)을 활용하여 문서 처리 워크플로 내에서 유연한 데이터 검증 및 조작을 지원합니다. Document AI는 문서 엔티티 데이터에 맞게 조정된 맞춤 함수, 매크로, 동작 수정사항을 제공합니다.

CEL 표현식에서 엔티티 액세스

모든 표현식은 문서에 속하는 문구 또는 속성인 항목으로 구성된 doc라는 루트 변수를 기준으로 평가됩니다. 이러한 항목은 추출된 문서의 항목 구조를 따릅니다.

추출된 항목에는 여러 속성이 포함되지만 CEL 평가에 사용할 수 있는 속성은 3개뿐입니다.

  • mention_text: 추출된 항목에 있는 그대로 추출된 텍스트입니다. 기본값은 빈 문자열입니다.
  • normalized_value: 추출된 항목에 표시된 정규화된 멘션 텍스트입니다. 기본값은 null입니다. 정규화에 대해 자세히 알아보세요.
  • bounding_poly: 추출된 엔티티의 문서 내 위치 표현을 포함하고 정렬 확인에 사용되는 특수 객체입니다. 기본값은 null입니다.

데이터 모델

doc 맵 내에서 추출된 항목의 정확한 구조는 두 가지 요소에 따라 달라집니다. 첫 번째는 구조가 숫자나 일반 텍스트와 같은 구체적인 값인지 아니면 복잡한 객체인지입니다. 두 번째 요소는 발생 유형이 단일인지 여러 개인지입니다. 자세한 내용은 OccurrenceType를 참조하세요.

유효성 검사 데이터 모델의 주요 기능은 스키마에 정의되어 있지만 문서에서 추출되지 않은 항목이 기본값으로 자동 채워진다는 것입니다. 이 설계를 사용하면 CEL 표현식에서 명시적 null 검사를 대부분 건너뛸 수 있으므로 유효성 검사 표현식이 크게 간소화됩니다. 선택한 항목이 실제로 추출되었는지 확인하기 위해 null 검사를 명시적으로 작성하기만 하면 됩니다.

리프 항목 예시 케이스

다음 섹션에서는 중첩된 하위 항목이 없는 리프 항목의 항목에 액세스하는 방법을 설명합니다. 리프 항목은 값을 직접 보유합니다.

단일 발생이 있는 리프 항목

OPTIONAL_ONCE 또는 REQUIRED_ONCEOccurrenceType를 사용하는 가장 기본적인 사례입니다. 항목은 세 가지 표준 속성이 포함된 객체로 표현됩니다.

이러한 값에 액세스하는 방법의 예는 doc.invoice_date.normalized_value입니다.

구조는 다음과 같습니다.

  "invoice_date": {
    "mention_text": "1",
    "normalized_value": 1.0,
    "bounding_poly": bounding_poly_object
  }

기본값:

  "invoice_date": {
    "mention_text": "",
    "normalized_value": null,
    "bounding_poly": null
  }

여러 번 발생하는 리프 항목

이 사례는 여러 번 발생할 수 있고 OccurrenceTypeOPTIONAL_MULTIPLE 또는 REQUIRED_MULTIPLE인 리프 항목에 적용됩니다. 예를 들어 결제 기한 목록에서 모든 항목의 해당 값 목록을 보유하는 각 속성이 객체로 표시됩니다. 따라서 mention_text, normalized_value, bounding_poly과 같은 속성에는 여러 항목이 있을 수 있습니다.

이러한 값에 액세스하는 방법의 예는 doc.payment_due_dates.normalized_value[0]입니다.

구조는 다음과 같습니다.

  "payment_due_dates": {
    "mention_text": ["Mar 1, 2024", "Apr 1, 2024"],
    "normalized_value": [null, proto.timestamp(2024-04-01)],
    // Note: If a value is not normalized, it is stored as a null.
    "bounding_poly": [bounding_poly_object,bounding_poly_object]
  }

기본값:

  "payment_due_dates": {
    "mention_text": [],
    "normalized_value": []
    "bounding_poly": []
  }

중첩된 항목

중첩된 항목은 '하위 요소'인 다른 항목의 컨테이너입니다.

발생 횟수가 1인 중첩 항목

중첩된 항목이 한 번만 발생하는 경우(예: 단일 receiver_address) 키가 하위 항목의 이름인 객체로 표현됩니다.

이러한 값에 액세스하는 방법의 예는 doc.receiver_address.city.mention_text입니다.

구조는 다음과 같습니다.

  "receiver_address": {
    "street": {
      "mention_text": "123 Main St",
      "normalized_value": "123 Main St",
      "bounding_poly": bounding_poly_object
    }
    }

기본값:

  "receiver_address": {
    "street": {
      "mention_text": "",
      "normalized_value": null,
      "bounding_poly": null
    }
    }

여러 번 발생하는 중첩된 항목

중첩된 항목이 여러 번 발생할 수 있는 경우 객체 목록으로 표시됩니다. 목록의 각 객체는 중첩된 엔티티의 전체 인스턴스를 나타내며 하위 요소를 포함합니다.

이러한 값에 액세스하는 방법의 예는 doc.line_items[1].description.normalized_value입니다.

구조는 다음과 같습니다.

  "line_items": [
    {
      "description": { "mention_text": "Product A", ... },
      "quantity": { "mention_text": "2", ... }
    },
    {
      "description": { "mention_text": "Service B", ... },
      "quantity": { "mention_text": "5", ... }
    }
  ]

기본값:

  "line_items": []

정규화된 가치의 전환 표

이 표는 선택한 스키마 항목 데이터 유형이 CEL normalized_value 데이터 유형으로 변환되는 방식을 보여줍니다.

스키마 데이터 유형 CEL 데이터 유형
통화, 주소 string
숫자, 금액 double
날짜/시간 proto.Timestamp
체크박스, 서명 bool
일반 텍스트 해당 사항 없음

표현식 예시

다음은 CEL 표현식의 몇 가지 예입니다.

// Leaf entity with a single occurrence: Get the invoice ID string
doc.invoice_id.normalized_value == "INV-12345"

// Leaf entity with multiple occurrences: Get the first payment term from the list
doc.payments.mention_text[0].matches('^\d+$')

// Nested entity with one occurrence: Access a child entity of a single nested entity
doc.receiver_address.name.normalized_value.star
tsWith("John")
// Nested entity with multiple occurrences: Access a child of a specific item in a list of nested entities
doc.line_items[1].description.normalized_value == "Premium Gadget"

// Advanced: Sum the total of all line items
doc.line_items.map(item, item.total.normalized_value).sum() == 275.0

// Advanced: Check if any line item has a quantity greater than 1
doc.line_items.exists(item, item.quantity.normalized_value > 1.0)

다음은 사용할 수 있는 CEL 논리의 다른 예입니다.

// Ensure due date is after invoice date
doc.due_date.normalized_value > doc.invoice_date.normalized_value

// Cross list validation: ensure that each employer_contribution 
// has a corresponding employee deduction
 doc.employer_contribution.size() == doc.employee_deduction.size() && lists.range(doc.employer_contribution.size()).all(i,doc.employee_deduction[i].current_amount.mention_text != "" && doc.employer_contribution[i].current_amount.mention_text != "")

동작 변경사항

Document AI의 CEL 언어는 문서 처리 사용 사례에 더 적합하도록 일부 표준 동작을 수정합니다.

엡실론 기반 등식

CEL에 10진수 유형이 없고 금융 및 숫자 데이터의 일반적인 부동 소수점 부정확성을 고려하기 위해 숫자 유형 (double, int)의 등호(==) 및 부등호 (!=) 연산자가 수정되었습니다. 정확한 등호 대신 허용 오차 1e-2(0.01)를 사용한 엡실론 기반 비교를 사용합니다.

예를 들어 정규화된 값이 100.005total_amount을 생각해 보겠습니다.

doc.total_amount.normalized_value == 100.0 표현식을 사용하면 결과는 true입니다. abs(100.005 - 100.0)0.01보다 작기 때문입니다. 표준 CEL은 false을 반환합니다.

doc.total_amount.normalized_value == 100.02 표현식의 결과는 false입니다. abs(100.005 - 100.02)0.01보다 크기 때문입니다.

문자열 함수 제한사항

표준 CEL 문자열 조작 함수는 엔티티의 mention_text 속성에서만 작동하도록 제한됩니다. 이 제한사항은 문서에 표시되는 리터럴 텍스트 문자열에 유효성 검사 규칙이 일관되게 적용되도록 합니다.

영향을 받는 함수는 다음과 같습니다.

  • contains()
  • endsWith()
  • startsWith()
  • matches()

다음은 올바른 예입니다.

// Checks if the extracted currency symbol is a dollar sign.
doc.total_amount.mention_text.startsWith("$")

다음은 잘못된 명령어의 예입니다.

// This will produce a validation error upon save because contains() is not
// being used on a .mention_text field.
doc.supplier_name.normalized_value.contains("Inc.")

추가 기능

이 섹션에서는 Document AI CEL 평가 환경에서 사용할 수 있는 비표준 전역 함수와 멤버 함수를 설명합니다.

Sum 함수

### sum()

숫자 요소 목록의 합계를 계산합니다. 정수 또는 double 목록에서 호출할 수 있습니다. 목록의 null 값은 무시됩니다. 목록에 숫자가 아닌 요소가 포함되어 있으면 함수에서 오류가 발생합니다.

서명: <list>.sum()

다음은 여러 항목의 정규화된 값을 합산하는 예입니다.

// Calculates the sum of all line item amounts.
doc.line_item_amounts.normalized_value.sum()

OR 함수

### or()

원래 값이 null이 아니면 원래 값을 반환하고, null이면 두 번째(기본) 인수를 반환합니다.

서명: <value>.or(<;default_value>)

예를 들어 선택적 필드가 누락될 수 있는 경우 기본값을 제공하는 데 사용할 수 있습니다.

// If the tax amount is not found, use a default of 0.0 for calculation.
doc.tax_amount.normalized_value.or(0.0) > 5.0

목록 세로 정렬 기능 확인

### checkVerticalAlignment()

모든 bounding_poly 객체가 허용 범위에 의해 지정된 각도로 수직 정렬되면 true를 반환합니다. 그렇지 않으면 정렬되지 않은 항목을 설명하는 오류를 반환합니다.

허용 오차는 선택사항인 인수로, 경계 폴리와 자동으로 선택된 최적의 정렬 경계 폴리의 중첩을 지정합니다. 0은 경계 폴리가 교차하지 않음을 의미하고 1은 경계 폴리가 동일함을 의미합니다.

서명: checkVerticalAlignment([<;bounding_poly>,...],tolerance=0.8)

예를 들어 이를 사용하여 추출된 모든 항목을 단일 열 내에 유지할 수 있습니다.

// Make sure that all extracted quantities are in the same column
checkVerticalAlignment(doc.line_items.map(li,li.quantity.bounding_poly))

수평 정렬 함수 확인

### checkHorizontalAlignment()

모든 bounding_poly 객체가 허용 오차로 지정된 정도까지 수평으로 정렬되면 true를 반환합니다. 그렇지 않으면 정렬되지 않은 항목을 설명하는 오류가 반환됩니다.

허용 오차는 자동으로 선택된 최적의 정렬 경계 폴리와 경계 폴리의 중복을 지정하는 선택적 인수입니다. 0은 경계 다각형이 교차하지 않음을 의미하고 1은 경계 다각형이 동일함을 의미합니다.

서명: checkHorizontalAlignment([<;bounding_poly>,...],tolerance=0.6)

예를 들어 이를 사용하여 추출된 모든 항목을 단일 행 내에 유지할 수 있습니다.

// For all line items make sure that each extracted line item's
// children are in the same row. For example, if line item has
// quantity and description properties, it makes sure they are in 
// a single row for each respective line item.
doc.line_items.all(li, checkHorizontalAlignment(li.map(col,li[col].bounding_poly)))

추가 매크로

이 섹션에서는 Document AI CEL 평가 환경에서 사용할 수 있는 비표준 매크로를 설명합니다.

매크로에 대한 자세한 내용은 언어 정의: 매크로를 참고하세요.

매크로 줄이기

### reduce()

reduce 매크로를 사용하여 목록에 누적 작업을 실행합니다.

서명: <list>.reduce(<;iterator_name>, <;accumulator_name>, <;initial_value>, <;loop_expression>)

  • iterator_name: 각 반복에서 처리되는 요소의 변수 이름입니다.
  • accumulator_name: 결과를 누적하는 값의 변수 이름입니다.
  • initial_value: 누산기의 초기 값입니다.
  • loop_expression: 각 단계에서 누산기가 업데이트되는 방식을 정의하는 표현식입니다.

다음은 매크로 사용의 예입니다.

// Use reduce to sum up the quantities from all line items.
doc.line_items.reduce(item, running_total, 0.0, running_total + item.quantity.normalized_value)

// Result: 3.0
// Tip: this could also be done by concatenating map and sum:
doc.line_items.map(item,item.quantity.normalized_value).sum()

CEL 확장 프로그램 라이브러리

맞춤 기능 외에도 다음과 같은 표준 CEL 확장 프로그램 라이브러리를 사용할 수 있습니다.

  • 목록: 목록 조작을 위한 함수를 제공합니다(range, distinct, flatten, reverse, sort, slice). 자세한 내용은 목록을 참고하세요.
  • 수학: math.greatest, math.least, math.abs와 같은 확장된 수학 함수를 제공합니다. 자세한 내용은 수학을 참고하세요.

다음 단계

사전 학습된 프로세서에 대해 알아봅니다.