如何在两个不同的线程上运行LOF类的DatabaseUtil.precomputedKNNQuery方法

时间:2018-08-24 05:40:07

标签: elki

我想通过在两个不同的线程上运行该方法来减少DatabaseUtil.precomputedKNNQuery方法的运行时间,并且KNNQuery是一个接口。

    KNNQuery<O> knnq = DatabaseUtil.precomputedKNNQuery(database, relation, getDistanceFunction(), k);

我将LOF类的这种方法分为两个部分

       Callable<KNNQuery> task1(Database database, Relation<O> relation){
        DBIDs idss = relation.getDBIDs();
        ArrayDBIDs aids = (ArrayDBIDs) idss;
        aids = aids.slice(0, (aids.size() / 2));
        aids.size();
        ProxyView<O> pv = new ProxyView<>(aids, relation);
        return () -> {
            return DatabaseUtil.precomputedKNNQuery(database, pv, 
        getDistanceFunction(), k);
        };
    }

    Callable<KNNQuery> task2(Database database, Relation<O> relation) {
        DBIDs idss = relation.getDBIDs();
        ArrayDBIDs aids = (ArrayDBIDs) idss;
        aids = aids.slice(((aids.size() / 2) - 1), aids.size());
        aids.size();
        ProxyView<O> pv2 = new ProxyView<>(aids, relation);
        return () -> {
            return DatabaseUtil.precomputedKNNQuery(database, pv2, getDistanceFunction(), k);
        };
    }

然后我在LOF类的run()方法中的两个不同线程上调用了这两个任务

 public OutlierResult run(Database database, Relation<O> relation) {
StepProgress stepprog = LOG.isVerbose() ? new StepProgress("LOF", 3) : null;
DBIDs ids = relation.getDBIDs();

 LOG.beginStep(stepprog, 1, "Materializing nearest-neighbor sets.");     
 ExecutorService executor = Executors.newFixedThreadPool(2);
 List<Callable<KNNQuery>> callables = Arrays.asList(
            task1(database, relation),
            task2(database, relation));
  for (Future<KNNQuery> future : executor.invokeAll(callables)) {
       KNNQuery<O> knnq = future.get();
  // Compute LRDs
  // compute LOF_SCORE of each db object
  // Build result representation
    }
}

但是我遇到了这样的异常,因为forEach仅在knnq变量中提供第一个Future的输出,而不提供两个Future的组合输出。请帮我如何摆脱这种例外,并附上示例感谢?

de.lmu.ifi.dbs.elki.datasource.FileBasedDatabaseConnection.load: 505 ms
LOF #1/3: Materializing nearest-neighbor sets.
de.lmu.ifi.dbs.elki.index.preprocessed.knn.MaterializeKNNPreprocessor.k: 4
de.lmu.ifi.dbs.elki.index.preprocessed.knn.MaterializeKNNPreprocessor.k: 4
Materializing k nearest neighbors (k=4): 21751 [100%]  de.lmu.ifi.dbs.elki.index.preprocessed.knn.MaterializeKNNPreprocessor.precomputation-time: 21470 ms
Materializing k nearest neighbors (k=4): 21750 [100%] 
de.lmu.ifi.dbs.elki.index.preprocessed.knn.MaterializeKNNPreprocessor.precomputation-time: 22355 ms
LOF #2/3: Computing Local Reachability Densities (LRD).
Task failed
de.lmu.ifi.dbs.elki.database.datastore.ObjectNotFoundException: Object 
21751 was not found in the database.
at de.lmu.ifi.dbs.elki.database.datastore.memory.ArrayStore.get(ArrayStore.java:69)
at de.lmu.ifi.dbs.elki.index.preprocessed.knn.AbstractMaterializeKNNPreprocessor.get(AbstractMaterializeKNNPreprocessor.java:118)
at de.lmu.ifi.dbs.elki.database.query.knn.PreprocessorKNNQuery.getKNNForDBID(PreprocessorKNNQuery.java:84)
at de.lmu.ifi.dbs.elki.algorithm.outlier.lof.LOF.computeLRD(LOF.java:292)
at de.lmu.ifi.dbs.elki.algorithm.outlier.lof.LOF.computeLRDs(LOF.java:277)
at de.lmu.ifi.dbs.elki.algorithm.outlier.lof.LOF.run(LOF.java:244)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at de.lmu.ifi.dbs.elki.algorithm.AbstractAlgorithm.run(AbstractAlgorithm.java:89)
at de.lmu.ifi.dbs.elki.workflow.AlgorithmStep.runAlgorithms(AlgorithmStep.java:100)
at de.lmu.ifi.dbs.elki.KDDTask.run(KDDTask.java:109)
at de.lmu.ifi.dbs.elki.application.KDDCLIApplication.run(KDDCLIApplication.java:58)
at [...]

1 个答案:

答案 0 :(得分:0)

如果以此方式拆分数据集,则一个分区的邻居将看不到其他分区的邻居。

您似乎想并行化LOF。为什么不只使用现有的并行LOF?

https://elki-project.github.io/releases/current/doc/de/lmu/ifi/dbs/elki/algorithm/outlier/lof/parallel/ParallelLOF.html

您可以研究源代码,以了解如何将其与类似map-reduce的框架并行进行:

https://github.com/elki-project/elki/blob/9908f56f14ec76912745369edb68c07c4339eae0/elki-outlier/src/main/java/de/lmu/ifi/dbs/elki/algorithm/outlier/lof/parallel/ParallelLOF.java#L114L133

或者-更接近您现在正在执行的操作-您可以执行两个分区,在两个分区上运行LOF,然后通过复制“合并”两个LOF结果。在运行LOF之前加入kNN结果没有任何好处,因为它们将保持独立-分区A中的一个对象不会像分区数据那样设置分区B中的邻居。

请注意,DatabaseUtil.precomputedKNNQuery是许多方法中使用的功能的便捷方法。但这不是“必需”的。 ParallelLOF版本不使用它,因为它不是并行的。

在将来的ELKI 0.8中,我希望我们将拥有可以根据需要自动设置索引(包括预先计算的索引)的基础架构;并可能带有允许并行执行此操作的标志(或不允许-对于运行时比较,单线程算法通常会产生更有意义的结果)。