使用 ELKI 和 Mongodb
Posted
技术标签:
【中文标题】使用 ELKI 和 Mongodb【英文标题】:Using ELKI with Mongodb 【发布时间】:2016-01-28 06:47:18 【问题描述】:通过使用测试用例,我能够看到如何直接从 Java 中使用 ELKI,但现在我想从 MongoDB 读取我的数据,然后使用 ELKI 对地理(经纬度)数据进行聚类。
我只能使用 ELKI 对 CSV 文件中的数据进行聚类。是否可以将 de.lmu.ifi.dbs.elki.database.Database 与 MongoDB 连接?我可以从java调试器中看到de.lmu.ifi.dbs.elki.database.Database中有一个databaseconnection字段。
我查询 MongoDB 为每一行创建 POJO,现在我想使用 ELKI 对这些对象进行聚类。
可以从 MongoDB 读取数据并将其写入 CSV 文件,然后使用 ELKI 读取该 CSV 文件,但我想知道是否有更简单的解决方案。
---------发现_1:
从ELKI - Use List<String> of objects to populate the Database 我发现我需要实现 de.lmu.ifi.dbs.elki.datasource.DatabaseConnection 并专门重写返回 MultiObjectsBundle 实例的 loadData() 方法。
所以我认为我应该用 MultiObjectsBundle 包装一个 POJO 列表。现在我正在查看 MultiObjectsBundle,看起来数据应该保存在列中。为什么列数据类型是 List> 不应该是 List?只是您要聚类的项目列表?
我有点困惑。 ELKI 怎么知道它应该查看 POJO 的 long 和 lat?我在哪里告诉 ELKI 这样做?使用 de.lmu.ifi.dbs.elki.data.type.SimpleTypeInformation?
---------发现_2:
我曾尝试使用 ArrayAdapterDatabaseConnection 并尝试实现 DatabaseConnection。抱歉,我需要用非常简单的术语来理解。
这是我的聚类代码:
int minPts=3;
double eps=0.08;
double[][] data1 = -0.197574246, 51.49960695, -0.084605692, 51.52128377, -0.120973687, 51.53005939, -0.156876, 51.49313,
-0.144228881, 51.51811784, -0.1680743, 51.53430039, -0.170134484,51.52834133, -0.096440751, 51.5073853,
-0.092754157, 51.50597426, -0.122502346, 51.52395143, -0.136039674, 51.51991453, -0.123616824, 51.52994371,
-0.127854211, 51.51772703, -0.125979294, 51.52635795, -0.109006325, 51.5216612, -0.12221963, 51.51477076, -0.131161087, 51.52505093 ;
// ArrayAdapterDatabaseConnection dbcon = new ArrayAdapterDatabaseConnection(data1);
DatabaseConnection dbcon = new MyDBConnection();
ListParameterization params = new ListParameterization();
params.addParameter(de.lmu.ifi.dbs.elki.algorithm.clustering.DBSCAN.Parameterizer.MINPTS_ID, minPts);
params.addParameter(de.lmu.ifi.dbs.elki.algorithm.clustering.DBSCAN.Parameterizer.EPSILON_ID, eps);
params.addParameter(DBSCAN.DISTANCE_FUNCTION_ID, EuclideanDistanceFunction.class);
params.addParameter(AbstractDatabase.Parameterizer.DATABASE_CONNECTION_ID, dbcon);
params.addParameter(AbstractDatabase.Parameterizer.INDEX_ID,
RStarTreeFactory.class);
params.addParameter(RStarTreeFactory.Parameterizer.BULK_SPLIT_ID,
SortTileRecursiveBulkSplit.class);
params.addParameter(AbstractPageFileFactory.Parameterizer.PAGE_SIZE_ID, 1000);
Database db = ClassGenericsUtil.parameterizeOrAbort(StaticArrayDatabase.class, params);
db.initialize();
GeneralizedDBSCAN dbscan = ClassGenericsUtil.parameterizeOrAbort(GeneralizedDBSCAN.class, params);
Relation<DoubleVector> rel = db.getRelation(TypeUtil.DOUBLE_VECTOR_FIELD);
Relation<ExternalID> relID = db.getRelation(TypeUtil.EXTERNALID);
DBIDRange ids = (DBIDRange) rel.getDBIDs();
Clustering<Model> result = dbscan.run(db);
int i =0;
for(Cluster<Model> clu : result.getAllClusters())
System.out.println("#" + i + ": " + clu.getNameAutomatic());
System.out.println("Size: " + clu.size());
System.out.print("Objects: ");
for(DBIDIter it = clu.getIDs().iter(); it.valid(); it.advance())
DoubleVector v = rel.get(it);
ExternalID exID = relID.get(it);
System.out.print("DoubleVec: ["+v+"]");
System.out.print("ExID: ["+exID+"]");
final int offset = ids.getOffset(it);
System.out.print(" " + offset);
System.out.println();
++i;
ArrayAdapterDatabaseConnection 产生两个集群,当我设置 epsilon=0.008 dbscan 开始创建集群时,我只需要使用 epsilon 的值。当我设置 epsilon=0.04 时,所有项目都在 1 个集群中。
我也尝试过实现DatabaseConnection:
@Override
public MultipleObjectsBundle loadData()
MultipleObjectsBundle bundle = new MultipleObjectsBundle();
List<Station> stations = getStations();
List<DoubleVector> vecs = new ArrayList<DoubleVector>();
List<ExternalID> ids = new ArrayList<ExternalID>();
for (Station s : stations)
String strID = Integer.toString(s.getId());
ExternalID i = new ExternalID(strID);
ids.add(i);
double[] st = s.getLongitude(), s.getLatitude();
DoubleVector dv = new DoubleVector(st);
vecs.add(dv);
SimpleTypeInformation<DoubleVector> type = new VectorFieldTypeInformation<>(DoubleVector.FACTORY, 2, 2, DoubleVector.FACTORY.getDefaultSerializer());
bundle.appendColumn(type, vecs);
bundle.appendColumn(TypeUtil.EXTERNALID, ids);
return bundle;
这些 long/lat 与 ID 相关联,我需要将它们链接回此 ID 到值。使用 ID 偏移量(在上面的代码中)是唯一的方法吗?我尝试添加 ExternalID 列,但不知道如何检索特定 NumberVector 的 ExternalID?
在看到Using ELKI's Distance Function 之后,我尝试使用 Elki 的 longLatDistance 但它不起作用,我找不到任何示例来实现它。
【问题讨论】:
我觉得我应该使用这个例子中的关系 elki.dbs.ifi.lmu.de/browser/elki/elki/src/main/java/tutorial/… 但我不知道如何使它适应地理点 其实我觉得这就是我需要的elki.dbs.ifi.lmu.de/releases/release0.4.0/doc/de/lmu/ifi/dbs/…我现在只需要了解如何.. 所以.. 尝试实现 databaseConnection 我需要它以某种方式接受 long 和 lat 你看过例如的来源吗?ArrayAdapterDatabaseConnection
?
@Anony-Mousse 我已尝试实现 ArrayAdapterDatabaseConnection 请参阅我编辑的问题。谢谢。
【参考方案1】:
数据源的接口称为DatabaseConnection
。
JavaDoc of DatabaseConnection
您可以实现基于 MongoDB 的接口来获取数据。
接口不复杂,方法单一。
【讨论】:
请参阅我的问题中的编辑。我对如何实现 DatabaseConnection 有点困惑。 您想要一列DoubleVector
,因为这是距离函数所需的数据类型。您需要二维数值向量场的类型。
所以在 MultiObjectsBundle List> 列中,对于每个条目,您有 2 个 DoubleVector,一个用于 long,另一个用于 lat
SimpleTypeInformation 在哪里发挥作用?我不明白如何使用它?
你想要每个对象一个向量,很明显,还有一个VectorFieldTypeInformation
,表明该列是一个二维向量场。 (向量具有 恰好 2 维,而不是像文本向量那样的 0-1000 维)。 数学对象中的向量,而不是Java中的误称Vector
(这是一个通用列表)。以上是关于使用 ELKI 和 Mongodb的主要内容,如果未能解决你的问题,请参考以下文章