CEL-Dialekt für die Dokumentvalidierung

Bei der Validierung und Korrektur mit Document AI wird die Common Expression Language (CEL) verwendet, um eine flexible Datenvalidierung und ‑bearbeitung in Ihren Dokumentverarbeitungs-Workflows zu ermöglichen. Document AI bietet eine Reihe von benutzerdefinierten Funktionen, Makros und Verhaltensänderungen, die auf Daten zu Dokumententitäten zugeschnitten sind.

Auf Entitäten im CEL-Ausdruck zugreifen

Alle Ausdrücke werden anhand einer Stammvariablen namens doc ausgewertet, die aus Entitäten besteht, die Phrasen oder Eigenschaften des Dokuments sind. Diese Entitäten folgen eng der Struktur der Entitäten Ihres extrahierten Dokuments.

Eine extrahierte Entität enthält viele Eigenschaften, aber nur drei davon sind für die CEL-Auswertung verfügbar.

  • mention_text: Der extrahierte Rohtext, wie er in einer extrahierten Entität vorhanden ist. Der Standardwert ist ein leerer String.
  • normalized_value: Normalisierter Erwähnungstext, wie er in einer extrahierten Entität vorhanden ist. Der Standardwert ist „null“. Weitere Informationen zur Normalisierung
  • bounding_poly: Ein spezielles Objekt, das eine Darstellung der Platzierung der extrahierten Einheit im Dokument enthält und für Abgleichsprüfungen verwendet wird. Der Standardwert ist null.

Datenmodell

Die genaue Struktur einer extrahierten Entität in der doc-Karte hängt von zwei Faktoren ab. Erstens: Ist die Struktur ein konkreter Wert wie eine Zahl oder ein Nur-Text oder ein komplexes Objekt? Der zweite Faktor ist, ob der Ereignistyp „einzeln“ oder „mehrfach“ ist. Weitere Informationen finden Sie unter OccurrenceType.

Ein wichtiges Merkmal des Validierungsdatenmodells ist, dass jede im Schema definierte, aber nicht aus dem Dokument extrahierte Entität automatisch mit Standardwerten gefüllt wird. Dadurch können Sie die meisten expliziten Nullprüfungen in Ihren CEL-Ausdrücken überspringen, was Ihre Validierungsausdrücke erheblich vereinfacht. Sie müssen nur explizit Nullprüfungen schreiben, um sicherzustellen, dass eine ausgewählte Entität tatsächlich extrahiert wurde.

Beispiele für Endknotenentitäten

In den folgenden Abschnitten wird beschrieben, wie Sie auf die Entitäten in einer Blattentität zugreifen, die keine verschachtelten untergeordneten Entitäten enthält. Blattentitäten enthalten direkt einen Wert.

Blattentität mit einem einzelnen Vorkommen

Dies ist der einfachste Fall, bei dem OccurrenceType von OPTIONAL_ONCE oder REQUIRED_ONCE verwendet wird. Die Entität wird als Objekt mit den drei Standardattributen dargestellt.

Ein Beispiel für den Zugriff auf diese Werte ist doc.invoice_date.normalized_value.

Sie hat die folgende Struktur:

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

Und Standardwert:

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

Blattknoten mit mehreren Vorkommen

Dieser Fall gilt für Blatttypen, die mehrmals vorkommen können und einen OccurrenceType-Wert von OPTIONAL_MULTIPLE oder REQUIRED_MULTIPLE haben. In einer Liste mit Fälligkeitsdaten für Zahlungen wird sie beispielsweise als Objekt dargestellt, wobei jede Eigenschaft eine Liste der entsprechenden Werte aus allen Vorkommen enthält. Attribute wie mention_text, normalized_value und bounding_poly können also mehrere Einheiten haben.

Ein Beispiel für den Zugriff auf diese Werte ist doc.payment_due_dates.normalized_value[0].

