2010-02-16 20 views
9

Ich werde das Bibliothekssystem einer Universität verwenden, um meinen Anwendungsfall zu erklären. Die Schüler registrieren sich im Bibliothekssystem und geben ihr Profil an: Geschlecht, Alter, Abteilung, vorher abgeschlossene Kurse, aktuell registrierte Kurse, bereits ausgeliehene Bücher usw. Jedes Buch im Bibliothekssystem definiert einige Ausleihregeln, die zum Beispiel auf dem Profil der Schüler basieren ein Lehrbuch für den Computeralgorithmus kann nur von Schülern ausgeliehen werden, die gegenwärtig in dieser Klasse registriert sind; ein anderes Lehrbuch darf nur von Studenten in der Mathematikabteilung ausgeliehen werden; Es könnte auch Regeln geben, so dass die Schüler höchstens 2 Computer-Vernetzungsbücher ausleihen können. Als Folge der Ausleihregeln sieht ein Student, wenn er im Bibliothekssystem sucht/blättert, nur die Bücher, die er ausleihen kann. Also, die Anforderung kommt wirklich auf die Linie der effizienten Generierung der Liste der Bücher, die ein Student ausleihen kann.Sollte ich Drools in dieser Situation verwenden?

Hier ist, wie ich das Design mit Drools Vision - jedes Buch wird eine Regel mit ein paar Einschränkungen Feld auf dem Schüler Profil als LHS, die RHS der Buchregel fügt einfach die Buch-ID zu einer globalen Ergebnisliste, dann Alle Buchregeln werden in eine RuleBase geladen. Wenn ein Schüler das Bibliothekssystem durchsucht/browtet, wird aus der RuleBase eine statusfreie Sitzung erstellt und das Profil des Schülers als Tatsache bestätigt, dann wird jedes Buch, das der Schüler ausleihen kann, seine Buchregel auslösen und Sie erhalten die vollständige Liste der Bücher Die Schüler können in der globalen Ergebnisliste ausleihen.

Ein paar Annahmen: Die Bibliothek wird mit Millionen von Büchern umgehen; Ich erwarte nicht, dass die Buchregel zu kompliziert ist, 3 einfache Feldbeschränkungen für jede Regel im Durchschnitt höchstens; Die Anzahl der Schüler, die das System handhaben muss, liegt im Bereich von 100 K, daher ist die Belastung ziemlich hoch. Meine Fragen sind: Wie viel Speicher werden Drools nehmen, wenn sie mit einer Million Buchregeln geladen sind? Wie schnell wird es sein, dass all diese Millionen Regeln ausgelöst werden? Wenn Drools die richtige Lösung ist, würde ich gerne einige Best Practices für die Entwicklung eines solchen Systems von erfahrenen Benutzern hören. Vielen Dank.

+2

Da Ihre Rule Constraints tatsächlich in der Datenbank sitzen - warum nicht einfach SQL Queries verwenden, um zu erreichen, ob einem Benutzer erlaubt oder nicht erlaubt wird, diese Bücher zu bekommen. – Jasper

Antwort

7

Meine Erfahrung mit Drools (oder einer Regel-Engine im Allgemeinen) ist, dass es gut passt, wenn die Sichtbarkeit der Benutzer in den Regeln wichtig ist, oder wenn schnelle Änderungen an den Regeln wichtig sind, oder wenn Das Regelwerk ist sehr groß, so dass es schwierig ist, im Code zu managen, darüber nachzudenken und zu analysieren (also würden Geschäftsleute technische Mitarbeiter bitten, den Code zu lesen und ihnen zu sagen, was in Situation X passiert).

Das heißt, Regel-Engines können ein Engpass sein. Sie funktionieren nicht annähernd so leistungsfähig wie der Code, also müssen Sie das im Vorfeld architektonisch erledigen. In diesem speziellen Fall gibt es sicherlich eine Datenbank dahinter, und Sie können den Leistungsproblemen hinzufügen, dass die Datenbank eine Abfrage viel schneller zurückgibt, als Sie den gesamten Satz im Code analysieren können.

