Как использовать drools в Grails3 без каких-либо плагинов?

Можно ли использовать механизм правил drools в GRAILS3 без установки плагина? Я спрашиваю об этом, потому что знаю, что drools реализован на Java, а настоящим официальным плагином Кена Сипрелла для GRAILS является ( видимо) больше не работает.


person Stefano Scarpanti    schedule 07.11.2016    source источник


Ответы (1)


После долгих исследований и многих попыток я получил небольшой API-сервис GRAILS3, с помощью которого можно обрабатывать данные с помощью движка DROOLS без каких-либо плагинов. Все это возможно благодаря тому, что DROOLS основан на Java и благодаря идеальной совместимости между GRAILS и Java.
Все, что вам нужно, это следующее:

  1. включить минимальную зависимость DROOLS в build.gradle
  2. выберите папку для хранения files.drl
  3. есть некоторые объекты для использования в качестве фактов для обработки (не обязательно сохранять их, поэтому я пропускаю настройку гибернации)
  4. внедрить сервис для создания базы знаний правил и получения сеанса
  5. внедрить некоторые методы в контроллер API для обработки данных через DROOLS (получив сеанс от службы)

Ниже приведен простой пример всего этого:

Зависимости DROOLS (в build.gradle):

runtime "org.drools:drools-compiler:6.5.0.Final"
compile "org.drools:drools-core:6.5.0.Final"
compile "org.drools:knowledge-api:6.5.0.Final"

Хранилище DRL в src/rules (ссылка на этот путь будет в сервисе, см. ниже): myrules.drl

import my.entities.Book;
import java.util.List;

rule "Find author"
   salience 10
   when
    $book: Book( author=="Shakespeare" )
   then
    System.out.println("Book found, date:"+$book.getDate0());
end

Некоторая сущность, например Книга:

package my.entities
import java.util.Date

class Book {
    String title, author
    Date date0
}

Сервис для создания знаний DROOLS и получения сеанса (я подготовил движок без состояния, более легкий, чем движок с состоянием):

package my.services
import grails.converters.*

import org.kie.api.runtime.*;
import org.kie.internal.io.ResourceFactory;
import org.kie.api.*;
import org.kie.api.io.*;
import org.kie.api.builder.*;

class DroolsService  {

def getSession() {
        def path    = "src/rules"
        def lru = ["myrules.drl"]
        def rules   = []
        lru.each{
            rules.add("${path}${it}")
        }
        StatelessKieSession ksess   = buildSession(rules)
        return ksess
    }
}

private buildSession(def lfile) {
    println "Building DROOLS session..."
    try {
        def lres    = []
        lfile.each{
            Resource resource   = ResourceFactory.newFileResource(new File(it));
            lres.add(resource)
        }

        KieContainer kieContainer = buildKieContainer(lres)
        StatelessKieSession kieSession = kieContainer.newStatelessKieSession()
        return kieSession
    } catch(Exception e) {
        e.printStackTrace()
        return null
    }

protected KieContainer buildKieContainer(def lres) {
    KieServices kieServices = KieServices.Factory.get()
    KieFileSystem kieFileSystem = kieServices.newKieFileSystem()
    lres.each{
        kieFileSystem.write("src/main/resources/rule.drl", it)  
    }

    KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem).buildAll()
    Results results = kieBuilder.results
    if (results.hasMessages(Message.Level.ERROR)) {
        throw new IllegalStateException(this.class.name + ": " + results.messages.toString())
    }
    KieContainer kieContainer = kieServices.newKieContainer(kieServices.repository.defaultReleaseId)
    kieContainer
}

}

И использование службы в контроллере API:

class ApiController  {

def droolsService

def proc = {
    def sess    = droolsService.getSession()

    def mess    = "ok DROOLS proc from JSON"
    Book book   = null

    if (params.contbook) {
        book = new Book(JSON.parse(params.contbook))
        sess.execute book
    } 

    response.status  = 200 
    render mess
}

В контроллере я беру данные json из параметра и заполняю ими объект, чтобы выполнить его с помощью механизма правил, инициализированного службой DROOLS. Конечно, это очень простое решение, но оно работает.

Некоторые примечания:

  • часть RHS каждого правила drl (после "then") должна быть java, поэтому, как в примере, вы не можете получить прямой доступ к частному свойству объекта, но вы должны использовать геттер или сеттер (неявно созданный GRAILS)
  • getSession создает новую сборку знаний и новый сеанс, и это не оптимально, вы можете изменить его, чтобы сохранить сеанс DROOLS, а затем повторно использовать его через сеанс пользователя.
  • у вас может быть несколько файлов .drl в одной папке и тогда вы должны перечислить их все в сервисе, чтобы запаковать их в движок знаний

Надеюсь, что все это полезно.

person Stefano Scarpanti    schedule 11.11.2016