You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

多段线数组中最邻近多段线快速查找的算法优化方案问询(支持前Q个结果)

多段线数组中最邻近多段线快速查找的算法优化方案问询(支持前Q个结果)

场景与现有实现

我最近在处理一个多段线近邻查找的需求,目前的线性搜索方案在大数据集下实在太慢,想请教各位有没有更高效的优化思路。先跟大家说下我的场景:

我需要维护一个数据集,里面全是等长度的多段线(每条线由固定数量的3D点组成),点的顺序是严格对应的——计算两条线的距离时,是把对应位置点的曼哈顿距离累加起来。现在要做的是,给任意一条目标多段线,快速找到数据集中和它最近的那条;另外后续还需要支持返回前Q个最近的线。

目前我用的是最直接的线性搜索实现findClosest方法,小数据集跑起来没问题,但一旦数据集到几十万甚至近百万条线,每次查找的耗时就完全没法接受了。我也想过用二分查找,但实在找不到合适的规则给这些多段线排序,这条路走不通。

之前了解过k-d树这种空间索引结构,知道它适合单点的近邻查找,但完全摸不着头脑怎么把它扩展到这种由多个点组成的多段线场景。

下面是我目前的Java实现代码,方便大家理解我的数据结构和距离计算逻辑:

import java.util.Random;

public class Search {
    static class Point {
        static final int MAXIMUM = 100;
        final int x;
        final int y;
        final int z;

        Point(int x, int y, int z) {
            this.x = verify(x);
            this.y = verify(y);
            this.z = verify(z);
        }

        Point(Random random) {
            this(random.nextInt(Point.MAXIMUM), random.nextInt(Point.MAXIMUM), random.nextInt(Point.MAXIMUM));
        }

        int getDistance(Point point) {
            return Math.abs(x - point.x) + Math.abs(y - point.y) + Math.abs(z - point.z);
        }

        static int verify(int value) {
            if ((0 > value) || (MAXIMUM < value)) {
                throw new IllegalArgumentException();
            }
            return value;
        }
    }

    static class Line {
        final Point[] points;

        Line(Point[] points) {
            this.points = points;
        }

        Line(Random random, int indices) {
            points = new Point[indices];
            for (int j = 0; j < points.length; j++) {
                points[j] = new Point(random);
            }
        }

        int getDistance(Line line) {
            if (points.length != line.points.length) {
                throw new IllegalArgumentException();
            }
            int distance = 0;
            for (int i = 0; i < points.length; i++) {
                distance += points[i].getDistance(line.points[i]);
            }
            return distance;
        }
    }

    static class DataSet {
        final int indices;
        final Line[] lines;

        DataSet(Line[] lines) {
            // TODO - Verify all lines have the same number of points
            indices = lines[0].points.length;
            this.lines = lines;
        }

        DataSet(Random random) {
            indices = 1 + random.nextInt(99);
            lines = new Line[1 + random.nextInt(999999)];
            for (int i = 0; i < lines.length; i++) {
                lines[i] = new Line(random, indices);
            }
        }

        Line findClosest(Line line) {
            int closestDistance = Integer.MAX_VALUE;
            Line closestLine = null;
            for (Line nextLine : lines) {
                int distance = line.getDistance(nextLine);
                if ((Integer.MAX_VALUE == closestDistance) || (distance < closestDistance)) {
                    closestDistance = distance;
                    closestLine = nextLine;
                }
            }
            return closestLine;
        }
    }

    public static void main(String[] arguments) {
        final Random random = new Random();
        final DataSet dataSet = new DataSet(random);
        final Line arbitraryLine1 = new Line(random, dataSet.indices);
        final Line arbitraryLine2 = new Line(random, dataSet.indices);
        final Line arbitraryLineM = new Line(random, dataSet.indices);

        dataSet.findClosest(arbitraryLine1);
        dataSet.findClosest(arbitraryLine2);
        dataSet.findClosest(arbitraryLineM);
    }
}

我的具体需求与疑问

  • 现有线性搜索在百万级数据集下性能太差,有没有更高效的查找算法能适配这种多段线的场景?
  • 我知道k-d树适合单点近邻查找,但怎么扩展到这种由多个点组成的多段线?或者有没有其他更适合的空间索引结构?
  • 我的坐标值可以做任意归一化处理(比如缩放到[0,1000]、[-100,100]或者[-1.0,1.0]区间),如果归一化能帮助优化算法,完全可以做。
  • 除了找最近的一条线,后续还需要支持返回前Q个最近的线,这个需求也要考虑进去。
  • 数据集的线可以预先排序或者构建索引结构——只要能加速后续的查找,预处理的时间我完全可以接受。

有没有大佬能给我指条明路?最好能有Java相关的实现思路或者参考方案,万分感谢!

内容来源于stack exchange

火山引擎 最新活动