如何在 ELKI 中存储索引?

How to store index in ELKI?

我在大型数据集上使用 ELKI 0.7.2(master)进行 运行 DBSCAN 和 R* 树。之后,我需要持久存储树,以便在评估新数据点时无论它们是否为噪声,都可以将其重新加载到内存中。为此,我尝试了 PersistentPageFileFactory 并得到了以下错误

java.lang.ClassCastException: de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.rstar.RStarTreeNode cannot be cast to de.lmu.ifi.dbs.elki.persistent.ExternalizablePage

虽然简单的修改了RStarTreeNode实现了接口ExternalizablePage,但是并没有什么用。当我使用 OnDiskArrayPageFileFactory 时,我得到另一个错误如下

java.lang.RuntimeException: IOException occurred during reading of page 0
at de.lmu.ifi.dbs.elki.persistent.OnDiskArrayPageFile.readPage(OnDiskArrayPageFile.java:113)

有没有办法存储索引,例如R* 树,到文件中并从文件中加载它?

非常感谢!

磁盘反序列化代码已多年未使用,因此可能已损坏。

我什至不确定它是否完全支持独立从磁盘读取索引;我假设它的实现只是为了模拟一个 on-disk 索引以进行基准测试(即,它将从磁盘读取和写入数据,但它可能无法读取现有索引)。

这不是我需要的功能,所以除了重构之外,我从未对这段代码做过太多工作。我实际上一直在尝试慢慢删除大部分代码(特别是 ExternalizablePage),因为我没有印象它是可用的。

我在某处重写了 R-tree 版本,它更适合 on-disk 实际使用。但是还没完,还不支持R*-tree re-insertions。所以代码尚未发布(不幸的是,可能永远不会完成)。

因此您可能需要重写该代码的大部分才能使其可用。

如果您这样做,请在 Github 上分享您的修改。

我也想问同样的问题。我的情况是一样的。如果数据集是 10k 或 100K,则不需要存储集群, 但是如果你想获得 1M 或更多数据集的集群,则需要 1 个多小时。我发现很少有解决方法如何将模型存储在磁盘上。 要检测异常值,您必须从没有噪声的数据集中获取 KnnQuery。它比集群计数花费的时间更少(1M 数据集需要 1-3 分钟)。 因此,您可以对集群进行计数并仅存储属于集群的元素并使用它。

首先,按照此处所述计算簇。 https://elki-project.github.io/howto/java_api 处理结果(只保留不是噪声的点):

    List<String> clusterPoints = new ArrayList<>(); // List which will be stored in file

    for (Cluster<Model> cluster : clusters.getAllClusters()) {
        if (!cluster.isNoise()) { // write to output only not noises

            for (DBIDIter iterator = cluster.getIDs().iter(); iterator.valid(); iterator.advance()) {
                NumberVector vector = relation.get(iterator);

                for (int i = 0; i < vector.toArray().length; i++) {
                    clusterPoints.add(String.valueOf(vector.toArray()[i]));
                }
            }
        }
    }

将此 clusterPoints 保存在文件中。要恢复集群,请按照所述从文件中的点获取关系 https://elki-project.github.io/howto/java_api#creating-a-database

    double[] pointToDetect = YOUR_POINT_TO_DETECT_OUTLIER;
    // get db as described here: https://elki-project.github.io/howto/java_api#creating-a-database
    Relation<NumberVector> relation = db.getRelation(TypeUtil.NUMBER_VECTOR_FIELD);
    NumberVector vector = DoubleVector.FACTORY.newNumberVector(pointToDetect);

    KNNQuery<NumberVector> knnQuery = QueryUtil.getKNNQuery(relation, EuclideanDistanceFunction.STATIC); // or any other DistanceFunction
    KNNList list = model.getKnnQuery().getKNNForObject(vector, NEAREST_NEIGHBORS_NUMBER);

    DoubleDBIDPair pairNearest = list.get(0);
    double distanceNearest = pairNearest.doubleValue();
    if (distanceNearest > EPSILON) {
        log.warn("Outlier detected!");
    }

它工作正常,但我发现在某些数据集群上恢复需要很长时间。 这就是为什么仍然需要集群存储实现的原因。