Matching a list (of tags) with another and detecti

2020-02-15 05:35发布

问题:

My requirement is to match tags. In the example, this particular HourConstraint checks the TeacherHour assigned to Hour(23).

Specifically, it checks TeacherHour.attributes["tags"] for the values ["asst_ct","teacher_john_smith"] and detects atleast one match, two in this case (both "asst_ct" and "teacher_john_smith") .

TeacherHour:
  id: 47
  assigned_hour: Null
  attributes:Map<List<String>>
    "tags":["asst_ct","no_strenuous_duties","kinda_boring","teacher_john_smith"]
    "another_attribute":[...]

HourConstraint:
   hour: Hour(23)
   attribute: "tags"
   values_list: ["asst_ct","teacher_john_smith"]

Question: How do I detect the presence (true or false) of common elements between two lists?

Drools Expert has memberOf and contains, but they check a scalar vs a collection, never a collection vs a collection.

I see two potential ways:

  1. introduce a function boolean isIntersecting(list,list) and tell Drools to use that for truth checking
  2. Implement TeacherHour.attributes[] as a string instead of a list and HourConstraint.valueslist as a regular expression that can match that list

回答1:

There are a few options. Most straight forward is to use the Collections class to do that for you:

rule X
when
    $t: TeacherHour( )
    HourConstraint( Collections.disjoint( $t.attributes["tags"], values_list ) == false )
...

If this is something you would use often in your rules, then I recommend wrapping that function in a pluggable operator, supported by Drools. Lets say you name the operator "intersect", you can then write your rules like this:

rule X
when
    $t: TeacherHour( )
    HourConstraint( values_list intersect $t.attributes["tags"] )
...

A third option, is to use "from", but that is less efficient in runtime as it causes iterations on the first list:

rule X
when
    $t: TeacherHour( )
    $tag : String() from $t.attributes["tags"]
    exists( HourConstraint( values_list contains $tag ) )
...