Ich würde absolut nicht implementieren, indem Sie eine Million Regeln Objekte, eher würde ich einen Buch-Typ, dass mehrere Bücher zugeordnet werden können, und führen Sie die Regeln gegen die Buch-Typen, und zeigen dann nur Bücher, die in einem sind erlaubter Typ Auf diese Weise können Sie die Typen laden, sie über die Regelengine übergeben und dann die zulässigen Typen an eine Abfrage auf der Datenbankende übergeben, die die Liste der Bücher in den zulässigen Typen abruft.

Typen werden ein wenig kompliziert durch die Tatsache, dass es in der Praxis wahrscheinlich ein Buch von zwei Arten sein kann (erlaubt, wenn Sie einen bestimmten Kurs nehmen, oder allgemein, wenn Sie Teil der Abteilung sind), aber die Ansatz sollte noch halten.

-1

Ich wäre besorgt über die Notwendigkeit, die Anzahl der Regeln eine Funktion der Anzahl der Schüler zu haben - das könnte wirklich die Dinge schwierig machen (das klingt wie das größte Problem).

11

Erstens, machen Sie keine Regeln für jedes Buch. Machen Sie Regeln für die Einschränkungen — gibt es viel weniger Einschränkungen als Bücher definiert. Dies wird einen großen Einfluss auf die Laufzeit und den Speicherverbrauch haben.

Eine Tonne Bücher durch die Regelmaschine laufen zu lassen wird teuer sein. Vor allem, weil Sie dem Benutzer nicht alle Ergebnisse zeigen werden: nur 10-50 pro Seite. Eine Idee, die Ihnen einfällt, ist die Verwendung der Regel-Engine, um eine Reihe von Abfragekriterien zu erstellen. (Ich würde nicht wirklich tun dies — siehe unten).

Hier ist, was ich im Sinn haben:

rule "Only two books for networking" 
when 
    Student($checkedOutBooks : checkedOutBooks), 
    Book(subjects contains "networking", $book1 : id) from $checkedOutBooks, 
    Book(subjects contains "networking", id != $book1) from $checkedOutBooks 
then 
    criteria.add("subject is not 'networking'", PRIORITY.LOW); 
end 

rule "Books allowed for course" 
when 
    $course : Course($textbooks : textbooks), 
    Student(enrolledCourses contains $course) 

    Book($book : id) from $textbooks, 
then 
    criteria.add("book_id = " + $book, PRIORITY.HIGH); 
end 

Aber ich würde das nicht wirklich tun!

So hätte ich das Problem geändert: Die Bücher dem Benutzer zu zeigen ist eine schlechte Erfahrung. Ein Benutzer möchte vielleicht die Bücher lesen, um zu sehen, welche Bücher das nächste Mal erhalten. Zeigen Sie die Bücher, aber verbieten Sie das Auschecken beschränkter Bücher. Auf diese Weise haben Sie nur 1-50 Bücher, um die Regeln pro Benutzer zu durchlaufen. Das wird ziemlich zippy sein. Die oben genannten Regeln würden:

rule "Allowed for course" 
    activation-group "Only one rule is fired" 
    salience 10000 
when 
    // This book is about to be displayed on the page, hence inserted into working memory 
    $book : Book(), 

    $course : Course(textbooks contains $book), 
    Student(enrolledCourses contains $course), 
then 
    //Do nothing, allow the book 
end 

rule "Only two books for networking" 
    activation-group "Only one rule is fired" 
    salience 100 
when 
    Student($checkedOutBooks : checkedOutBooks), 
    Book(subjects contains "networking", $book1 : id) from $checkedOutBooks, 
    Book(subjects contains "networking", id != $book1) from $checkedOutBooks, 

    // This book is about to be displayed on the page, hence inserted into working memory. 
    $book : Book(subjects contains "networking") 
then 
    disallowedForCheckout.put($book, "Cannot have more than two networking books"); 
end 

Wo ich Aktivierung-Gruppe verwenden, um sicherzustellen, nur eine Regel ausgelöst wird, und salience um sicherzustellen, dass sie in der Reihenfolge abgefeuert werden ich sie sein will.

Schließlich halten Sie die Regeln zwischengespeichert. Drools erlaubt — und schlägt vor, dass — Sie die Regeln nur einmal in eine Wissensdatenbank laden und dann Sitzungen daraus erstellen. Wissensbasen sind teuer, Sitzungen sind billig.

+1

