Фильтрация цепочек списков Newbee Drools

Я новичок в Drools, но хотел использовать его для дела, которое мне нужно решить.

В основном мои правила должны делать следующее:

  • Отфильтровать заданный исходный (полный) список местоположений, доступный только для чтения, на основе заданного расстояния до текущего местоположения человека
  • Создайте новый список с местоположениями в пределах заданного радиуса расстояния
  • Передайте этот новый список следующему правилу
  • Отфильтруйте новый список местоположений по определенному заголовку
  • Создайте новый список с местоположениями (теперь отфильтрованный по расстоянию и заголовку)

Итак, я хочу связать несколько правил ... сначала сделайте это, создайте новый список с результатами, используйте новый список в следующем правиле, выполните дальнейшую фильтрацию по нему, создайте новый список с еще большим количеством отфильтрованных элементов ... и так далее .. .

Честно говоря, как упоминалось ранее, я абсолютно застрял и подумал, что могу получить дополнительную информацию ...

Мое первоначальное правило, которое я придумал, выглядит так:

package com.acme.rulesets
import com.acme.domain.TopLocation
import com.acme.domain.Person
import com.acme.storage.LocationContainer
import com.acme.helper.GeoHelpers
rule "Get by Distance"
salience 10
when
    $allLocations: LocationContainer()
    $person: Person()
    $loc: TopLocation() from $allLocations.getAllLocations()
then
    double distance = GeoHelpers.getInstance().getHaversineInMiles($person.getLat(), $person.getLon(), $loc.getLat(), $loc.getLon());
    System.out.println($loc.getTitle() + " -- distance in miles to person: " + distance); 
end;

Это далеко не то, чего я хочу достичь ... но, возможно, вы можете дать несколько намеков ...

Итак, прежде всего я думаю, что мне нужно вызвать мой статический java-метод (который просто вычисляет расстояние между двумя заданными точками) в LHS правила, но как только я (пытаюсь) сделать это, он не может скомпилировать правило. Затем мне нужно использовать результат $ dist, чтобы определить, нужно ли эту текущую запись поместить в новый список (как я могу: а. Создать новый список и б.) Поместить в него текущую запись?) .. ... а затем следующим логическим шагом будет создание нового правила «Получить по заголовку местоположения» с более высокой значимостью и использование нового отфильтрованного списка. Так что, в конце концов, когда я вернусь на сторону java, я могу взять все списки из рабочей памяти и проделать с ними дальнейшие действия.

Да, я знаю, мои вопросы могут быть довольно глупыми ... но я не смог найти ничего, из чего я мог бы вывести свой вариант использования.

Однако заранее спасибо.


person Markus Velten    schedule 18.02.2016    source источник


Ответы (1)


Я буду рассматривать этот вопрос по пунктам, а не пытаться предложить «полное» решение. Вам нужно будет решить, что использовать.

Во-первых, может быть веская причина для хранения всех местоположений в классе контейнера, который является единым фактом, но, как правило, правила легче писать, если сами элементы контейнера являются фактами.

rule "person and location"
when
    $p: Person()
    $l: TopLocation(...)
    ...

(Конечно, вы можете придерживаться предложения from.)

Чтобы выбрать местоположение с определенным свойством в сочетании с Person: используйте любое логическое выражение в качестве ограничения или шаблона eval. Если выражение включает какую-либо статическую функцию Java, импортируйте ее (как в Java) или реализуйте как функцию DRL. Я проиллюстрирую это как комбинацию всех трех.

import com.acme.helper.GeoHelpers
function double dist( Person p, TopLocation t ){
    double d =
      GeoHelpers.getInstance().getHaversineInMiles(p.getLat(), p.getLon(),
                                                   t.getLat(), t.getLon());
}

rule "p & l closer than"
when
    $p: Person()
    $l: TopLocation( dist($p,$l) < 100.0 )
    ...

Для фильтрации местоположений по большему количеству критериев вы можете использовать дополнительное правило, в котором выбираются местоположения, соответствующие требуемому «заголовку», но при этом необходимо отслеживать местоположения, выбранные по расстоянию. Чтобы обойтись без этого, просто добавьте к правилу ограничение «title»:

 rule "p & l: Hotel closer than 100"
 when
    $p: Person()
    $l: TopLocation( dist($p,$l) < 100.0,
                     title == "Hotel" )
    ...

И так далее.

Вы скажете, что это правило предназначено только для одного варианта использования - что, если расстояние другое или вы ищете книжные магазины?

Вы можете использовать факт блока параметров для определения литералов.

rule "p & l, X loc closer than D"
when
    Param( $d: distance, $t: title )
    $p: Person()
    $l: TopLocation( dist($p,$l) < $d, title == $t )
    ...

Вы можете сказать, что это очень хорошо, но что, если меняется сама комбинация критериев выбора, а не только значения? Тогда, конечно, действительно может быть лучше иметь отдельные правила, каждое из которых выбирает места по одному критерию. При этом предоставление параметров может быть объединено с выбором соответствующего правила, что может быть выполнено несколькими подклассами Param. Возникает дополнительная проблема: как отслеживать набор выбора. Для этого нам, возможно, придется использовать еще один вспомогательный факт, назовем его ResultSet. Предполагая, что расстояние всегда является критерием, мы можем написать такие правила, как

rule "p & l, closer than D"
when
    $dp: DistParam( $v: distance )
    $p: Person()
    $l: ArrayList() from 
        collect( $l: TopLocation( dist($p,$l) < $v )
then
    retract( $dp );
    insert( new ResultSet( $l ) );
end

rule "p & l, filter by title"
when
    $t: TitleParam( $v: title )
    $r: ResultSet( $s: result )
    $l: ArrayList() from 
        collect( $l: TopLocation( title == $v ) from $s
then
    retract( $t );
    modify( $r ){ setResult($l) }
end

Теперь легко иметь произвольный выбор критериев со значениями, полученными из текущего поиска. - Вы можете получить ResultSet с помощью API после возврата fireAllRules или написать другое правило для его обработки и отзыва.

Рекомендую изучить имеющуюся литературу.

person laune    schedule 19.02.2016