我使用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框架应支持从Predicate
或Predicates
构建的PredicateBuilder
?如果没有,则应创建新类型(例如AggregationPredicate
)以避免这种混淆。
问题#2(与#1相关):使用lambda Predicate
会导致我创建的索引未被使用。相反,地图中的每个条目都被反序列化以确定它是否与Predicate
匹配,这会使事情减慢很多。有没有办法从Supplier
创建一个使用该索引的Predicate
? (编辑:我通过在readPortable
方法中放置一个计数器来验证每个条目都被反序列化。
答案 0 :(得分:1)
这看起来像是一个Hazelcast错误。我想我从来没有创建过单元测试来测试PredicateBuilder创建的Predicate。你能在github上提出问题吗?
目前,mapreduce不支持索引,无论你尝试什么。索引系统将在不久的将来重写,以支持各种非原始索引,如partial或stuff。
尚未提供的另一件事是针对Portable对象的优化读取器,这将阻止完全反序列化。