Java:如何使用大量谓词过滤大量对象?

时间:2013-01-28 23:24:33

标签: java collections predicate

在Java中,我有一个大对象集合(~10,000个对象),比如Set<Person> cityInhabitants。我还有一个大的谓词集合(~1,000个谓词),用于过滤匹配任何这些谓词的任何Person。谓词可以是例如

  • person.getName().equals("ugly name1")
  • person.getName().equals("ugly name2")
  • person.getAge() < 18

此要求需要以下挑战:

  • 过滤应快速
  • 谓词是“业务定义的”,因此添加和删除谓词应该很容易。这意味着谓词可能不应该在源代码中进行硬编码,而是最好在数据库中维护(?)

这些挑战的解决方案是什么?有没有可以提供帮助的图书馆?

4 个答案:

答案 0 :(得分:2)

我建议你按照执行速度的顺序对谓词进行排序。然后,您可以按速度顺序执行谓词,首先使用最快的谓词,通常意味着较慢的谓词必须在较小的集合上运行。

但是,这个假设并不完全正确,您需要计算出被删除的谓词百分比以便执行速度。然后我们可以看到哪个是移除最高百分比对象的最快谓词。然后我们可以按此顺序执行谓词给我最优化。

您可以轻松实现自己的谓词interface

public interface Predicate<T> {

    boolean filter(T object);

}

然后,您需要为每个规则创建谓词对象。您可以为年龄和名称检查创建一些更动态的类,这将减少您还需要的代码量。

public class AgeCheck<T> implements Predicate<T> {

    private final int min;
    private final int max;
    public AgeCheck(int min, int max) {
        this.min = min;
        this.max = max;
    }

    @Override
    public boolean filter(T object) {
        // if( t.age() < max && t.age > min) ...
    }

}

答案 1 :(得分:2)

在这种情况下,关于操作本身的复杂性,你无能为力。如果条目很多,谓词很多,谓词很贵,那么你可以尽可能快地进行优化,但是你肯定不会超过某个阈值,因为这里的单个操作可能很昂贵。

您应该测试不同的方法,看看在特定情况下表现更好的方法:

  • 排序谓词首先检查应该更宽的谓词(以便第一个谓词将过滤掉尽可能多的条目)
  • 根据它们的复杂性对谓词进行排序(因此首先执行速度越快,条目越少则越慢)
  • 不更新原始数据结构,但保留包含已过滤元素vs
  • 的并行集
  • 始终更新数据结构,以便您每次都可以遍历少量人员

答案 2 :(得分:1)

这是另一种选择:识别类实例可能具有的所有可能属性。在您的示例中,您有一个具有两个属性的person类;姓名和年龄。因为你有这些属性的getter,所以最多可能person可以有两个属性(除非你没有提到其他的getter)。您可以实现person,以便将属性保存在集合中,这样您就不会对属性数量进行限制。无论如何实施,都要确定所有属性。

现在,对于每个属性,关联唯一的素数,然后为person的每个实例维护与分配给person的那些属性对应的素数的乘积。例如,假设一个人可以是年轻人或老年人,男性或女性,外表美观或不好看。这是6个属性,让我们按如下方式分配素数:

02: young
03: old
05: male
07: female
11: good looking
13: bad looking

继续这个例子,假设一个人是一个好看的年轻女性。素数的乘积为2 X 7 X 11或154。

现在你想找到所有漂亮的年轻人,无论性别如何。与该谓词相关的素数的乘积是2 X 11或22。

因此,您现在可以遍历所有people,并且如果与每个people关联的素数的乘积可以除以22而没有任何余数(在{{1}的情况下可以与素数的乘积是154),然后你有一个匹配。

您可能希望使用BigNumber类来执行乘法,除法和素数乘积的存储。

如果给你一个person并且询问它是否匹配所有谓词,那么这个解决方案非常快(同样,谓词已经被简化为唯一的素数,而谓词的集合现在由以下产品表示:那些素数)。

如果您必须遍历整个person集合寻找匹配项,此解决方案可能不会那么快。

答案 3 :(得分:1)

我还没有意识到这个问题已经过了2年。我参加这个派对的时间太晚了!知道作者最终使用了什么解决方案会很好。

是否有任何图书馆可以提供帮助?嗯,肯定有!

您的数据收集量不是很大,但是您的谓词数量不成比例。此外,您希望这些谓词由您的用户管理,并集中存储等。这听起来非常适合Drools,这是一个规则引擎,并附带额外的工具来创作,验证和存储这些规则

但是Drools可能很大而且参与其中。也许你需要更简单的东西?你的代码示例和你对速度的第一个要求让我想到了CQEngine,它是一个用于索引对象的库。它索引字段(例如您的'名称字段),它可以以各种方式搜索这些字段(等号,开头,包含等)。它很快而且很简单,但它只能索引。您自己必须提出规则定义等。另一方面,CQEngine支持逻辑谓词,因此您可以将谓词链接到和/或。

还有其他用于规则引擎或对象索引的库。我相信其他人会在答案中列出这些内容。