C++ 如何在GPU(最好是CUDA)上的两个数据容器上执行关系连接?

C++ 如何在GPU(最好是CUDA)上的两个数据容器上执行关系连接?,c++,cuda,gpgpu,thrust,dynamic-parallelism,C++,Cuda,Gpgpu,Thrust,Dynamic Parallelism,我想做的是: 在GPU上,我试图模仿SQL在关系代数中用于对表执行联接的约定(例如内部联接、外部联接、交叉联接)。在下面的代码中,我想执行一个内部联接。想象两个表(容器),其中一个表是父/主表,另一个是子表。父-子连接关系是1对多(如果子\u parentId中没有与父\u id中的元素匹配的元素,则为1对无) 输入数据示例: Parent_IDs: [1, 2, 3, 4, 5] ... 5 elements Parent_Values: [0, 21, 73, 0, 91] ..

我想做的是:

在GPU上,我试图模仿SQL在关系代数中用于对表执行联接的约定(例如内部联接、外部联接、交叉联接)。在下面的代码中,我想执行一个内部联接。想象两个表(容器),其中一个表是父/主表,另一个是子表。父-子连接关系是1对多(如果子\u parentId中没有与父\u id中的元素匹配的元素,则为1对无)

输入数据示例:

Parent_IDs:    [1, 2,  3,  4, 5]  ... 5 elements
Parent_Values: [0, 21, 73, 0, 91] ... 5 elements
Child_ParentIDs:   [1,   1,   1,  2,   3,   5,  5]  ... 7 elements
Child_Permanences: [120, 477, 42, 106, 143, 53, 83] ... 7 elements
Child_Values:      [0,   0,   0,  0,   0,   0,  0]  ... 7 elements
操作作为SQL查询:

SELECT child.permanence * parent.value FROM child, parent WHERE child.parent_id = parent.id;
操作说明:

将Child\u parentId连接到Parent\u id以访问相应的Parent\u值。使用相应的父_值与相应的子_永久性相乘,并将每个操作的结果放入子_值中

预期输出(子_值是操作期间唯一更改的向量):

解释(如果没有意义):

2226的值是通过乘以106和21得出的。10439是143和73的乘积。还要注意的是,所有条目都保留在子向量上(所有7个元素仍然存在于输出中,尽管每个元素的child_值都已更新)。输出中不保留父向量(请注意,向量列表中缺少ParentID 4,并且没有“虚拟”占位符)。这是“内部联接”的行为

我没有想到的优雅解决方案:

-利用CUDA的动态并行性。也许我在整个互联网上找到的唯一的解决方案就是和

-使用CUDPP的哈希操作

-阿伦卡DB

最后,我的问题重申:

从纯GPU的角度(最好是CUDA,但OpenCL也可以)是否有任何可行的解决方案来实现两个单独的数据容器上的关系连接,以便可以通过所述连接并行地搜索数据和更新元素

编辑

父项ID并不总是一个序列。在运行时,可以删除父向量中的元素。新插入的父元素将始终附加一个ID,该ID是从最后一个元素的ID开始播种的,我理解这意味着子元素可能是孤立的,但我不在这里讨论解决方案。

它看起来像是
Child\u Permanences
元素与
父值中选定元素之间的简单元素相乘。只需几次重启,就可以通过一次
推力::转换来完成

thrust::transform(
    Child_Permanences.begin(),
    Child_Permanences.end(),
    thrust::make_permutation_iterator(
        Parent_Values.begin(),
        thrust::make_transform_iterator(Child_ParentIDs.begin(),
                                        _1 - 1)),
    Child_Values.begin(),
    _1 * _2);
您可能会注意到未使用
Parent\u id
。这是上述代码的限制。代码假定
Parent_id
只能是一个单碱基序列。您会发现,如果
Parent\u id
是一个0碱基序列,或者
Child\u parentid
只是一个父值索引,则不需要
stress::make\u transform\u迭代器,如下示例所示

Child_ParentIDs:   [0, 0, 0, 1, 2, 4, 4]
编辑

上述代码假设1)没有孤儿;和2)
Parent_id
是一个固定的基于1的序列,如
1,2,3,…


条件是

  • 没有孤儿
  • Parent_id
    无序且唯一
  • Child\u parentId
    未排序但不唯一 事实上,您的
    父ID
    属于
    int16
    类型,当
    父ID
    的范围相当小时,您可以创建一个父值索引表供子元素查找

    假设
    Parent_id
    的范围为[132767],则解决方案代码可能为

    thrust::device_vector<int> Parent_index(32768, -1);
    thrust::scatter(thrust::make_counting_iterator(0),
                    thrust::make_counting_iterator(0) + Parent_IDs.size(),
                    Parent_IDs.begin(),
                    Parent_index.begin());
    thrust::transform(
        Child_Permanences.begin(),
        Child_Permanences.end(),
        thrust::make_permutation_iterator(
            Parent_Values.begin(),
            thrust::make_permutation_iterator(
                Parent_index.begin(),
                Child_ParentIDs.begin())),
        Child_Values.begin(), _1 * _2);
    
    设备向量父索引(32768,-1); 推力::分散(推力::生成计数迭代器(0), 推力::使\u计数\u迭代器(0)+父\u id.size(), 父\u id.begin(), 父索引(index.begin()); 推力::变换( Child_Permanences.begin(), Child_Permanences.end(), 推力::生成置换迭代器( 父\u值。开始(), 推力::生成置换迭代器( 父索引。开始(), Child\u parentId.begin()), 子值。begin(),_1*_2);

  • 请注意,
    Parent\u索引
    需要在每次修改父向量时重新创建。

    TL;DR:你真的只是在问是否存在现成的解决方案吗?如果你不想读这些,那么当然,给我指一个现成的解决方案。我将根据我的需要对其进行调整,并在此处进行更新。我认为您可以基于@eg0x20中的解决方案构建一个解决方案。顺便提一下,我研究了昨天提供的解决方案:D。当“连接”的数据没有重复的ID(键)时,Robert Crovella提供的第二种方法尤其出色。他的解决方案在那里有效,因为两个容器中的数据是相同的类型(能够在顺序键上合并,然后在内核中偏移1以应用乘法)。我的需求有点不同(注意重复的Child\u parentId)。如果由于父项删除而出现孤立子项,您希望结果如何?或者只有父项添加而没有删除?关于从1开始而不是从0开始的父项ID,您是正确的,但是建议的实现将不起作用,因为父项ID并不总是一个序列(尽管它们总是唯一的)。假设父元素从父向量的第n个位置移除。我之所以使用SQL内部联接来解释我所寻找的内容,是因为它说明了要删除的父元素;例如在数据库表删除操作中。它没有0或1碱基序列依赖关系。不过,您提出的关于不必使用推力::make_transform_迭代器的观点很有帮助。我选择1-base的唯一原因是
    thrust::device_vector<int> Parent_index(32768, -1);
    thrust::scatter(thrust::make_counting_iterator(0),
                    thrust::make_counting_iterator(0) + Parent_IDs.size(),
                    Parent_IDs.begin(),
                    Parent_index.begin());
    thrust::transform(
        Child_Permanences.begin(),
        Child_Permanences.end(),
        thrust::make_permutation_iterator(
            Parent_Values.begin(),
            thrust::make_permutation_iterator(
                Parent_index.begin(),
                Child_ParentIDs.begin())),
        Child_Values.begin(), _1 * _2);