Abstrakte Wikipedia/Vorlagensprache für Wikifunctions
Vorschlag von Ariel Gutman und Maria Keet
Hinweis: Wenn du dich hauptsächlich für die Implementierung der Sprache interessierst, siehe den Abschnitt Implementierungen unten.
Das Ziel dieses Dokuments ist, eine Syntax für die Vorlagensprache vorzuschlagen, die im Projekt Abstrakte Wikipedia genutzt wird. Dies ist eine Ausarbeitung des Dokuments Architektur eines Systems zur Generierung natürlicher Sprache (NLG) und insbesondere des Bestandteils des “Vorlagen-Renderers”. Es kann auf der Wikifunctions-Plattform implementiert werden, indem es in "Kompositions"syntax umgewandelt wird oder in einer anderen Programmierumgebung, wie der Wikipedia-Scribunto-Umgebung und kann möglicherweise in anderen NLG-Systemen oder -Realisierern abgebildet oder umgewandelt werden.
Zentrale Änderungen im Vergleich zur ersten Version sind folgende: 1) eine Generalisierung des Realisierungsalgorithmus mit dem auf Wikifunctions zugeschnittenen im Anhang; 2) eine größere Genauigkeit bei einigen Designentscheidungen und das Eingehen auf Kommentare, Vorschläge und Beispiele von Mitgliedern der Gemeinschaft; 3) weitere anschauliche Erweiterungen, wie der Bezug zu anderen NLG-Realisierern und -Implementierungen.
Einführung
Van Deemter, Krahmer & Theune (2003)[1] beschreiben vorlagenbasierte Systeme wie folgt:
Vorlagenbasierte Systeme sind Systeme zur Generierung natürlicher Sprache, die ihre nicht linguistischen Eingaben direkt (d. h. ohne Zwischendarstellungen) auf die linguistische Oberflächenstruktur abbilden (vgl. Reiter und Dale (1997), S. 83-84[2]). Entscheidend ist, dass diese linguistische Struktur Lücken enthalten kann; eine wohlgeformte Ausgabe entsteht, wenn die Lücken gefüllt sind oder, genauer gesagt, wenn alle Lücken durch linguistische Strukturen ersetzt wurden, die keine Lücken enthalten.
Mit anderen Worten: Vorlagen können als Sequenzen von (statischem) Text verstanden werden, die Lücken enthalten, welche mit strukturiertem Inhalt gefüllt werden sollen (Mahlaza & Keet, 2021)[3] – diese Daten können beispielsweise aus einer Datenbank stammen, Wissen aus einer Ontologie seiner oder aus einer anderen Informationsquelle mit strukturiertem Inhalt stammen[Note 1] – oder sie können das Ergebnis einer Berechnung sein (möglicherweise die Ausgabe einer anderen realisierten Vorlage oder Funktion). Im vorgeschlagenen Design für das NLG-Modul für WF wurde ein zusätzliches Element hinzugefügt (nach Gutman et al., 2019;[4] 2022[5]), nämlich UD/SUD-Annotationen, die die Lücken der Vorlage miteinander verknüpfen, sodass die erhaltene Ausgabe nicht nur eine Zeichenkette aus Text, sondern ein syntaktischer Baum (oder ein Wald aus Bäumen) ist, der über die Lücken/Textteile definiert wird. Eine Lücke kann verschiedenen Organisationsebenen der Syntax einer Sprache entsprechen, nämlich einem Satzfragment, einem Wort, einem Unterwortmorphem, etc. Abhängig von der Syntax der natürlichen Zielsprache kann die Abhängigkeitsverknüpfung somit zwischen verschiedenen linguistischen Elementen des resultierenden Satzes gemäß der erforderlichen Granularität definiert werden.
Vorlagen können als kontextfreie grammatikalische Regeln umgestaltet werden, in denen der Text als Terminalsymbole und die Lücken als Nichtterminale dienen.[Note 2] Aus diesem Grund sind Vorlagen mindestens so ausdrucksstark wie CFG-basierte Systeme, die bekanntermaßen die meisten (aber nicht alle) Sprachphänomene abdecken. Der Unterschied zwischen den beiden liegt darin, dass die Designer eines Vorlagensystems zunächst nicht den Anspruch haben, für die Aufgabe der NLG linguistische Zwischendarstellungen zu verwenden. Tatsächlich kann es jedoch - wenn ein Vorlagensystem wächst und domänenunabhängig wird - Vorlagen erlangen, die einer formalen Grammatik der Zielsprache ähneln.
Im Folgenden stellen wir die vorgeschlagene Syntax für die Vorlagensprache für Wikifunktionen vor, zunächst als Freitextbeschreibung und anschließend unter Verwendung der formalen Notation als CFG und als logisches Modell, das als Diagramm dargestellt wird.[Note 3]
Syntax der Vorlagensprache
Eine Vorlage besteht aus einer Kombination aus:
- Freiem Text, einschließlich Satzzeichen und Lexemen (Wörtern) mit besonderem Verhalten;
- Lücken, die Interpolationen von Argumenten oder Aufrufe lexikalischer Funktionen und Untervorlagen sind, möglicherweise mit einer Abhängigkeitsbeziehung versehen.
Im Wesentlichen sieht ein nicht-normatives Diagramm mit den Schlüsselfunktionen der Vorlagensprache in ORM-Notation wie folgt aus:
Wir werden verschiedene Textteile (durch Leerzeichen getrennt) und Lücken gemeinsam als Vorlagenelemente bezeichnen. Jede Vorlage hat mindestens ein Element, wobei eine Untervorlage aus Implementierungsgründen leer sein kann.[Note 4] Die Vorlagensprache erlaubt die Angabe von Abhängigkeitsbögen zwischen den Lücken auf eine Art, bei der jede Vorlage als Baum über den beteiligten Lücken interpretiert werden kann. Da Untervorlagen nicht unbedingt mit diesem Baum verbunden sind und für eine Untervorlage eine eigene Wurzel angegeben sein kann, ermöglicht die Vorlagensprache die Angabe eines Waldes über die Lücken in den verschiedenen Untervorlagen, die dann mit der Wurzel der Übervorlage verbunden werden kann, wenn dies gewünscht ist. Die Absicht dieser Struktur besteht darin, eine Analyse der Abhängigkeitsgrammatik der produktiven Elemente in der Vorlage bereitzustellen, um die Realisierung zu leiten. Bekannte Frameworks für Abhängigkeitsgrammatik, die hierfür verwendet werden können, sind z. B. UD oder SUD. Beachte aber, dass diese normalerweise nur eine Analyse auf Wortebene ermöglichen, weshalb man bei morphemischen Lücken entweder ein anderes Grammatik-Framework verwenden oder das UD/SUD-Framework für Abhängigkeitsgrammatik erweitern müsste (wie z. B. kürzlich für UD vorgeschlagen[Note 5] oder das eng damit verbundene Katena).
Die Lücken werden durch geschweifte Klammern abgegrenzt und bestehen aus zwei Teilen, entsprechend der folgenden Syntax (eckige Klammern weisen auf Optionalität hin):
{[dependencyLabel:]invocation}
dependencyLabel:
Der optionale TeildependencyLabel
hat die folgende Syntax und besteht aus drei Elementen, gefolgt von einem Doppelpunkt:role[_index][<sourceLabel]:
role
gibt die (eingehende) Abhängigkeitsbeziehung der Lücke an und ist somit erforderlicher Bestandteil vondependencyLabel
.- Die Lücke, die als Wurzel (auch bekannt als Kopf) des Abhängigkeitsbaums fungiert, muss die Rolle
root
haben. Wenn in einer Vorlage Abhängigkeitsbezeichnungen genutzt werden, muss es genau eine Wurzel für den Satz geben. - Jede Rolle sollte einer Wikifunctions-Funktion entsprechen, die den Lemma-Baum umwandelt, um die Anwendung der gegebenen Rolle widerzuspiegeln; z.B. würde eine
subj
-Rolle die Subjekt-Verb-Übereinstimmung im Lemmabaum erzwingen. Diese Wikifunctions-Funktionen sind sprachspezifisch und können darüber hinaus Bezeichnungen in der besagten Sprache haben (z. B. "onderwerp" fürsubj
auf Niederländisch).
- Die Lücke, die als Wurzel (auch bekannt als Kopf) des Abhängigkeitsbaums fungiert, muss die Rolle
_index
ist eine optionale positive Ganzzahl nach einem Unterstrich, die die Unterscheidung mehrerer Lücken mit derselben Rolle ermöglicht (z. B. zwei Adjektivmodifikatoren:amod_1
,amod_2
).- Die Kombination aus
role
undindex
muss in jeder Vorlage einzigartig sein. - Wenn
role
selbst innerhalb einer Vorlage einzigartig ist, wird der Teilindex
nicht benötigt.
- Die Kombination aus
<sourceLabel
ist eine optionale Zeichenkette, die es ermöglicht, die Quelle der eingehenden Beziehung als Bezeichnung der Quelllücke anzugeben (was ihre Rolle darstellt, gefolgt vom optionalen Index). Wenn die Quelle nicht angegeben ist, wird implizit die Lückeroot
als Quelle verwendet.- Falls vorhanden, folgt auf den Teil der Abhängigkeitsbezeichnung ein Doppelpunkt, um ihn von
invocation
zu trennen.
invocation
kann einer von drei Typen sein:functionInvocation()
oderinterpolation
oder "string
"functionInvocation()
ist, wie der Name andeutet, ein Aufruf einer Funktion. Die Funktion kann zwischen ihren Klammern eine durch Kommas getrennte Liste von Argumenten annehmen, die selbstinvocation
s sein können, wie oben definiert. Beachte, dass die aufgerufene Funktion eine Untervorlage sein kann.interpolation
läuft darauf hinaus, die Lücke durch ein formales Argument der Vorlage zu füllen, was entweder das direkte Füllen der Lücke oder das Füllen des Arguments einer Funktion in der Lücke sein kann.[Note 6] Da das Argument im Allgemeinen nicht vom erforderlichen Rückgabetyp einer Lücke ist, ist eine implizite Umwandlungsfunktion erforderlich, damit dies funktioniert. Insbesondere Felder des Konstruktors, die selbst Unterkonstruktoren sind, führen bei der Interpolation dazu, dass ihre entsprechende Vorlage mit ihren Feldern aufgerufen wird, um Kompositionalität zu ermöglichen."string"
(jeder in Anführungszeichen eingeschlossene Text) entspricht der Verwendung derselben Zeichenkette wie freier Text, jedoch mit dem Unterschied, dass er mit einer Abhängigkeitsrolle bezeichnet sein muss.
Formalisierung als CFG
Die obige Syntax kann als Satz von CFG-Regeln formalisiert werden. Nichtterminale Symbole werden in Kursivschrift angegeben, während terminale Symbole (sowie Sätze von terminalen Symbolen) in monospace
angegeben werden.
Regel | Anmerkung |
---|---|
Template → Element | |
Element → { Slot} | Text | Element Element
|
|
Text → lexeme | punctuation | string
|
|
Slot → DependencyLabel : Invocation | Invocation
|
|
DependencyLabel → Label < SourceLabel | Label | root
|
|
Label → Role _ Index | Role
|
|
Role → … | endliche Menge von Rollennamen (ohne Wurzel), zum Beispiel übernommen von UD/SUD oder einer Erweiterung davon |
Index → 1 | 2 | …
|
endliche Menge positiver Ganzzahlen |
SourceLabel → Label | die Quellbezeichnung kann nur eine von den Bezeichnungen sein, die an anderer Stelle in der Vorlage als Bezeichnung verwendet wurden; hier werden hauptsächlich aus Gründen der Klarheit unterschiedliche Variablennamen verwendet |
Invocation → FunctionInvocation | Interpolation | String | |
FunctionInvocation → F(ArgumentList) | F() | eine Funktion mit einer variablen, möglicherweise leeren, Anzahl von Argumenten |
ArgumentList → invocation | invocation , ArgumentList | Jeder Aufruf kann als Argument fungieren |
F → functionName | templateName | Dies sind Namen von Funktionen (oder Vorlagen, die als Funktionen fungieren), die im System verfügbar sind |
Interpolation → interpolation
|
Satz von Namen (Felder im Konstruktor), die nur Terminale sind, daher hier Kurzschreibweise. |
String → "string "
|
offensichtlich auch eine Reihe von Terminalen (platziert innerhalb von “ und “ ), Kurzschreibweise.
|
Es gibt drei Funktionen auf Vorlagenebene, die mit jeder Vorlage aufgezeichnet werden müssen, sich jedoch nicht auf die Teile auswirken, die gerendert werden sollen. Sie sind:
- Der Name/Identifikator der Vorlage (erforderlich). In einem bestimmten Vorlagenbereich (der durch die Implementierung definiert wird) muss der Name einzigartig sein.
- Die Sprache, in der sie gerendert werden muss (erforderlich). Der Sprachcode sollte mit denen übereinstimmen, die in Wikidata genutzt werden, deren Verwendung geplant ist oder die möglicherweise in Zukunft genutzt werden.
- Die Vorbedingungen (optional). Ein Konstruktor kann mit mehr als einer Vorlage verknüpft sein, d. h. er kann über eine Liste mit zugehörigen Variantenvorlagen verfügen. Eine solche Liste von Variantenvorlagen enthält eine oder mehrere Vorbedingungen für die Auswahl der geeigneten Vorlage. Die erste Variantenvorlage, die die Vorbedingung(en) erfüllt, wird ausgewählt und realisiert. Zu den Vorbedingungen können Parameter gehören wie:
- Zufällige Startbedingungen oder Rangfolge von Vorlagenvarianten zum Injizieren von Variationen;
- Globale, sprachspezifische oder artikelspezifische Argumente für die Realisierung, wie etwa Grad der Formalität oder Ausführlichkeit;
- Ob bestimmte Felder des Konstruktors vorhanden sind oder nicht, oder Bedingungen für ihre Werte;
- Die grammatikalische Rolle einer Untervorlage innerhalb einer Übervorlage (wie durch eine Abhängigkeitsbezeichnung definiert).
- Und bei Bedarf können weitere spezifiziert werden.
Erweiterung durch Konditionalfunktionen
Man kann die Syntax um sogenannten ‘syntaktische Zucker‘ erweitern, bei dem es sich um Kurznotationen für komplexere Vorlagen mit mehreren Untervorlagen handelt. Beispielsweise kann der Funktionsaufruf der Lücke um eine oder mehrere Konditionalfunktionen erweitert werden, wie diese:
{[dependencyLabel:](invocation)[|conditionalFunction]*}
Der optionale Teil conditionalFunction
, der wiederholt werden kann, indem er mit einem Pipe-Symbol von der vorherigen Funktion getrennt wird, gibt einen Aufruf einer Konditionalfunktion an, der zusätzlich zu den angegebenen Argumenten das Ergebnis des Aufrufs vor dem Pipe-Symbol übernimmt. Mit anderen Worten handelt es sich um eine Funktion, die eine Liste von Lexemen übernimmt und eine modifizierte Liste von Lexemen zurückgibt. Einige mögliche Verwendungen sind:
- Dies ermöglicht das bedingte Eliminieren von Lücken (wobei möglicherweise ihre grammatikalischen Funktionen erhalten bleiben) oder die bedingte Pronominalisierung (Generierung verweisender Ausdrücke); z. B. “Simba der Löwe …; er …“ vgl. Wiederholung “Simba der Löwe … ; Simba …“
- Es ermöglicht eine größere Flexibilität bei der Satzstruktur, um die Auswahl zwischen alternativen Wörtern in einer Lücke zu erleichtern, wie die häufige Neuordnung von Sätzen; z. B. “Wegen x haben wir y gemacht“ und “Wir haben y gemacht wegen x“.
- und möglicherweise andere Operationen.
Der Grund für diese Syntax statt der einfachen Zusammensetzung von Funktionen besteht darin, die Lesbarkeit der Vorlage zu verbessern, da der Hauptteil invocation
klar die Art des gerenderten Ergebnisses angeben sollte, das wir in der Lücke erwarten. Ohne diesen syntaktischen Zucker könnte man eine Funktion in die andere einbetten, was {ConditionalFunction(invocation, conditional_arguments)}
ergeben würde oder eine bedingte Ebene über der (Unter-)Vorlagenauswahl hinzufügen, um solche Vorbedingungen verarbeiten zu können.
Beispiele für die Syntax finden sich weiter unten.
Kern-Funktionen
Ein Kernelement der Vorlagensprache sind die Funktionsaufrufe innerhalb der Lücken. Diese Funktionsaufrufe sollten entweder Lexeme (Paradigmen flektierter Formen, die mit grammatikalischen Funktionen verbunden sind, ähnlich wie Wikidata-Lexeme) oder teilweise spezifizierte syntaktische Bäume von Lexemen zurückgeben, wobei das Wurzellexem jedes Unterbaums minimal angegeben ist.
Die Kern-Funktionen der Vorlagensprache geben jedoch einzelne Lexeme zurück. Diese Kern-Funktionen werden von Beitragenden der Abstrakten Wikipedia geschrieben, daher gibt es keine geschlossene Liste. Beispiele für Funktionen, die im Voraus oder im Laufe der Zeit als Kern-Funktionen betrachtet werden können, können sein:
Lexeme(L-id, …)
: Ruft ein Wikidata-Lexem ab, das mit einerL-id
(in einer bestimmten Sprache) verknüpft ist und wandelt es in den Lexemtyp um. Weitere Argumente können Q-IDs grammatikalischer Funktionen sein, die die Formwahl einschränken.Label(entity)
oderLabel(entity, language)
: Ruft die mit einerQ-id
verknüpfte Bezeichnung in einer bestimmten Sprache ab, die standardmäßig die Realisierungssprache ist, falls nicht anders angegeben.Cardinal(integer)
: Erstellt ein Lexem aus der Ganzzahl (möglicherweise buchstabiert) mit der entsprechenden grammatikalischen Zahl (Singular/Plural/etc.)[Note 7]Ordinal(integer)
: Erstellt ein Lexem, das der gewünschten Ordinalzahl entspricht (möglicherweise mit Flexionen, abhängig von der Sprache).TemplateText(string)
: Erstellt ein Lexem, das der eingegebenen Zeichenkette entspricht.
Zusätzlich können Funktionen implementiert werden, die bestimmten semantischen Domänen entsprechen, zum Beispiel:
Person(entity):
WieLabel
, füllt aber auch das grammatikalische Geschlecht entsprechend dem Geschlecht der Person aus, wodurch möglicherweise auch pronominalisierte Lexemformen entstehen.
Sprachspezifische Funktionsausführung
Alle oben genannten Funktionen können (und werden höchstwahrscheinlich auch) eine sprachspezifische Implementierung haben. Wie die sprachspezifische Implementierung ausgewählt wird, hängt von der Implementierung ab.
Behandlung von Anmerkungen
Möglicherweise möchten man Anmerkungen zu einer Vorlage oder einem Element einer Vorlage hinzufügen. In der aktuellen Spezifikation gibt es keine separaten Anmerkungsfelder für die Elemente. Sofern gewünscht, kann jede Implementierung Bestimmungen für Kommentare hinzufügen, so wie Kommentare im Code hinzugefügt werden: Du kannst sie an einer beliebigen Stelle in der Spezifikation platzieren und ihnen ein oder mehrere geeignete reservierte Zeichen voranstellen. Diese reservierte Zeichenkette hängt von der Implementierung ab, in der die Vorlagenspezifikationen gespeichert sind; z. B. mit // kommentiere hier
, wie in der CFG-Spezifikation oben genutzt, % kommentiere hier
oder <!-- kommentiere hier -->
. Beispielsweise werden in Wikifunctions auch Kommentare auf der Seite der Funktion angezeigt, die auch für Vorlagen oder eine andere zusätzliche Schnittstellenkomponente übernommen werden könnten.
Realisierungsalgorithmus
Die Realisierung einer mit der oben genannten Notation spezifizierten Vorlage erfolgt in fünf verschiedenen Phasen.
Phase 1
Alle Vorlagenelemente werden durch Auswertung ihres Inhalts erweitert: Textelemente, Zeichenketten von Lücken und Interpolationen von Lücken werden in Lexeme umgewandelt (entweder mit einer generischen oder einer sprachspezifischen Funktion)[Note 8] und alle Funktionen von Lücken werden mit ihren Argumenten ausgewertet. Beachte, dass bei der Auswertung von Untervorlagen diese bis zu Phase 2 rekursiv ausgewertet werden müssen (detailliert unten).
Die Auswertung jedes Textelements oder einer Lücke sollte entweder den Datentyp Lexem oder Lexemliste ergeben:
- Ein Lexem besteht aus einer Sammlung von Flexionsformen, von denen jede ihre eigene Schreibweise hat, die mit einer Liste grammatikalischer Funktionen verbunden ist, sowie mit eine Liste gemeinsamer grammatikalischer Funktionen (die auf alle Formen anwendbar sind oder diese einschränken). Jede grammatikalische Funktion besteht aus einem Identifikator (z. B. “Singular“), dem eine grammatikalische Kategorie (z. B. “Zahl“) zugeordnet ist. Unter diesen grammatikalischen Funktionen sollte eine Funktion Teil der Sprache obligatorisch sein. Beachte, dass hinsichtlich der oben genannten Begriffe einige Verwirrung herrscht, da verschiedene Quellen den Begriff Funktion entweder als Kategorie oder als spezifischen Wert einer Kategorie verwenden (siehe Kibort & Corbett, 2008,[6] für eine Diskussion dieser Terminologie). Hier verwenden wir den Begriff Funktion im engeren Sinne zur Bezeichnung des Werts einer Kategorie (z. B. Plural) und im weiteren Sinne (fett geschrieben) zur Bezeichnung des oben genannten Datentyps mit Angabe sowohl der Kategorie als auch des zugewiesenen Werts.
- Alle Textelemente und die meisten Kern-Funktionen sollten zum Lexem-Datentyp ausgewertet werden.
- Eine Lexemliste ist einfach eine geordnete Liste von Elementen, von denen eines als Wurzel der Liste identifiziert wird. Jedes Element ist selbst entweder ein Lexem oder eine Lexemliste. Dies bedeutet, dass eine Lexemliste ein teilweise spezifizierter Baum von Lexemen ist. Durch rekursives Eintauchen in die Wurzel einer Lexemliste gelangt man schließlich zu einem einzelnen Lexem, das als Wurzellexem der Liste bezeichnet wird.
- Die Auswertung von Untervorlagen sollte im Allgemeinen eine Lexemliste ergeben (außer in dem Sonderfall, bei dem die Untervorlage zu einem einzelnen Lexem ausgewertet wird), wobei jedes Element in dieser Liste einem Element der Untervorlage entspricht. Darüber hinaus sollte das Element, dem die Bezeichnung
root
gegeben wird, dem Element entsprechen, das als die Wurzel der Liste identifiziert wird.
- Die Auswertung von Untervorlagen sollte im Allgemeinen eine Lexemliste ergeben (außer in dem Sonderfall, bei dem die Untervorlage zu einem einzelnen Lexem ausgewertet wird), wobei jedes Element in dieser Liste einem Element der Untervorlage entspricht. Darüber hinaus sollte das Element, dem die Bezeichnung
Phase 2
In dieser Phase werden die Abhängigkeitsbezeichnungen der Vorlage ausgewertet. Die Reihenfolge der Auswertung ist unerheblich. Für jede Vorlagen-Lücke mit einer Bezeichnung nennen wir die Lücke selbst die Ziel-Lücke. Die Lücke, auf die sich die Lückenbezeichnung bezieht, wird als Quell-Lücke bezeichnet. Wenn keine Lückenbezeichnung vorhanden ist, wird die Quell-Lücke immer als Wurzel-Lücke der Vorlage verwendet (die, die durch die Bezeichnung root
identifiziert wird).
Das Ziel-Lexem ist das Lexem, das sich aus der Auswertung der Ziel-Lücke ergibt. Wenn diese Auswertung eine Lexemliste ergibt, wählen wir das Wurzellexem der Liste aus. Ebenso finden wir das Quell-Lexem.
Jede Abhängigkeitsbezeichnung sollte einer Funktion entsprechen, die als Eingabeargument zwei Lexem-Argumente akzeptiert, nämlich das Quell- und das Ziel-Lexem. Wenn es keine solche Funktion gibt, ist die Abhängigkeitsbezeichnung inaktiv. Um sicherzustellen, dass die Reihenfolge der Auswertung von Abhängigkeitsbezeichnungsfunktionen unerheblich ist, darf jede dieser Funktionen nur die folgenden drei Operationen verwenden:
- Überprüfung der Wortart des Lexems in Bezug auf die Abhängigkeitsbezeichnung (d. h. die Wortart sollte von einem Wortarttyp subsumiert werden).[Note 9]
- Teilen einiger Funktionen, identifiziert durch ihre Kategorien, zwischen den beiden Lexemen mittels Vereinheitlichung. Funktionen können nur dann vereinheitlicht werden, wenn sie gemäß einer bestimmten Hierarchie von Funktionen kompatibel sind. Sobald sie vereinheitlicht sind, werden sie im gesamten Lexem gemeinsam genutzt und jede spätere Änderung dieser Funktion durch eines der Lexeme (z. B. durch eine andere Abhängigkeitsbeziehungsfunktion) würde sich auch auf das andere Lexem auswirken.
- Modifizieren einiger Funktionen eines der Lexeme mit einem vorgegebenen Wert, wie Zuweisen von “Nominativ“ zu dem Element, das das Subjekt ist. Dies wird erreicht, indem die durch seine Kategorie identifizierte Funktion mit einem vorgegebenen Wert vereinheitlicht wird.
Beachte, dass die oben genannten Vereinheitlichungsoperationen nur auf die grammatikalischen Funktionen auf Lexemebene und nicht auf die Funktionen auf der Formebene angewendet werden. Nach diesem Stadium gelten die gemeinsamen grammatikalischen Funktionen jedes Lexems nicht unbedingt für alle Formen, sondern stellen vielmehr grammatikalische Einschränkungen für die Formen dar.
Phase 3
An diesem Punkt wird die Baumstruktur der Lexemliste nicht mehr benötigt und die Liste kann abgeflacht werden. Anschließend wird die resultierende Lexemliste der Vorlage durchlaufen und die Liste der Formen jedes Lexems gemäß den grammatikalischen Einschränkungen beschnitten und im Falle einer grammatikalischen Unterspezifikation[Note 10] nach einer vorgegebenen relativen Bedeutung grammatikalischer Kategorien und Funktionen lexikographisch sortiert, um sicherzustellen, dass Formen mit Standard- oder nicht markierten Funktionen (z. B. “Nominativ”) Vorrang haben.
Die Beschneidung der Formen kann je nach Konsistenz und Sauberkeit der lexikalischen Daten auf zwei Arten erfolgen:
- Wenn bekannt ist, dass die lexikalischen Daten in dem Sinne konsistent und sauber sind, dass es Formen für alle linguistisch möglichen Kombinationen von Funktionen gibt und genau die notwendigen grammatikalischen Kategorien vertreten sind, kann eine strikte Beschneidung erfolgen, bei der nur Formen beibehalten werden, die die Einschränkungen subsumieren.[Note 11] Dies bedeutet insbesondere, dass, wenn eine Form eine grammatikalische Kategorie hat, die in den Einschränkungen nicht erwähnt wird, sie beschnitten wird. Unter den resultierenden Formen entfernen wir außerdem die Formen, die alle anderen Formen in dieser Liste subsumieren.[Note 12] Dies läuft darauf hinaus, die spezifischsten Formen (aus Sicht der Funktionshierarchie) zu finden, die die Einschränkungen noch berücksichtigen.
- Wenn die lexikalischen Daten nur teilweise bekannt oder ‘unsauber’ sind, kann ein Realisierer eine alternative Best-Effort-Strategie implementieren. Dabei kann es sich um eine nachsichtige Beschneidung handeln, sodass jede Form beibehalten wird, deren Einschränkungen mit den Einschränkungen vereinbar sind oder eine Form der Human-in-the-Loop-Beschneidung, bei der nach Eingaben eines Benutzers gesucht wird, um die Lücke zu füllen, um zur strikten Beschneidung überzugehen oder eine sanfte Degradierung, um den betroffenen Teil zu entfernen.
Bei beiden Beschneidungsmethoden können mehrere verbleibende Formen entstehen. Aus diesem Grund ist es wichtig, die Formen nach einer kanonischen Reihenfolge zu sortieren, damit letztlich eine bevorzugte Form ausgewählt werden kann.
Phase 4
In dieser Phase wird die lineare Liste der Lexeme durchlaufen, leere Lexeme (die das Ergebnis der Realisierung einer leeren Untervorlage oder einiger Funktionsaufrufe sein können) werden entfernt und phonologische Einschränkungen werden berechnet (oder nachgeschlagen). Dies ermöglicht die Auswahl der phonologisch bedingten Formen der verschiedenen Lexeme und eine effektive Modellierung von Sandhi-Phänomenen (sowohl wortintern als auch an Wortgrenzen).
Die Einzelheiten dieser Phase hängen von der Realisierungssprache ab. Im Allgemeinen müssen diejenigen Lexeme, die phonologisch bedingte Formen haben, auf die phonologische Darstellung (oder Funktionen) ihrer benachbarten Lexeme in der linearen Liste der Lexeme zugreifen und dementsprechend die entsprechende Form auswählen. Beachte, dass dies einer weiteren Beschneidung der vorhandenen Liste von Formen gleichkommen kann (entsprechend den gegebenen phonologischen Einschränkungen) oder dass eine Logik angewendet werden kann, um die vorhandenen Formen zu verändern.
Diese Phase sollte sich auch um notwendige Verschmelzungen von Formen kümmern. Dies ähnelt der Auswahl einer phonologisch bedingten Form, betrifft jedoch mehr als ein Lexem (üblicherweise zwei). In einigen Fällen kann es zur Änderung einer Lexemform und zur Entfernung der zweiten Lexemform kommen, wobei die zwei Formen miteinander verschmelzen.
Phase 5
In dieser Phase wird der endgültige Realisierungstext erstellt. Die bevorzugten Formen aller Lexeme (die ersten in der beschnittenen und sortierten Liste der Formen) werden miteinander verkettet mit entsprechenden Abständen dazwischen. Im Allgemeinen wird der Abstand der ursprünglichen Vorlage eingehalten, obwohl aufeinanderfolgende Leerzeichenbereiche auf ein einziges Leerzeichen reduziert werden können. Einige Leerzeichen können jedoch entfernt werden, insbesondere in der Nähe von Satzzeichen oder Lexemen, die als (orthografische) Klitika gekennzeichnet sind.
In dieser Phase werden auch Groß- und Kleinschreibung und Interpunktion gehandhabt, wobei die gesamte Interpunktion entfernt wird, die bei der endgültigen Realisierung überflüssig wird (dies kann beispielsweise passieren, wenn eine Untervorlage als leere Zeichenfolge realisiert wird) und Wörter am Satzanfang großgeschrieben werden (in Sprachen, in denen dies nötig ist).
Beispiel-Vorlagen
Um die Vorlagensyntax und die resultierende Kompositionssyntax zu veranschaulichen, untersuchen wir den im Architekturdokument angegebenen Beispielkonstruktor:
Age( Entity: Malala Yousafzai (Q32732) Age_in_years: 24 )
In diesem einfachen Beispiel werden beide Felder des Konstruktors benötigt, um einen Satz zu generieren (z. B. “Malala Yousafzai ist 24 Jahre alt”), es könnte jedoch Konstruktoren mit optionalen Feldern geben, die mehr Flexibilität ermöglichen.
Wir können davon ausgehen, dass der Konstruktor (durch den Orchestrator oder durch eine spezielle Dispatch
-Funktion) einem Funktionsaufruf der Form Age_renderer_xx
zugeordnet ist, wobei xx
für den Sprachcode steht. Darüber hinaus stehen diesen Funktionen die Unterfelder des Konstruktors als Argumente zur Verfügung. Der Einfachheit halber verwenden wir hier englische Bezeichnungen, aber in der Praxis können sowohl der Konstruktorname als auch seine Argumente durchaus Z-IDs sein.
Lass uns untersuchen, wie die Vorlagen für verschiedene Sprachen in der Vorlagensyntax aussehen können (die abgeleitete Kompositionssyntax und andere Zuordnungen finden sich in den Anhängen weiter unten). Um die Beispiele realistischer (und interessanter) zu gestalten, nehmen wir an, dass einige von ihnen einen Untervorlagenaufruf Year_xx
verwenden, dessen Aufgabe darin besteht, nur die Nominalphrase "n Jahre" wiederzugeben.
Schwedisch
Im Schwedischen gibt es keine (personenbezogene) verbale Flexion. Lediglich die Ziffer 1 darf in diesem Zusammenhang entsprechend dem Geschlecht des Nomens flektiert werden, aber wenn wir nur an der numerischen Ausgabe interessiert sind, ist dies irrelevant. Die resultierende Vorlage ist also sehr einfach, da keine grammatikalische Vereinbarung erforderlich ist.
Age_renderer_sv(Entity, Age_in_years): "{Person(Entity)} är {Age_in_years} år gammal ."
Französisch
Unter der Annahme, dass sich der Alterskonstruktor immer auf Personen bezieht, kann das Hauptverb avoir für diesen Konstruktor in der Singularform a gehalten werden, sodass keine verbale Vereinbarung erforderlich ist. Andererseits kann das Nomen für das Jahr, an, für eine Zahl dekliniert werden (im Plural ans). Um dies zu kodieren, verwenden wir eine grammatikalische Abhängigkeitsbeziehung, nummod. Die Wirkung dieser Beziehung (Geschlechts- und Zahlenvereinbarung zwischen Nomen und Quantor) wird an anderer Stelle (in der entsprechenden grammatikalischen Funktion) definiert.
Age_renderer_fr(Entity, Age_in_years):
"{Person(Entity)} a {Year(Age_in_years)}."
Year_fr(years): "{nummod:Cardinal(years)} {root:Lexeme(L10081)}"
Hebräisch
Im Hebräischen gibt es zwei zusätzliche Komplikationen: Eine besteht darin, dass das Hauptprädikat (ein pseudoverbaler Partikel) im Geschlecht mit dem Subjekt übereinstimmen muss (und die Anzahl der Jahre als Genitivkomplement annimmt, gekennzeichnet durch die Abhängigkeitsrolle gmod
). Die zweite besteht darin, dass die Konstruktion zum Ausdrücken von "n Jahren" (im Kontext des Alters) abhängig vom Wert von n nur n oder Jahr ausdrückt. Wir können davon ausgehen, dass eine eingebaute bedingte Funktion namens ElideIf die bedingte Eliminierung des Textinhalts der Liste der Lexeme ermöglicht, ohne die grammatikalischen Funktionen ihrer Wurzel zu entfernen. Mithilfe der Pipe-Syntax kann dies problemlos zusätzlich zum grundlegenden Lücken-Aufruf angewendet werden.
Age_renderer_he(Entity, Age_in_years):
"{subj:Person(Entity)} {root:GenderedLexeme(L64310, L64399)} {gmod:Year(Age_in_years)}."
Year_he(years):
"{nummod:Cardinal(years)|Elide_if(years<=2)} {root:Lexeme(L68440)|Elide_if(years>2)}"
Zulu
In der Sprache Zulu (auch bekannt als isiZulu) ist die allgemeine Struktur des Satzes vergleichbar mit "Person hat Jahr(e), die sind N" (Ausgabe für das Beispiel: UMalala Yousafzai uneminyaka engama-25). Es gibt mehrere Ebenen der Übereinstimmung, auf die geachtet werden muss:
- Die Funktion
Person
für Zulu sollte den Namen der Person zusammen mit der entsprechenden Nominalmarkierung abrufen (die für Personen immer u ist, geschrieben als u- vor Vokalen). - Das Verb "haben" (na-) muss mithilfe einer Subjektübereinstimmungsmarkierung mit dem Subjekt übereinstimmen. Während Menschen im Allgemeinen immer die Subjektmarkierung u- haben, erlauben wir hier für das Beispiel ein allgemeineres Muster der Subjektübereinstimmung, indem wir eine
subj
-Beziehung zwischen der Subjekt-Lücke und einer Lücke erzwingen, die das Subjektübereinstimmungsmorphem (mittels einer gleichnamigen Funktion) abruft. Das Subjektübereinstimmungsmorphem wird durch die Nomenklasse des Nomens in der Subjektrolle bestimmt. - Das Wort für Jahr, unyaka (Pl. iminyaka), dargestellt durch L-ID
L686326
, stimmt in der Zahl (Singular/Plural) mit dem Alter überein. Dies wird erreicht, indem einenummod
-Beziehung zwischen der Jahres-Lücke und der Lücke des Alterskardinals erzwungen wird. - Die relative Übereinstimmung verknüpft die Jahre mit der Anzahl der Jahre. Es wird durch die Nomemklasse des Wortes für Jahre bestimmt (die für die Singular- und Pluralformen unterschiedlich ist). Dies wird durch die
concord
-Beziehung erreicht, die auf eine Funktion angewendet wird, die die relative Übereinstimmungsmarkierung abruft und das Lexem "Jahr" als Quelle hat, das wiederum als Eigenschaft eine Nomenklasse hat, der es angehört. - Die Alterszahl selbst wird als Nomen behandelt und benötigt das Nomen-Präfix. Auch dies wird mithilfe der
concord
-Beziehung erreicht, die diesmal als Quelle die Alterskardinalzahl hat. Wir gehen hier davon aus, dass die Kardinalfunktion für die Sprache Zulu das Kardinallexem gemäß den Regeln der Sprache mit der entsprechenden Nomenklasse anreichert.
Zusätzlich zu diesen morphosyntaktischen Vereinbarungsmustern müssen mehrere phonologische Anpassungen vorgenommen werden. Diese werden in den folgenden Teilen der NLG-Pipeline behandelt, sind aber der Vollständigkeit halber hier aufgeführt:
- Das Verb na ("haben") wird als ein Wort zusammen mit dem folgenden Wort iminyaka ("Jahre") geschrieben. Das /a/ wird mit dem /i/ verschmolzen (d. h. Vokalverschmelzung), um ein /e/ zu bilden.
- Die Kopula ba ("sein") wird in diesem Zusammenhang als y realisiert, wenn ihr ein /i/ folgt und sonst als ng. Hier wird es durch die Funktion
Copula()
dargestellt.
Age_renderer_zu(Entity, Age_in_years):
"{subj:Person(Entity)} {root:SubjectConcord()}na{Year(Age_in_years)}."
Year_zu(years):
"{root:Lexeme(L686326} {concord:RelativeConcord()}{Copula()}{concord_1<nummod:NounConcord()}-{nummod:Cardinal(years)}"
Bretonisch
(Vielen Dank an VIGNERON für das Aufbringen dieses Beispiels)
Bretonisch ähnelt dem Schwedischen darin, dass es keine erforderliche morphologische Flexion gibt, da Nomen nach Zahlen im die Singularform annehmen. Der resultierende Satz für den Beispielkonstruktor sollte "25 bloaz eo Malala Yousafzai" lauten. Aus diesem Grund müssen wir die Lücke des Lexems "Jahr" (bloaz, Lexem L45068) nicht mit einer Abhängigkeitsbeziehungsbezeichnung versehen, da standardmäßig die Singularform ausgewählt wird. Andererseits kann das Wort bloaz nach bestimmten Zahlen (1, 3, 4, 5 und 9) und der Zahl 1000 eine phonologische Mutation (sogenannte Erweichung) durchlaufen, um zu vloaz zu werden. Um dies zu erklären, müssen wir davon ausgehen, dass die bretonische Implementierung der Funktion Cardinal
(Cardinal_br
) die wiedergegebene Zahl mit einer phonologischen Funktion annotiert, die darauf hinweist, dass diese Zahl eine Erweichung des folgenden Zeichens auslösen kann. Wenn dies der Fall ist, würde das Phonotaktikmodul der NLG-Architektur für die Erweichung des folgenden Nomens sorgen, ohne dass Anmerkungen zu Abhängigkeitsbezeichnungen erforderlich wären.
Age_renderer_br(Entity, Age_in_years):
"{Cardinal(Age_in_years)} {Lexeme(L45068)} eo {Person(Entity)} ."
Instrumentalisierung der Vorlagensyntax
Die Semantik der Vorlagensyntax wird durch ihren Realisierungsalgorithmus vorgegeben, der unverändert implementiert werden kann (siehe auch Implementierungen) oder die Vorlagensyntax kann auf andere Weise verwendet werden. Im Kontext von Wikifunctions muss die Vorlagensyntax algorithmisch in der Wikifunctions-Kompositionssyntax abgebildet werden. Andere Ansätze umfassen möglicherweise die Zuordnung der Vorlagensyntax zu anderen NLG-Frameworks. Nachfolgend findet sich eine Auswahl; weitere werden möglicherweise zu gegebener Zeit hinzugefügt, wenn Interesse, Techniken und Werkzeuge zunehmen.
Umwandlung von Vorlagensyntax in Wikifunctions-Kompositionssyntax
Umwandlung von Vorlagensyntax in andere Formalismen in NLG-Realisierern
Implementierungen
Derzeit gibt es eine einzige Implementierung des Systems als Scribunto-Modul.
Fußnoten
- ↑ Im Anwendungsfall der Abstrakten Wikipedia wären dies hauptsächlich Informationen, die aus Wikidata stammen, einschließlich des neuen abstrakten Inhalts, der noch definiert werden muss.
- ↑ Da die Lücken in der Praxis Funktionen enthalten können, die beliebige Berechnungen durchführen, sind sie tatsächlich ausdrucksstärker als ein reines CFG-System.
- ↑ Im Allgemeinen werden Vorlagen durch die Verwendung einer Vorlagensprache spezifiziert, sei es deskriptiv formuliert, umgestaltet als kontextfreie Grammatik (unter Ausnutzung der Dualität von Grammatik und Sprache) oder in der gebräuchlicheren Backus-Naur-Form oder als Modell, beispielsweise als XML-Schema (XSD) und Dokumenttypdefinition (DTD) oder als Ontologie (Mahlaza & Keet, 2021).
- ↑ Wenn die Vorlage nur Text enthält, der unverändert gerendert wird, kann dies als "vorgefertigter Text" betrachtet werden, den manche Autoren nicht als eigentliche Vorlagen betrachten, da er nicht mindestens eine Lücke hat (siehe z. B. ToCT). Es ist hier erlaubt, da es in manchen Fällen nützlich sein kann. In ähnlicher Weise möchte man unter bestimmten Voraussetzungen möglicherweise, dass eine Untervorlage nicht realisiert wird, was als Realisierung einer leeren Zeichenkette implementiert werden kann; alternativ kann dies durch eine andere Verarbeitung der Vorbedingungen erreicht werden. Beachte, dass Textelemente innerhalb der Vorlage von der NLG-Pipeline geändert werden können, wenn sie bestimmten vorgegebenen Lexemen entsprechen.
- ↑ Siehe zum Beispiel hier.
- ↑ Der Begriff "Interpolation" wird hier im Sinne von "das Einfügen von etwas anderer Art in etwas anderes" verwendet (wie im Oxford Sprachen-Wörterbuch definiert).
- ↑ Nebenbei bemerkt, zu den in diesen Beispielen verwendeten Datentypen: Die tatsächlichen Datentypen wären diejenigen, die in Wikifunctions definiert sind. Als Beispiel kannst du dir hier die Kerntypen ansehen.
- ↑ Wie zum Beispiel die oben erwähnte Funktion
TemplateText
. - ↑ Beachte, dass auch eine andere Art der Überprüfung verwendet werden könnte, sei es in dieser Phase oder als separates Modul, d. h. es gibt den Aspekt der Überprüfung von Wortarten und der behaupteten Abhängigkeiten sowie der Frage, wann und wo die Einschränkungsprüfung stattfinden muss und wie man das schafft.
- ↑ Eine Unterspezifikation kann auftreten, wenn ein Lexem Formen aufweist, die sich aufgrund einer grammatikalischen Funktion unterscheiden, die nicht (direkt oder indirekt) in der Vorlage spezifiziert ist. Dies kann insbesondere auch dann der Fall sein, wenn Wikidata-Lexeme Formen angeben, die sich durch phonotaktische Funktionen unterscheiden. Da in dieser Phase noch keine phonotaktischen Funktionen propagiert wurden, stehen nach dem Beschneiden alle möglichen phonologisch bedingten Formen zur Verfügung.
- ↑ Siehe hier für eine Erklärung der Subsumierung linguistischer Funktionen.
- ↑ Dies kann gleichzeitig bei der Suche nach geeigneten Kandidaten erfolgen, die die Einschränkungen subsumieren.
Referenzen
- ↑ Deemter, Kees van; Theune, Mariët; Krahmer, Emiel (2003). "Real versus Template-Based Natural Language Generation: A False Opposition?". Computational Linguistics 31 (1): 15–24. ISSN 0891-2017. doi:10.1162/0891201053630291.
- ↑ Reiter, Ehud; Dale, Robert (1997). "Building applied natural language generation systems". Natural Language Engineering 3 (1): 83–84. doi:10.1017/S1351324997001502.
- ↑ Mahlaza, Zola, & Keet, C. Maria. (2021). ToCT: A Task Ontology to Manage Complex Templates. Proceedings of the Joint Ontology Workshops 2021, FOIS'21 Ontology Showcase. Sanfilippo, E.M. et al. (Eds.). CEUR-WS vol. 2969.
- ↑ Gutman, Ariel; Ivanov, Anton; Kirchner, Jess (2019), Using Dependency Grammars in guiding Natural Language Generation, Poster presented in the The Israeli Seminar of Computational Linguistics, IBM Research, Haifa.
- ↑ Gutman, Ariel; Ivanov, Anton; Saba Ramírez, Jessica (2022), Using Dependency Grammars in guiding templatic Natural Language Generation, Working paper, retrieved 2022-07-27
- ↑ Kibort, Anna; Corbett, Greville G. (2008). "Grammatical Features Inventory: Typology of grammatical features". University of Surrey. doi:10.15126/SMG.18/1.16.