首页 > 解决方案 > 使用流口水验证具有嵌套地图的事实

问题描述

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

{
"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.
现在,我想在attributes和上运行一些验证locks。对于属性,我想确保这张地图中存在所有需要的属性,并且它们的对应值是正确的。所以我在 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>>一个键,其值仅是键名的值)。 锁是类型 锁具有 Map<String, String> 类型的属性idLinkedHashMap
ArrayList<LinkedHashMap<String, Object>>

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

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

另外,我如何使用嵌套Maplocks.

标签: javaspring-bootdrools

解决方案


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

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

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

  • 您添加了一个带有键“key1”的字符串值(“value”)
  • 您添加了一个带有“锁”键的List<Map<String, ?>>值(可能是 a )List<Fact>
  • 您添加了一个带有键“attributes”的List<Map<String, ?>>值(可能是 a )List<Fact>

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"]返回与键属性关联的值。在这种情况下,它是一个列表或任何你塞进去的东西。如果该键不存在,则 null 检查会处理该问题。

您还询问了如何在其中一个列表中使用子地图进行操作。假设想要对具有"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 和只传递数据的适当模型我们需要。它节省了大量资源,最终速度更快。


推荐阅读