+1 für die Neudefinition des Problems - Ich stimme zu, dass Sie keine Million Bücher als Regel Sitzung Fakten benötigen, nur diejenigen, die der Student in den "Warenkorb" auf dem Weg zur "Kasse" –

1

Meine Fragen sind: Wie viel Speicher wird geifert nehmen, wenn mit einer Million Buch Regeln geladen? Wie schnell wird es für alle diese Millionen Regeln zu feuern sein?

Wie schnell ist Ihr Computer und wie viel Speicher haben Sie? In einem gewissen Sinn können Sie das nur herausfinden, indem Sie einen Proof of Concept erstellen und ihn mit der richtigen Menge an (zufällig generierten) Testdaten füllen. Meine Erfahrung ist, dass Drools schneller ist als man erwartet, und dass man sehr gut wissen muss, was unter der Haube ist, um vorhersagen zu können, was es langsam machen wird.

Beachten Sie, dass Sie sprechen über eine Million Regel Sitzung Fakten (d. H. Bücher Objekte), nicht eine Million Regeln. Es gibt nur eine Handvoll Regeln, die nicht lange brauchen werden. Der potentiell langsame Teil fügt die Millionen Objekte ein, da Drools entscheiden muss, welche Regeln für jede neue Tatsache auf die Agenda gesetzt werden sollen.

Es ist eine Schande, dass keiner von uns eine Antwort für eine bestimmte Einrichtung mit einer Million Fakten hat.

Bei der Implementierung wäre mein Ansatz, ein Book-Objekt für jedes Buch einzufügen, das der Student auschecken möchte, die nicht erlaubten zurückzuziehen und eine Abfrage, um die verbleibenden (zulässigen) Buchobjekte zu erhalten. und eine weitere Abfrage, um die Liste der Gründe zu erhalten. Alternativ können Sie RequestedBook-Objekte verwenden, für die zusätzliche Eigenschaften boolean allowed und String reasonDisallowed verfügbar sind, die Sie in Ihren Regeln festlegen können.

+0

Ich bevorzuge Ihre Lösung lieber als ändern die von @Michael Deardeuff vorgeschlagene Problembeschreibung. Wie wird Ihre Lösung aussehen, wenn der Benutzer die letzte Seite sagt? Erwarten Sie alle Millionen Fakten, die in das Arbeitsgedächtnis eingehen? –

1

Jedes Mal, wenn wir große Datenmengen untersuchen (worum es sich bei dieser Frage handelt ... ob Drools in einem großen Datensatz sehr gut passt), denke über den Tellerrand hinaus (siehe unten). Jedes Mal, wenn wir über "Millionen von Objekten" oder ähnliche Probleme vom Log-N-Typ sprechen, denke ich nicht, dass das fragliche Tool notwendigerweise das Problem ist.Also ja, Drools (oder JBoss Rules) kann verwendet werden, aber würde nur in einem bestimmten Kontext Sinn machen ...

Wenn Sie log-N von irgendetwas (Cross-Referenzierung großer Datensätze gegen Eingaben), würde ich empfehlen, neuere Ansätze wie datenbankgestützte Bloom-Filter zu verwenden. Diese können als Java-Objekte implementiert werden und von Drools für das Fact-Lookup referenziert werden.

Da Bloom-Filter winzige Speicherstrukturen mit nur grundlegenden Funktionen insert()/contains() sind, haben sie einen Nachteil ... etwa 1% falsch-positive Rate. Das wird also als primärer Cache dienen. Wenn die Drools-Frage im Allgemeinen als Antwort "NEIN" ist, wird eine Bloom-Filter-basierte Fact-Table-Konstrukt-Suche blitzschnell und mit einem winzigen Speicherbedarf (etwa 1,1 Bytes pro Datensatz in meiner Implementierung), also 1 MB RAM für dieser Fall. Dann im "contains" -Fall (was ein false-positive sein könnte), verwenden Sie die datenbankgestützte Faktentabelle, um zu klären. Wenn in 80% der Fälle die Suche falsch ist, dann wird der Bloom-Filter eine enorme Kostenersparnis in Speicher und Zeit sein. Ansonsten werden die reinen (alles - Drools Fakten, Datenbank, etc.) 1M-Record-Lookups jedes Mal sehr teuer (in Speicher und Geschwindigkeit).

Verwandte Themen