CEL-Dialekt für die Dokumentvalidierung

Die Validierung und Korrektur von Document AI nutzt die Common Expression Language (CEL), 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 Dokumententitätsdaten 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 Wortgruppen oder Attribute des Dokuments sind. Diese Entitäten entsprechen weitgehend der Struktur der Entitäten Ihres extrahierten Dokuments.

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

  • mention_text: Extrahierter Rohtext, wie er in einer extrahierten Entität vorhanden ist. Die Standardeinstellung 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 Entität 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-Zuordnung hängt von zwei Faktoren ab. Erstens: Ist die Struktur ein konkreter Wert, z. B. eine Zahl oder Nur-Text, oder ein komplexes Objekt? Der zweite Faktor ist, ob der Vorkommenstyp 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. Durch dieses Design 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.

Beispielfälle für Blattentitäten

In den folgenden Abschnitten wird beschrieben, wie Sie auf die Entitäten in einer Blattentität zugreifen, also einer Entität ohne verschachtelte untergeordnete Entitäten. 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 Standardeigenschaften 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
  }

Blattentität mit mehreren Vorkommen

Dieser Fall gilt für Blattentitäten, die mehrmals vorkommen können und einen OccurrenceType-Wert von OPTIONAL_MULTIPLE oder REQUIRED_MULTIPLE haben. In einer Liste von Fälligkeitsdaten für Zahlungen wird es beispielsweise als Objekt dargestellt, wobei jede Property eine Liste der entsprechenden Werte aus allen Vorkommen enthält. Attribute wie mention_text, normalized_value und bounding_poly können also mehrere Entitäten 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
    }
    }

Verschachtelte Entität 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 Entität 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": []

Konvertierungstabelle für normalisierte Werte

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

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

Beispielausdrücke

Hier sind einige CEL-Beispielausdrü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 sind weitere Beispiele für die 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 sie besser an Anwendungsfälle für die Dokumentverarbeitung anzupassen.

Epsilon-basierte Gleichheit

Da in CEL kein Dezimaltyp vorhanden ist und häufige Gleitkommaungenauigkeiten in Finanz- und numerischen Daten berücksichtigt werden müssen, werden die Gleichheits- (==) und Ungleichheitsoperatoren (!=) für numerische Typen (double, int) geändert. Anstelle einer genauen Gleichheit wird ein Epsilon-basierter Vergleich mit einer Toleranz von 1e-2 (0, 01) verwendet.

Angenommen, Sie haben einen total_amount mit dem normalisierten Wert 100.005.

Mit dem Ausdruck doc.total_amount.normalized_value == 100.0 ist das Ergebnis true. Das liegt daran, dass abs(100.005 - 100.0) kleiner als 0.01 ist. Standard-CEL würde false zurückgeben.

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 für Stringfunktionen

Die Standard-CEL-Funktionen zur Stringbearbeitung sind auf das Attribut mention_text einer Entität beschränkt. Diese Einschränkung sorgt dafür, dass Validierungsregeln einheitlich auf den literalen Textstring angewendet werden, so wie er im Dokument erscheint.

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 und Mitgliedsfunktionen beschrieben, die in der Document AI-CEL-Bewertungsumgebung verfügbar sind.

Summenfunktion

### sum()

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

Unterschrift: <list>.sum()

Hier ist ein Beispiel, in dem der normalisierte Wert mehrerer Werbebuchungen summiert wird.

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

ODER-Funktion

### or()

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

Unterschrift: <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

Vertikale Ausrichtungsfunktion für Checkliste

### checkVerticalAlignment()

Gibt true zurück, wenn alle bounding_poly-Objekte vertikal bis zu einem durch die Toleranz angegebenen Grad ausgerichtet sind. Andernfalls wird ein Fehler zurückgegeben, der beschreibt, welche Entitäten nicht übereinstimmen.

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

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

Sie können damit beispielsweise alle extrahierten Entitäten in einer einzigen Spalte speichern.

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

Funktion für horizontale Ausrichtung prüfen

### checkHorizontalAlignment()

Gibt true zurück, wenn alle bounding_poly-Objekte horizontal in einem durch die Toleranz angegebenen Grad ausgerichtet sind. Andernfalls wird ein Fehler zurückgegeben, der beschreibt, welche Entitäten nicht übereinstimmen.

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

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

Sie können damit beispielsweise alle extrahierten Entitäten in einer einzigen Zeile speichern.

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

### reduce()

Verwenden Sie das Makro reduce, um kumulative Vorgänge für eine Liste auszuführen.

Unterschrift: <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, der das Ergebnis akkumuliert.
  • initial_value: Der erste Wert für den Akkumulator.
  • 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.
  • Math: Bietet erweiterte mathematische Funktionen wie math.greatest, math.least, math.abs. Weitere Informationen finden Sie unter Mathematik.

Nächste Schritte

Informationen zur Fundierung