如何在 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!");
}
它工作正常,但我发现在某些数据集群上恢复需要很长时间。
这就是为什么仍然需要集群存储实现的原因。
我在大型数据集上使用 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!");
}
它工作正常,但我发现在某些数据集群上恢复需要很长时间。 这就是为什么仍然需要集群存储实现的原因。