MTree类代码解析与实例创建技术咨询(含JUnit测试需求)
我来一步步帮你理清这两个问题,都是Java中接口实现和工具类使用的常见场景,别担心~
问题1:
cached方法中return new DistanceFunction<Data>()的含义 你看到的这个写法是Java里的匿名内部类实现——简单说就是不用单独写一个实现DistanceFunction接口的类文件,而是在方法内部直接创建接口的实现对象。
这个匿名类的核心作用是给原有的距离函数加缓存功能:
- 内部定义了一个
Pair类,用来封装两个数据对象的组合,作为缓存的key - 用
HashMap<Pair, Double>来存储已经计算过的距离值 - 重写的
calculate方法会先检查缓存:- 先查
(data1, data2)的缓存,如果有直接返回 - 再查
(data2, data1)的缓存(因为距离计算一般是对称的,比如A到B和B到A距离相同) - 如果都没有,就调用传入的原
distanceFunction计算距离,然后把正反两个Pair都存入缓存,下次再计算相同组合就直接取缓存了
- 先查
这样做的好处是避免重复计算相同数据对的距离,提升MTree的性能,毕竟MTree在构建和查询过程中会频繁计算距离。
问题2:如何创建MTree实例
其实不用实例化DistanceFunctions类(它的构造方法私有就是为了不让你实例化),它本身就是一个工具类,提供了现成的距离函数实例和工具方法,我们直接用静态成员或静态方法就行。下面分步骤说:
第一步:获取DistanceFunction实例
有三种方式可以拿到符合要求的实例:
- 用
DistanceFunctions提供的现成静态实例:
比如如果你用的是欧式坐标数据,可以直接用DistanceFunctions.EUCLIDEAN;如果是整数列表类型的坐标,用DistanceFunctions.EUCLIDEAN_INTEGER_LIST,以此类推。这些都是已经实现好的距离函数。 - 自己实现
DistanceFunction接口:
如果你的数据类型不是现成支持的,可以自己写一个实现类,或者用匿名内部类当场实现,比如:DistanceFunction<String> stringDistance = new DistanceFunction<String>() { @Override public double calculate(String data1, String data2) { // 比如实现字符串的编辑距离 return calculateEditDistance(data1, data2); } }; - 用
cached方法包装现有距离函数:
如果想给上面两种方式拿到的距离函数加缓存,直接调用DistanceFunctions.cached(...)就行,比如:DistanceFunction<EuclideanCoordinate> cachedEuclidean = DistanceFunctions.cached(DistanceFunctions.EUCLIDEAN);
第二步:创建ComposedSplitFunction实例
ComposedSplitFunction是SplitFunction的实现类,它的作用是处理MTree节点分裂的逻辑,一般可以用MTree提供的默认实现,或者自己构造:
- 通常这类分裂函数会依赖
PromotionFunction(选择要提升的节点)和PartitionFunction(划分节点数据),MTree里应该有现成的实现,比如RandomPromotionFunction和PartitionFunctions.balanced(...)之类的。 - 举个例子,创建默认的
ComposedSplitFunction:
另外,很多时候MTree会提供静态工厂方法或者默认的SplitFunction实例,你也可以看看MTree类里有没有类似// 先选一个提升函数,比如随机提升 PromotionFunction<EuclideanCoordinate> promotionFunction = new RandomPromotionFunction<>(); // 再选一个划分函数,比如平衡划分 PartitionFunction<EuclideanCoordinate> partitionFunction = PartitionFunctions.balanced(); // 组合成ComposedSplitFunction SplitFunction<EuclideanCoordinate> splitFunction = new ComposedSplitFunction<>(promotionFunction, partitionFunction);DEFAULT_SPLIT_FUNCTION这样的静态成员,直接用会更方便。
第三步:创建MTree实例
把上面拿到的DistanceFunction和SplitFunction传入构造方法就行:
// 用现成的欧式距离函数 DistanceFunction<EuclideanCoordinate> distanceFunction = DistanceFunctions.EUCLIDEAN; // 创建分裂函数 SplitFunction<EuclideanCoordinate> splitFunction = new ComposedSplitFunction<>(new RandomPromotionFunction<>(), PartitionFunctions.balanced()); // 实例化MTree MTree<EuclideanCoordinate> mTree = new MTree<>(distanceFunction, splitFunction);
如果你的数据是列表类型(比如List<Double>),可以直接用对应的距离函数:
DistanceFunction<List<Double>> distanceFunction = DistanceFunctions.EUCLIDEAN_DOUBLE_LIST; MTree<List<Double>> mTree = new MTree<>(distanceFunction, splitFunction);
内容的提问来源于stack exchange,提问作者PipiGireffa
相关产品推荐
相关产品推荐

