2015-04-06 36 views
0

我使用Hazelcast IMap實例來保存喜歡的對象以下內容:Hazelcast聚集API結果與謂詞

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; 
    // ... 
} 

IMapid鍵,而我也sourceId創建索引,因爲我需要根據該字段進行查詢和聚合。

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

我一直在試圖使用聚合框架,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(); 
    }  

這就產生了一個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框架應該支持由PredicatesPredicateBuilder構建的Predicate?如果不是,則應創建新類型(例如,AggregationPredicate)以避免這種混淆。

問題#2(與#1有關):使用lambda Predicate會導致我創建的索引未被使用。相反,映射中的每個條目都將被反序列化以確定它是否與Predicate相匹配,這會使事情減慢很多。有什麼辦法可以從Predicate創建一個Supplier來使用索引? (編輯:我通過在readPortable方法中加入一個計數器來驗證每個條目正在被反序列化)。

回答

1

這看起來像一個Hazelcast錯誤。我想我從來沒有創建一個單元測試來測試由PredicateBuilder創建的Predicate。你能否在github上提出問題?

無論您嘗試什麼,mapreduce都不支持當前的索引。索引系統將在不久的將來重寫,以支持各種非基本索引,如部分或東西。

另一件尚未提供的功能是用於便攜式對象的優化閱讀器,它將防止完全反序列化。

+0

感謝您的快速響應。提交:https://github.com/hazelcast/hazelcast/issues/5010 – mmindenhall

+0

完美的感謝!讚賞。 – noctarius

+0

該修復程序剛剛合併到Hazelcast主程序中,並將在即將發佈的3.6版本中發佈。 Thx報告它! –