STL:在海量数据中排序和搜索
Posted
技术标签:
【中文标题】STL:在海量数据中排序和搜索【英文标题】:STL: sorting and searching in enormous data 【发布时间】:2017-04-15 20:56:35 【问题描述】:我有两组点(source
和 target
)。目标是在target
中为每个source
点找到一个唯一的1:1 最近邻 点。
我的尝试按预期工作,但速度慢得离谱。我已经测试了几千点,但在实际场景中点数将是数百万。我不是 STL 方面的专家。有什么建议可以优化吗?
std::vector<UT_Vector3> targetPosVector;
for (auto i = 0; i < targetNumPoints; i++)
auto pos = target->getPos3(i);
targetPosVector.push_back(pos);
std::vector<int> uniqueNeighborVector;
for (auto ptoff = 0; ptoff < sourceNumPoints; ptoff++)
std::vector<std::pair<int, fpreal>> nearpointVector; // neighbor vector in form of "(idx, dist)"
auto pos = source->getPos3(ptoff);
for (auto j = 0; j < targetNumPoints; j++)
fpreal dist = pos.distance(targetPosVector[j]);
std::pair<int, fpreal> neighbor j, dist;
nearpointVector.push_back(neighbor);
std::sort(nearpointVector.begin(), nearpointVector.end(), [](const std::pair<int, fpreal> &left,
const std::pair<int, fpreal> &right)
return left.second < right.second; );
std::vector<int> neighborVector;
for (auto i : nearpointVector)
neighborVector.push_back(i.first);
// trying to imitate Python's next() function
// uniqueNeighborList[]
// uneighbor = next(i for i in neighborVector if i not in uniqueNeighborVector)
// uniqueNeighborVector = set(uniqueNeighborList.append(uneighbor))
for (auto i : neighborVector)
if (std::find(uniqueNeighborVector.begin(), uniqueNeighborVector.end(), i) == uniqueNeighborVector.end())
int uneighbor = i; // later on binds to the geometry attribute
uniqueNeighborVector.push_back(i);
break;
在哪里:
source
和 target
是Detail Geometry数据
distance
是一个计算两个向量之间距离的函数
getPos3
是获取3-float vector
点位置的函数
fpreal
又名64-bit float
UT_Vector3
是 3-float vector
sourceNumPoints
和 targetNumPoints
是点数
source
和 target
几何。
【问题讨论】:
标准库确实没有针对这个任务进行优化。看看专门的库,比如PCL。 这里的问题与其说是 STL,不如说是所选择的算法。您正在生成二次距离对,因此这种方法不会扩展到数百万个点。您将需要使用某种形式的空间细分来快速拒绝不可能的配对,而不是盲目地尝试所有组合。 即便如此,即使是目前的蛮力实现也显得不必要地令人费解。我收集到一个目标点可能只匹配一次,低阶源获得第一个 dib。如果是这样,那么与其生成和排序一个临时向量,然后线性扫描整个目标集,我建议删除使用过的目标(通过交换回)并在没有中间缓冲和排序的情况下在线选择最佳匹配。诚然,它不会让您进入数百万美元,但它可能是一个开始。 目标点随机分布。让我们假设第一个点的最近邻居是 1203,而第二个点可能是 719123 之类的任何东西或具有巨大跳跃的东西。 @Pradeep Barua:太好了,(均匀的)随机分布应该让事情相对容易处理。例如,您可以尝试将目标点划分为 3D 网格结构。然后在搜索过程中直接索引最近的网格条目并逐渐向外扫描,返回并删除找到的第一个点。随着网格大小调整到密度,我相信这应该大致是线性的。 【参考方案1】:正如 cmets 中提到的,当尝试计算数百万个点时,二次复杂度是失败的。即使您优化了代码,如果方法没有改变,二次复杂度将保持不变。
在我看来,这听起来像是 R3 中的经典 NN 问题。一个众所周知的方法是使用k-d trees,它们允许 O(log n) 查询时间在 O(n log n) 构建时间和线性空间内。可以通过各种库寻求实现:nanoflann、kdtree(这些来自快速搜索,我敢肯定还有包含 k-d 树的复杂库。)
简短回顾:我会使用 3-d 树并在您的目标点集上构建它。然后取每个源点(一个接一个)并在 O(log n) 时间内找到 3-d 树中的最近邻居,每个都将导致 O(|source| log |target|) 时间和 O(|目标|) 大小。
一个相关的question。
【讨论】:
以上是关于STL:在海量数据中排序和搜索的主要内容,如果未能解决你的问题,请参考以下文章
海量数据处理 大量数据中找出最大的前10个数 (Top K 问题)