boost::multi_index_container复合键equal_range查询实现求助
解决Boost Multi-Index复合键的范围查询问题
我明白你现在的困境:你想基于现有的复合键索引,查询指定UID,同时满足Value>500和Rank>5的元素,但equal_range只能处理精确匹配的复合键,没法直接嵌入范围条件。而且你不能添加新索引或重排容器,那我们可以利用现有复合键的排序特性来实现需求。
核心思路
现有复合键索引的排序规则是先按UID升序,再按Value升序,最后按Rank升序。所以所有UID等于目标值的元素在索引里是连续的一段。我们可以分两步操作:
- 先定位到所有
UID匹配的元素范围 - 在这个范围内筛选出满足
Value>500且Rank>5的元素
完整实现代码
#define RANKFILTERVIEW 0 #include <boost/interprocess/managed_shared_memory.hpp> #include <boost/multi_index_container.hpp> #include <boost/multi_index/composite_key.hpp> #include <boost/multi_index/member.hpp> #include <boost/multi_index/ordered_index.hpp> #include <boost/tuple/tuple.hpp> #include <algorithm> #include <vector> using namespace boost::interprocess; namespace bmi = boost::multi_index; struct TPQ { int UID; int Value; int Rank; TPQ():UID(0),Value(0),Rank(0) { } TPQ(int _T, int _V, int _R):UID(_T),Value(_V),Rank(_R) { } }; typedef allocator<TPQ, managed_shared_memory::segment_manager> shared_struct_allocator; typedef bmi::multi_index_container< TPQ, bmi::indexed_by< bmi::ordered_unique< bmi::tag<struct Composite>, bmi::composite_key<TPQ, bmi::member<TPQ, int,&TPQ::UID>, bmi::member<TPQ, int,&TPQ::Value>, bmi::member<TPQ, int,&TPQ::Rank> > > >, shared_struct_allocator > Rank_Set; typedef bmi::nth_index<Rank_Set, RANKFILTERVIEW>::type Rank_view; int main() { managed_shared_memory segment(open_only,"RANKSOTRE"); int target_UID = 52478; auto RankOrderRecord = segment.find<Rank_Set>("RANKDATARECORD"); if (!RankOrderRecord.first) { // 处理容器不存在的情况 return 1; } Rank_Set& rank_set = *RankOrderRecord.first; auto& composite_index = rank_set.get<Composite>(); // 第一步:获取所有UID等于target_UID的元素范围 auto uid_low = composite_index.lower_bound(boost::make_tuple(target_UID)); auto uid_high = composite_index.upper_bound(boost::make_tuple(target_UID)); // 第二步:在这个范围内筛选Value>500且Rank>5的元素 std::vector<TPQ> results; std::copy_if(uid_low, uid_high, std::back_inserter(results), [](const TPQ& item) { return item.Value > 500 && item.Rank > 5; }); // 现在results里就是符合条件的元素 for (const auto& item : results) { // 处理结果,比如打印 // std::cout << "UID: " << item.UID << ", Value: " << item.Value << ", Rank: " << item.Rank << std::endl; } return 0; }
关键点解释
定位UID范围:
lower_bound(make_tuple(target_UID))会找到第一个UID >= target_UID的元素upper_bound(make_tuple(target_UID))会找到第一个UID > target_UID的元素- 两者之间的区间就是所有
UID等于目标值的元素,这利用了复合键先按UID排序的特性,保证区间连续。
筛选条件:
- 因为我们不能修改现有索引,所以直接遍历UID匹配的区间,用lambda表达式过滤出满足
Value>500和Rank>5的元素。如果这个区间元素数量很大,遍历的开销会有点高,但这是在不修改索引结构前提下的最优方案。
- 因为我们不能修改现有索引,所以直接遍历UID匹配的区间,用lambda表达式过滤出满足
为什么不能用equal_range直接加条件:
equal_range要求复合键的每个部分都是精确匹配,你尝试的boost::make_tuple(UID,_2>500,_3>5)是不符合语法的,因为_2>500不是一个值,而是一个条件,equal_range无法识别这种形式。
内容的提问来源于stack exchange,提问作者Shailendra kumar
相关产品推荐
相关产品推荐

