【问题标题】:How to run DatabaseUtil.precomputedKNNQuery method of LOF class on two different threads如何在两个不同的线程上运行 LOF 类的 DatabaseUtil.precomputedKNNQuery 方法
【发布时间】:2018-08-24 05:40:06
【问题描述】:

我想通过在两个不同的线程上运行此方法来减少 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 变量中第一个未来的输出,而不是两个未来的组合输出。请帮助我如何摆脱这个例外,例如谢谢?

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 [...]

【问题讨论】:

  • 你想做什么?您似乎要将数据集分成两部分,但这是为了什么?
  • 我想通过在两个不同的线程上运行这个方法来减少这个方法的运行时间。现在我想我告诉了我这样做的原因,所以没有理由对我的问题投反对票
  • 但是,如果将数据拆分为 A 和 B,是否会丢失一个点在 A 中而另一个点在 B 中的结果?
  • 按原样,这个问题可能对其他人没有用处,但您除外 - 目前尚不清楚您要做什么以及为什么。也许如果你编辑它以更好地解释什么和为什么,那么它可能会变得有用。
  • 你和 Elki 合作过吗?

标签: elki


【解决方案1】:

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

您似乎想要并行化 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 中,我希望我们有可以根据需要自动设置索引(包括此类预计算)的基础设施;并且可能带有一个允许并行完成的标志(或不 - 对于运行时比较,单线程算法通常会产生更有意义的结果)。

【讨论】:

  • 方法DatabaseUtil.precomputedKNNQuery不只是计算查询实例和所有训练样本之间的距离吗?
  • 不,它正在预计算 all kNN。对于单个结果,不会预先计算,而只需使用常规 kNN 查询。这适用于需要 每个 对象的 kNN 重复(因此需要存储它们)的方法,例如 LOF。没有索引的朴素方法需要 n² 距离计算。你可以看看源代码看看它做了什么!
  • 你说的是hadoop的map-reduce框架吗?
  • 是的,这个 API 有点受到 map-reduce 的启发。但是 map reduce != hadoop。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-29
  • 2012-12-04
  • 2013-07-13
  • 2020-12-16
  • 1970-01-01
相关资源
最近更新 更多