我正在使用ELKI 0.7.2(master)在大型数据集上运行带有R *树的DBSCAN。之后,我需要持久存储树,以便在评估新数据点是否为噪声时可以在内存中重新加载。为此,我尝试了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 *树,放入文件并从文件中加载?
非常感谢提前!
答案 0 :(得分:0)
磁盘反序列化代码多年未使用,因此很可能已损坏。
我甚至不确定它是否完全支持从磁盘独立读回索引;我假设它仅用于模拟磁盘索引以进行基准测试(即,它将从磁盘读取和写入数据,但它可能无法读取现有索引)。
这不是我需要的功能,所以除了重构之外我从未研究过这个代码。我实际上一直试图慢慢删除大部分代码(特别是ExternalizablePage
),因为我没有给人的印象。
我有一个R-tree的重写版本,更适合实际的磁盘使用。但它还没有完成,它还不支持R * -tree重新插入。因此代码尚未发布(不幸的是,可能永远不会完成)。
因此,您可能需要重写该代码的大部分内容以使其可用。
如果您这样做,请在Github上分享您的修改。
答案 1 :(得分:0)
我想问同样的问题。我的情况是一样的。如果数据集为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!");
}
它工作正常,但是我发现在某些数据群集上,恢复需要花费很长时间。 这就是为什么仍需要集群存储实现的原因。