Sie hat die folgende Struktur:

  "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]
  }

Und Standardwert:

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

Verschachtelte Entitäten

Eine verschachtelte Entität ist ein Container für andere Entitäten, die ihre „untergeordneten Elemente“ sind.

Verschachtelte Entität mit einem Vorkommen

Wenn eine verschachtelte Entität nur einmal vorkommt, z. B. ein einzelnes receiver_address, wird sie als Objekt dargestellt, wobei die Schlüssel die Namen der untergeordneten Entitäten sind.

Ein Beispiel für den Zugriff auf diese Werte ist doc.receiver_address.city.mention_text.

Sie hat die folgende Struktur:

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

Und Standardwert:

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

Geschachtelte Einheit mit mehreren Vorkommen

Wenn eine verschachtelte Entität mehrmals vorkommen kann, wird sie als Liste von Objekten dargestellt. Jedes Objekt in der Liste stellt eine vollständige Instanz der verschachtelten Einheit dar und enthält ihre untergeordneten Elemente.

Ein Beispiel für den Zugriff auf diese Werte ist doc.line_items[1].description.normalized_value.

Sie hat die folgende Struktur:

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

Und Standardwert:

  "line_items": []

Conversion-Tabelle für normalisierten Wert

In dieser Tabelle sehen Sie, wie der ausgewählte Datentyp der Schemaentität in den CEL-Datentyp normalized_value übersetzt wird.

Schemadatentyp CEL-Datentyp
Währung, Adresse string
Zahl, Geld double
Datum/Uhrzeit proto.Timestamp
Kästchen, Unterschrift bool
Nur Text

Beispielausdrücke

Hier sind einige Beispiel-CEL-Ausdrücke.

// 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)

Hier finden Sie weitere Beispiele für CEL-Logik, die Sie verwenden können.

// 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 != "")

Verhaltensänderungen

Der CEL-Dialekt von Document AI ändert einige Standardverhalten, um besser für Anwendungsfälle zur Dokumentverarbeitung geeignet zu sein.

Gleichheit auf Epsilon-Basis

Um den fehlenden Dezimaltyp in CEL zu berücksichtigen und gängige Ungenauigkeiten bei Gleitkommazahlen in Finanz- und numerischen Daten zu berücksichtigen, werden die Gleichheitsoperatoren (==) und Ungleichheitsoperatoren (!=) für numerische Typen (double, int) geändert. Anstelle der genauen Gleichheit wird ein auf Epsilon basierender Vergleich mit einer Toleranz von 1e-2 (0, 01) verwendet.

Betrachten Sie beispielsweise eine total_amount mit einem normalisierten Wert von 100.005.

Mit dem Ausdruck doc.total_amount.normalized_value == 100.0 ist das Ergebnis true, da abs(100.005 - 100.0) kleiner als 0.01 ist. Bei Standard-CEL würde false zurückgegeben.

Für den Ausdruck doc.total_amount.normalized_value == 100.02 ist das Ergebnis false. Das liegt daran, dass abs(100.005 - 100.02) größer als 0.01 ist.

Einschränkungen bei Stringfunktionen

Die Standard-CEL-Funktionen zur Stringbearbeitung können nur für die mention_text-Property einer Einheit verwendet werden. Diese Einschränkung sorgt dafür, dass Validierungsregeln einheitlich auf den Literaltextstring angewendet werden, wie er im Dokument angezeigt wird.

Die betroffenen Funktionen sind:

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

Hier ein gültiges Beispiel:

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

Hier ein Beispiel für einen ungültigen Befehl:

// 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.")

Zusätzliche Funktionen

In diesem Abschnitt werden nicht standardmäßige globale Funktionen und Member-Funktionen beschrieben, die in der Document AI CEL-Auswertungsumgebung verfügbar sind.

SUM-Funktion

### sum()

