Hazelcast Aggregations API导致带有Predicates的ClassCastException

时间:2015-04-06 23:52:29

标签: hazelcast

我使用Hazelcast IMap实例来保存以下对象:

public class Report implements Portable, Comparable<Report>, Serializable 
{
    private String id;
    private String name;
    private String sourceId;
    private Date timestamp;
    private Map<String,Object> payload;
  // ...
}

IMap键入了id,我还在sourceId上创建了一个索引,因为我需要根据该字段进行查询和聚合。

IMap<String, Report> reportMap = hazelcast.getMap("reports");
reportMap.addIndex("sourceId", false);

我一直在尝试使用Aggregations框架按sourceId计算报告。 尝试#1:

  public static int reportCountforSource(String sourceId) 
  {
      EntryObject e = new PredicateBuilder().getEntryObject();
      Predicate<String, Report> predicate = e.get("sourceId").equal(sourceId);
      Supplier<String, Report, Object> supplier = Supplier.fromPredicate(predicate);
      Long count = reportMap.aggregate(supplier, Aggregations.count());

      return count.intValue();
  }    

这导致Aggregations框架抛出ClassCastException

Caused by: java.lang.ClassCastException: com.hazelcast.mapreduce.aggregation.impl.SupplierConsumingMapper$SimpleEntry cannot be cast to com.hazelcast.query.impl.QueryableEntry
    at com.hazelcast.query.Predicates$AbstractPredicate.readAttribute(Predicates.java:859) 
    at com.hazelcast.query.Predicates$EqualPredicate.apply(Predicates.java:779) 
    at com.hazelcast.mapreduce.aggregation.impl.PredicateSupplier.apply(PredicateSupplier.java:58) 
    at com.hazelcast.mapreduce.aggregation.impl.SupplierConsumingMapper.map(SupplierConsumingMapper.java:55)
    at com.hazelcast.mapreduce.impl.task.KeyValueSourceMappingPhase.executeMappingPhase(KeyValueSourceMappingPhase.java:49)

然后我改为使用Predicates代替PredicateBuilder().getEntryObject() 尝试#2:

  public static int reportCountforSource(String sourceId) 
  {
      @SuppressWarnings("unchecked")
      Predicate<String, Report> predicate = Predicates.equal("sourceId", sourceId);
      Supplier<String, Report, Object> supplier = Supplier.fromPredicate(predicate);
      Long count = reportMap.aggregate(supplier, Aggregations.count());

      return count.intValue();
  }    

这导致了相同的ClassCastException

最后,我使用lambda在尝试#3中实现Predicate接口:

  public static int reportCountforSource(String sourceId) 
  {
      Predicate<String, Report> predicate = (entry) ->  entry.getValue().getSourceId().equals(sourceId);
      Supplier<String, Report, Object> supplier = Supplier.fromPredicate(predicate);
      Long count = reportMap.aggregate(supplier, Aggregations.count());

      return count.intValue();
  }    

这种尝试终于有效了。

问题#1:这是Hazelcast中的错误吗?似乎Aggregations框架应支持从PredicatePredicates构建的PredicateBuilder?如果没有,则应创建新类型(例如AggregationPredicate)以避免这种混淆。

问题#2(与#1相关):使用lambda Predicate会导致我创建的索引未被使用。相反,地图中的每个条目都被反序列化以确定它是否与Predicate匹配,这会使事情减慢很多。有没有办法从Supplier创建一个使用该索引的Predicate? (编辑:我通过在readPortable方法中放置一个计数器来验证每个条目都被反序列化。

1 个答案:

答案 0 :(得分:1)

这看起来像是一个Hazelcast错误。我想我从来没有创建过单元测试来测试PredicateBuilder创建的Predicate。你能在github上提出问题吗?

目前,mapreduce不支持索引,无论你尝试什么。索引系统将在不久的将来重写,以支持各种非原始索引,如partial或stuff。

尚未提供的另一件事是针对Portable对象的优化读取器,这将阻止完全反序列化。