Sequenzieller Algorithmus
Anders als der RetePlus-Algorithmus stellt der sequenzielle Ausführungsmodus keine Inferenz bereit. Der sequenzielle Algorithmus arbeitet nur auf eine vorhersehbaren Art und Weise, wenn die Regeln homogen sind, d. h., wenn sie dieselben Bindungen verwenden.
Um dieselbe Ausführung bei beiden Algorithmen zu gewährleisten, müssen die folgenden beiden Bedingungen erfüllt sein:
Die Regeln müssen homogen sein. Homogene Regeln bedeuten, dass diese Regeln für dieselben Typen und dieselbe Anzahl von Objekten gesetzt werden müssen. Wenn Sie versuchen, den sequenziellen Algorithmus auf heterogene Regeln anzuwenden, werden dadurch in der Regel mehr Tupelobjekte erzeugt, was dazu führen kann, dass mehr Regeln ausgeführt werden als im RetePlus-Modus. Die allgemeine Tupelsignatur kann auch dazu führen, dass heterogene Regeln nicht ausgelöst werden. Wenn im Arbeitsspeicher keine entsprechenden Instanzen vorhanden sind, können keine Tupel erstellt werden.
Die Regeln dürfen nicht verkettet sein, d. h. die Modifikation, die im Aktionsteil einer Regel ausgeführt wird, darf nicht zur Ausführung einer anderen Regel führen.
Wenn Sie den sequenziellen Ausführungsmodus für Regeln angeben, die mit diesem Modus nicht kompatibel sind, gibt die Engine einen Fehler aus.
Die Verwendung des sequenziellen Ausführungsmodus wird in den folgenden Abschnitten ausführlicher beschrieben:
Tupel
Ein Tupel ist eine Liste von Objekten, die einer bestimmten Struktur entspricht. Eine Tupelstruktur ist einfach eine Folge von Klassendeskriptoren. Jede Position in einer Tupelstruktur wird als Slot bezeichnet. Derselbe Klassendeskriptor kann mehrfach an verschiedenen Slots vorkommen.
Nehmen Sie beispielsweise eine Tupelstruktur an:
(Customer,Product)
Im Folgenden sehen Sie ein Tupel, das dieser Struktur entspricht:
(new Customer("Henry"),new DVD("Mickey"))
Beachten Sie, dass die Unterklasse berücksichtigt wird, da ein DVD ein Productist. Es gibt jedoch einige Tupel, die mit der Struktur nicht
kompatibel sind:
Das folgende Tupel ist beispielsweise zu groß:
(new Customer("Henry"),new CD("Madona"),new DVD("Mickey"))
Dieses Tupel ist nicht ordnungsgemäß sortiert:
(new DVD("Lord of the rings"),new Customer("Henry"))
Und dieses Tupel ist zu klein:
(new Customer("Henry"))
In Java™wird ein Tupel einfach als Array von Objekten implementiert:
Java Tuple = Object[]
Der Java-Code zum Erstellen eines Tupels und seiner Objekte lautet wie folgt:
new Object[] {new Customer("Henry"),new DVD("Mickey")}
Zur Laufzeit werden die Tupel entweder manuell oder automatisch aus dem Inhalt des Arbeitsspeichers erstellt und dann an die Regelengine übergeben. Die Tupel werden nacheinander an die Tupelabgleichsmethode übergeben.
Tupel werden nur aus Objekten im Arbeitsspeicher erstellt, wenn sie der Tupelstruktur entsprechen: eine allgemeine Signatur, die von allen Regeln in der sequenziellen Aufgabe gemeinsam genutzt wird. Nach der Tupelerzeugung werden alle Regeln für alle Tupel ausgeführt. Aus diesem Grund wird die Verwendung homogener Regel mit dem sequenziellen Algorithmus empfohlen.
Wenn Sie ein eigenes Tupel
bereitstellen, muss es immer der Signatur entsprechen, es
muss aber nicht unbedingt vollständig sein. Ein partielles Tupel ist ein Tupel mit nicht belegten Slots. Nicht belegte Slots werden einfach auf null gesetzt. Das Tupel (new Customer("Henry")), das eigentlich zu klein ist, könnte als
(new Customer("Henry"),null) codiert werden, um der Tupelstruktur zu entsprechen.
rule r1 {
when{
Integer();
Integer();
}
then {...
rule r2 {
when{
Integer();
}
then {...rule r1 {
when{
Integer();
String();
}
then {...
rule r2 {
when{
Integer();
}
then {...Regelauswahl im sequenziellen Modus
Die Regeln einer Regelaufgabe, die mit der Eigenschaft algorithm gleich sequential festgelegt werden, werden dynamisch in Java-Bytecode umgesetzt. Der Bytecode ist in der Lage, die sequenzielle Verarbeitung auszuführen, wenn die Aufgabe ausgeführt wird.
Die Eigenschaft body einer Regelaufgabe ist verbindlich. Sie wählt die Regeln des Regelsatzes aus, die von der Regelaufgabe berücksichtigt werden.
Siehe auch Laufzeitregelauswahl.
Steuerungseigenschaften im sequenziellen Modus
Steuerungseigenschaften wirken sich auf die Ausführung im sequenziellen Modus und auf die Tupelstruktur aus. Weitere allgemeine Informationen finden Sie unter Steuerungseigenschaften für Regelaufgaben in Ausführungsmodi .
Die Anzahl auszuführender Regeln pro Tupel und die Ausführungsreihenfolge können mit den Steuerungseigenschaften ordering, firing und firinglimit festgelegt werden.
Eigenschaft "ordering"
Die Eigenschaft ordering
ist für die sequenzielle Verarbeitung verbindlich. Sie beschreibt die Reihenfolge, in der die Regeln der Regelaufgabe ausgeführt werden.
Es sind zwei Werte verfügbar:
literal: Die Regeln bleiben in der Reihenfolge, in der sie im Aufgabenhauptteil angegeben werden (mit Aufwärts-/Abwärtspfeilen).sorted: Die Regeln werden entsprechend ihren statischen Prioritäten sortiert.
Es ist ein weiterer Wert, dynamic, verfügbar,
der nur für Regelaufgaben gilt, die den Ausführungsmodus "RetePlus" verwenden.
Eigenschaft "firing"
Die Eigenschaft
firing gibt an, ob für jedes Tupel alle Regeln oder nur die erste zutreffende Regel
ausgeführt werden soll. Die Angabe dieser Eigenschaft ist optional.
Es gibt zwei mögliche Werte:
allrulesDieser Wert bedeutet, dass alle zutreffenden Regeln ausgeführt werden müssen, bevor mit dem nächsten Tupel fortgefahren wird. Dies ist der Standardwert.
ruleDieser Wert bedeutet, dass nur die erste zutreffende Regel im ersten Tupel ausgeführt werden muss.
Eigenschaft "firinglimit"
Die Eigenschaft
firinglimit legt eine weitere Steuerungsebene fest, wenn die Eigenschaft
firing auf allrules gesetzt ist. Mit dieser Eigenschaft wird
angegeben, wie viele Regeln maximal ausgeführt werden, bevor mit dem nächsten Tupel fortgefahren wird. Diese Zahl muss größer als null sein.
Bekannte Einschränkungen des sequenziellen Algorithmus
In fast allen Fällen gibt es keine
Einschränkung bezüglich der Anzahl der Regeln, die von einer einzelnen Aufgabe
verarbeitet werden können, deren Eigenschaft "algorithm" auf "sequential" gesetzt ist. Die einzige Ausnahme bilden extrem große Entscheidungstabellen mit einer Klausel
otherwise. Die Verarbeitung ist wie folgt: Alle Bedingungen aller Zeilen werden in einem einzigen Ausdruck verneint. Dieser einzige Ausdruck wird dann nach der Übersetzung in Bytecode in den Hauptteil einer einzelnen
Methode übernommen. Dies ist ein Problem, da die Java-Prüffunktion Methoden mit einem zu großen Hauptteil zurückweist. Der für die Regeln verwendete Skalierbarkeitsalgorithmus
wird nicht auf den Methodenhauptteil angewendet. Der Benutzer wird über diese Einschränkung benachrichtigt, wenn das Klassenladeprogramm
die Regeln zurückweist. Die Einschränkung bezüglich der Regelanzahl ist nicht eindeutig festgelegt, bezieht sich aber wahrscheinlich auf mehrere Tausend
Regeln.
In der folgenden Tabelle werden die Einschränkungen der sequenziellen Verarbeitung beschrieben, insbesondere ihre Verwendung in Kombination mit bestimmten IRL-Konstrukten (ILOG ® Rule Language).
| Einschränkung | Beschreibung |
|---|---|
| IRL-Einschränkungen (ILOG Rule Language) | Nicht alle Regelmuster, die für den statusabhängigen Rete-Abgleich konzipiert wurden, sind verfügbar. Es treten Kompilierzeitfehler auf, wenn eine Regel nicht mit der aktuellen Tupelabgleichsimplementierung kompatibel ist. Deshalb unterstützt IRL bei der sequenziellen Verarbeitung die folgenden Features nicht:
|
| Bedingungskonstrukte | Die folgenden Bedingungskonstrukte sind bei der sequenziellen Verarbeitung verfügbar:
|
| Ausnahmebehandlung | Die Ausnahmebehandlung wird in Regelbedingungsteilen im sequenziellen Modus und im Modus "Fastpath" nicht unterstützt. Wenn Sie beispielsweise einen Ausnahmehandler in einem Kontext angeben, wird dieser im sequenziellen Modus und im Modus "Fastpath" nicht berücksichtigt:
|
| Refraktion | Die Dateneinheit für einen Enginezyklus ist das Tupel. Die Engine zeichnet die Tupel nicht während des Abgleichs auf, sondern verwirft sie zwischen den Zyklen. Deshalb gibt es keine integrierte Unterstützung für Refraktion. Im sequenziellen Ausführungsmodus wird aus der vorherigen Regel Folgendes:
Berechnete Tupelstruktur:
Generierter Abgleichcode:
Der Hauptcode bleibt gleich:
Iteratorschleife für den Arbeitsspeicher:
Ausführungstrace:
Der Ausführungstrace zeigt, dass bei Verwendung des Modus für sequenzielle Verarbeitung dieselbe Regel zweimal für dieselben Teile zweier verschiedener Tupel ausgeführt wird. |
| IRL-Funktionen (ILOG Rule Language) | Im Gegensatz dazu sind praktisch alle Ausdrücke und Anweisungen auf Scriptebene der IRL für die sequenzielle Verarbeitung verfügbar. Sie dienen hauptsächlich dazu, die Konsistenz der anderen Regelaufgaben, die nicht auf den sequenziellen Algorithmus eingestellt sind, zu gewährleisten. Im Folgenden sehen Sie eine Liste dieser Features:
|
Die folgenden Beispiele zeigen Fälle, die JIT-Kompilierungsfehler (Just-in-time) verursachen, d. h. Fehler zur Ausführungszeit, keine Parsing-Fehler.
Beispiel 1: IRL-Einschränkung, die zu Kompilierungsfehlern führt
Dieses Beispiel führt zu JIT-Kompilierungsfehlern, weil Aufzählungsausdrücke fehlen.
ruletask T {
algorithm = sequential;
body = { R1, R2, R3, R4, R5, R6, R7, R8, R9 }
}
rule R1 {
when {
not MyObject(); // No enumerator, an error will occur
}
then {
}
}
rule R2 {
when {
exists MyObject(); // No enumerator, an error will occur
}
then {
}
}
rule R3 {
when {
collect MyObject() where (size() == 1); // No enumerator, an error
will occur
}
then {
}
}
function Object getObject() {
return new MyObject();
}
function Object[] getObjects() {
Object objs = new Object[1];
objs[0] = getObject();
return objs;
}
rule R4 {
when {
not MyObject() from getObject(); // An enumerator, no error
}
then {
}
}
rule R5 {
when {
not MyObject() in getObjects(); // An enumerator, no error
}
then {
}
}
rule R6 {
when {
exists MyObject() from getObject(); // An enumerator, no error
}
then {
}
}
rule R7 {
when {
exists MyObject() in getObjects(); // An enumerator, no error
}
then {
}
}
rule R8 {
when {
collect MyObject() from getObject() where (size() == 1);
// An enumerator, no error
}
then {
}
}
rule R9 {
when {
collect MyObject() in getObjects() where (size() == 1);
// An enumerator, no error
}
then {
}
}
Beispiel 2: IRL mit Konstrukteinschränkungen
Im Folgenden sehen Sie ein Beispiel
mit einem Konstrukt mit collect, das den Geltungsbereich der Bindungen demonstriert. Dies gilt für not und exists ebenfalls. Dieses Beispiel führt ebenfalls zu JIT-Kompilierungsfehlern, weil nicht unterstützte
Konstrukte verwendet werden.
rule R10 {
when {
r:MyRootObject();
c:collect MyObject(n:name; n.startsWith("ilog")) in r.getObjects();
where (s:size(); s > 1);
}
then {
out.println(r); // correct
out.println(c); // correct
out.println(s); // correct
out.println(n); // error
}
}