Berechnet die Summe einer Liste numerischer Elemente. Sie kann für Listen von Ganzzahlen oder Gleitkommazahlen aufgerufen werden. Nullwerte in der Liste werden ignoriert. Wenn die Liste nicht numerische Elemente enthält, löst die Funktion einen Fehler aus.

Signatur:<list>.sum()

Hier ein Beispiel für die Summe des normalisierten Werts mehrerer Positionen.

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

OR-Funktion

### or()

Gibt den ursprünglichen Wert zurück, wenn er nicht null ist. Andernfalls wird das zweite (Standard-)Argument zurückgegeben.

Signatur:<value>.or(<;default_value>)

Sie können damit beispielsweise einen Standardwert angeben, wenn ein optionales Feld fehlt.

// 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

Funktion für die vertikale Ausrichtung von Listen prüfen

### checkVerticalAlignment()

Gibt true zurück, wenn alle bounding_poly-Objekte vertikal ausgerichtet sind, und zwar in dem durch die Toleranz angegebenen Grad. Andernfalls wird ein Fehler zurückgegeben, der beschreibt, welche Einheiten nicht ausgerichtet sind.

Die Toleranz ist ein optionales Argument, das die Überschneidung eines Begrenzungspolygons mit dem automatisch ausgewählten, am besten ausgerichteten Begrenzungspolygon angibt. Der Wert 0 bedeutet, dass sich die Begrenzungspolygone nicht überschneiden, der Wert 1, dass sie identisch sind.

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

So können Sie beispielsweise dafür sorgen, dass alle extrahierten Einheiten in einer einzigen Spalte bleiben.

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

Funktion für die horizontale Ausrichtung prüfen

### checkHorizontalAlignment()

Gibt true zurück, wenn alle bounding_poly-Objekte horizontal auf einen durch die Toleranz angegebenen Grad ausgerichtet sind. Andernfalls wird ein Fehler zurückgegeben, der beschreibt, welche Einheiten nicht ausgerichtet sind.

Die Toleranz ist ein optionales Argument, das die Überschneidung eines Begrenzungspolygons mit dem automatisch ausgewählten, am besten ausgerichteten Begrenzungspolygon angibt. Der Wert 0 bedeutet, dass sich die Begrenzungspolygone nicht überschneiden, und der Wert 1 bedeutet, dass sie identisch sind.

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

So können Sie beispielsweise dafür sorgen, dass alle extrahierten Entitäten in einer einzigen Zeile bleiben.

// 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)))

Zusätzliche Makros

In diesem Abschnitt werden nicht standardmäßige Makros beschrieben, die in der CEL-Evaluierungsumgebung von Document AI verfügbar sind.

Weitere Informationen zu Makros finden Sie unter Sprachdefinition: Makros.

Makro zum Verringern

### reduce()

Mit dem Makro reduce können Sie kumulative Vorgänge für eine Liste ausführen.

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

  • iterator_name: Ein Variablenname für das Element, das in jeder Iteration verarbeitet wird.
  • accumulator_name: Ein Variablenname für den Wert, in dem das Ergebnis akkumuliert wird.
  • initial_value: Der Anfangswert des Akkumulators.
  • loop_expression: Ein Ausdruck, der definiert, wie der Akkumulator in jedem Schritt aktualisiert wird.

Hier ein Beispiel für die Verwendung von Makros:

// 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-Erweiterungsbibliotheken

Zusätzlich zu den benutzerdefinierten Funktionen sind die folgenden Standard-CEL-Erweiterungsbibliotheken verfügbar.

  • Listen: Bietet Funktionen für die Listenbearbeitung: range, distinct, flatten, reverse, sort, slice. Weitere Informationen finden Sie unter Listen.
  • Mathematische Funktionen: Bietet erweiterte mathematische Funktionen wie math.greatest, math.least, math.abs. Weitere Informationen finden Sie unter Mathematik.

Nächste Schritte

Vortrainierte Prozessoren