Используйте Boost multi_index для комбинированных ключей

Как я могу использовать Boost multi_index для объединения трех ключей в одно выражение запроса? Рассмотрим следующую структуру индекса:

struct indexItems {
    uint64_t x; // assume non-unique index
    std::string y; // assume unique within x
    std::string z; // assume unique within y
};

Допустим, я хочу запросить элементы с помощью бинарного оператора AND: x=1 AND y="a" AND z="s". Как я могу это сделать?

Все запросы и вставки будут использовать комбинацию x+y+z для вставки, обновления и удаления элементов из multi_index. Кроме того, мне нужно перебрать y и z, отсортированные по x.

Примеры, которые я нашел до сих пор, касаются только одиночных индексов.


person benjist    schedule 28.09.2019    source источник
comment
Все ли ваши запросы имеют дело с x+y+z или вы также ищете произвольные комбинации, такие как запросы x+z и y+z?   -  person John Zwinck    schedule 28.09.2019
comment
Хороший вопрос. Я обновлю описание.   -  person benjist    schedule 28.09.2019
comment
Когда вы говорите, что мне нужно перебрать y и z, отсортированные по x, означает ли это, что вам нужно получить все значения с определенным y, а затем перебрать эти значения в порядке x? Или это означает, что вы хотите перебрать все значения, отсортированные по x?   -  person John Zwinck    schedule 28.09.2019
comment
Последний. Мне никогда не нужно запрашивать конкретный y или z, но перебирать x и все связанные y и z для этого x.   -  person benjist    schedule 28.09.2019


Ответы (1)


На самом деле вам не нужен multi_index_container для этого. Ты можешь это сделать:

inline bool operator<(const indexItems& l, const indexItems& r) {
    return std::tie(l.x, l.y, l.z) < std::tie(r.x, r.y, r.z);
}

inline bool operator==(const indexItems& l, const indexItems& r) {
    return std::tie(l.x, l.y, l.z) == std::tie(r.x, r.y, r.z);
}

std::set<indexItems> items; // or use map with any second type

Теперь у вас есть набор данных, упорядоченных сначала по x, затем по y, затем по z. Чтобы запросить x=1 AND y="a" AND z="s":

items.find(indexItems{1, "a", "s"});

Чтобы перебрать все значения, отсортированные по x (вторично отсортированные по y и z, хотя это на самом деле не требуется, это тоже не повредит):

for (const indexItems& item : items)
    // ...

В качестве бонуса, если вы хотите найти все значения в некотором диапазоне x:

auto it = items.lower_bound(indexItems{100});
auto end = items.upper_bound(indexItems{105});
for (; it != end; ++it)
    // ...
person John Zwinck    schedule 28.09.2019
comment
Очень элегантный. Спасибо. - person benjist; 28.09.2019