【问题标题】:Validate facts having nested maps using drools使用流口水验证具有嵌套地图的事实
【发布时间】:2021-01-17 16:22:53
【问题描述】:

我有一个类Fact,它是一个扩展java.util.HashMap 类。我将此类的对象作为事实传递给流口水。 现在一个事实实例看起来像这样 (Map):

{
"key1": "value"
"attributes": [{"name": "name1", "value": "value1"},{"name": "name2", "value": "value2"},{"name": "name3", "value": "value3"}...]
"locks": [{"type": "type1", "value": "value1", "attributes": {"key_a1": "val_a1""key_a2": "val_a2"...}}]
}

在此映射中的根级别条目上运行验证是直截了当的,例如在 key1 上运行验证。
现在,我想在attributeslocks 上运行一些验证。 对于属性,我想确保此地图中存在所有需要的属性,并且它们的对应值是正确的。所以我在 when 块中这样做:

fact: Fact(this["key1"] != null && this.containsKey("attributes"));
attributesEntries: Entry(key == "attributes") from fact.entrySet();
attributesMaps: LinkedHashMap() from attributesEntries;

事实是HashMap
属性的类型为 ArrayList<LinkedHashMap<String, String>>(还为 LinkedHashMap 添加了一个 id 键,其值仅是键名的值)。
锁的类型为ArrayList<LinkedHashMap<String, Object>>
锁具有 Map

类型的属性

但它不起作用。当我评估 attributesEntries 它是 ArrayList<LinkedHashMap> 并且它具有所有预期值但 attributesMaps 是空的。我也尝试过传递像LinkedHashMap(key == 'key1', value == 'val1') 这样的过滤器,但这也没有用。尝试寻找解决方案,但没有一种可用于这种结构。无论有什么可用的,我都试图扩展,但没有奏效。 这有可能实现吗?如果可以,如何实现?此外,一旦我能够从Map 获取值,我如何验证值(非空且匹配模式)。

我是 drools 的新手,我们正在使用 5.4.0.Final 版本的 drools。

另外,我如何处理嵌套在Map 中的下一级locks

【问题讨论】:

  • 为什么不迭代根列表中的项目并将值添加到工作内存中?这样,您可以创建另一个规则来匹配孩子并避免使用所有 from。调试起来应该更简单

标签: java spring-boot drools


【解决方案1】:

我曾经不幸在一个项目中犯了同样的错误,并让我们的类扩展了 HashMap。 (公平警告:HashMap 不能很好地序列化,因此您将使用大量额外内存。)

我将假设您的模型有几件事情,因为您忽略了共享类定义本身。

但我将根据您的示例 JSON 假设以下内容:

  • 您已使用键“key1”添加了一个字符串值(“value”)
  • 您添加了一个List<Map<String, ?>> 值(可能是List<Fact>),键为“locks”
  • 您添加了一个List<Map<String, ?>> 值(可能是List<Fact>),其键为“attributes”

HashMap 的get(key) 方法会返回一个对象值;您已经注意到了特殊的 this[ key ] 语法。

从您的部分规则尝试来看,您要尝试做什么并不完全清楚。我认为您正在尝试获取保存在地图中“属性”键下的List<Map<String, ?>>

rule "Do something with the attributes"
when
  $fact: Fact( this["key1"] != null,
               $attr: this["attributes"] != null )
then
  System.out.println("Found " + $attr.size() + " attributes");
end

this["attributes"] 返回与键属性关联的值。在这种情况下,它是一个列表或任何你塞进去的东西。如果键不存在,则空检查处理。

您还询问了如何使用其中一个列表中的子地图进行操作。假设想对具有"name": "name1" 的属性做某事...

rule "Do something with the 'name = name1' attribute"
when
  $fact: Fact( this["key1"] != null,
               $attributes: this["attributes"] != null )
  
  $nameAttr: Map( this["name"] == "name1" ) from $attributes
then
  // do something with $nameAttr
end

当然,模式会重复。假设您已将另一个 List<Map<String, ?>> 推入属性映射:

rule "Do something with a child of 'name' attribute"
when
  $fact: Fact( this["key1"] != null,
               $attributes: this["attributes"] != null )

  $nameAttr: Map( this["name"] == "name1",
                  $attrKids: this["children"] != null ) from $attributes

  $childNameAttr: Map( this["name"] == "child1" ) from $attrKids

then
  // etc.
end

我强烈建议您重新考虑您的对象模型不是基于地图的。在我工作的公司,我们所有的项目都是基于嵌套的基于 Map 的模型构建并运行 Drools 5.0.1,我花费了大量的时间和精力将其中的一部分升级到 Drools 7 和一个仅传递数据的适当模型我们需要。它节省了 资源并最终变得更快。

【讨论】:

    猜你喜欢
    • 2017-11-07
    • 1970-01-01
    • 1970-01-01
    • 2019-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    相关资源
    最近更新 更多