SERVER-114476 Simplify JoinGraph representation (#44914)

GitOrigin-RevId: b57964a48368c379d687fa7d78ac04cfd86ddc6d
This commit is contained in:
Alexander Ignatyev 2025-12-08 15:35:26 +00:00 committed by MongoDB Bot
parent 78eb7793b2
commit 1485ff664a
26 changed files with 297 additions and 516 deletions

View File

@ -37,14 +37,8 @@ AdjacencyMatrix makeAdjacencyMatrix(const JoinGraph& joinGraph,
AdjacencyMatrix matrix; AdjacencyMatrix matrix;
for (auto edgeId : subgraph) { for (auto edgeId : subgraph) {
const auto& edge = joinGraph.getEdge(edgeId); const auto& edge = joinGraph.getEdge(edgeId);
matrix[edge.left].set(edge.right);
for (auto leftNodeId : iterable(edge.left, joinGraph.numNodes())) { matrix[edge.right].set(edge.left);
matrix[leftNodeId] |= edge.right;
}
for (auto rightNodeId : iterable(edge.right, joinGraph.numNodes())) {
matrix[rightNodeId] |= edge.left;
}
} }
return matrix; return matrix;

View File

@ -118,122 +118,6 @@ TEST(AdjacencyMatrixBuilderTest, Smoke) {
} }
} }
TEST(AdjacencyMatrixBuilderTest, OneToAllEdge) {
JoinGraph graph;
auto node0 = addNode(graph);
auto node1 = addNode(graph);
auto node2 = addNode(graph);
auto node3 = addNode(graph);
auto node4 = addNode(graph);
NodeSet left{};
left.set(node0);
NodeSet right;
right.set(node1);
right.set(node2);
right.set(node3);
right.set(node4);
auto edge = *graph.addEdge(left, right, {});
auto expectedMatrix = makeMatrix({
"11110",
"00001",
"00001",
"00001",
"00001",
});
ASSERT_EQ(makeAdjacencyMatrix(graph, {edge}), expectedMatrix);
}
TEST(AdjacencyMatrixBuilderTest, DoubleEdges) {
JoinGraph graph;
auto node0 = addNode(graph);
auto node1 = addNode(graph);
auto node2 = addNode(graph);
auto node3 = addNode(graph);
auto node4 = addNode(graph);
auto node5 = addNode(graph);
NodeSet left{};
NodeSet right{};
left.set(node0);
left.set(node2);
right.set(node1);
right.set(node3);
const auto edge0213 = *graph.addEdge(left, right, {});
left.reset();
right.reset();
left.set(node2);
left.set(node4);
right.set(node3);
right.set(node5);
const auto edge2435 = *graph.addEdge(left, right, {});
left.reset();
right.reset();
left.set(node3);
left.set(node5);
right.set(node0);
right.set(node2);
const auto edge3502 = *graph.addEdge(left, right, {});
// No edges case
{
auto expectedMatrix = makeMatrix({
"000000",
"000000",
"000000",
"000000",
"000000",
"000000",
});
ASSERT_EQ(makeAdjacencyMatrix(graph, {}), expectedMatrix);
}
// Single edge case
{
auto expectedMatrix = makeMatrix({
"001010",
"000101",
"001010",
"000101",
"000000",
"000000",
});
ASSERT_EQ(makeAdjacencyMatrix(graph, {edge0213}), expectedMatrix);
}
// two edges case
{
auto expectedMatrix = makeMatrix({
"001010",
"000101",
"101010",
"010101",
"101000",
"010100",
});
ASSERT_EQ(makeAdjacencyMatrix(graph, {edge0213, edge2435}), expectedMatrix);
}
// three edges case
{
auto expectedMatrix = makeMatrix({
"101010",
"000101",
"101010",
"010101",
"101000",
"010101",
});
ASSERT_EQ(makeAdjacencyMatrix(graph, {edge0213, edge2435, edge3502}), expectedMatrix);
}
}
TEST(AdjacencyMatrixBuilderTest, FullyConnectedGraph) { TEST(AdjacencyMatrixBuilderTest, FullyConnectedGraph) {
JoinGraph graph; JoinGraph graph;
auto node0 = addNode(graph); auto node0 = addNode(graph);

View File

@ -97,7 +97,7 @@ boost::optional<EdgeId> GraphCycleBreaker::findEdgeId(NodeId u,
const std::vector<EdgeId>& edges) const { const std::vector<EdgeId>& edges) const {
for (auto edgeId : edges) { for (auto edgeId : edges) {
const auto& edge = _graph.getEdge(edgeId); const auto& edge = _graph.getEdge(edgeId);
if ((edge.left[u] && edge.right[v]) || (edge.left[v] && edge.right[u])) { if ((edge.left == u && edge.right == v) || (edge.left == v && edge.right == u)) {
return edgeId; return edgeId;
} }
} }

View File

@ -51,7 +51,7 @@ public:
} }
EdgeId addEdge(NodeId u, NodeId v) { EdgeId addEdge(NodeId u, NodeId v) {
return *graph.addEdge(makeNodeSetFromId(u), makeNodeSetFromId(v), {}); return *graph.addEdge(u, v, {});
} }
template <typename... EdgeIds> template <typename... EdgeIds>

View File

@ -50,12 +50,6 @@ BSONObj canonicalQueryToBSON(const std::unique_ptr<CanonicalQuery>& cq) {
return accessPathBSON.obj(); return accessPathBSON.obj();
} }
void order(NodeSet& u, NodeSet& v) {
if (bitsetLess(v, u)) {
swap(u, v);
}
}
static void swapPredicateSides(JoinEdge::PredicateList& predicates) { static void swapPredicateSides(JoinEdge::PredicateList& predicates) {
std::for_each(predicates.begin(), predicates.end(), [](JoinPredicate& pred) { std::for_each(predicates.begin(), predicates.end(), [](JoinPredicate& pred) {
tassert(11233806, tassert(11233806,
@ -87,8 +81,8 @@ BSONObj JoinEdge::toBSON() const {
} }
result.append("predicates", ab.arr()); result.append("predicates", ab.arr());
} }
result.append("left", left.to_string()); result.append("left", left);
result.append("right", right.to_string()); result.append("right", right);
return result.obj(); return result.obj();
} }
@ -117,8 +111,7 @@ std::vector<EdgeId> JoinGraph::getJoinEdges(NodeSet left, NodeSet right) const {
for (size_t edgeIndex = 0; edgeIndex < _edges.size(); ++edgeIndex) { for (size_t edgeIndex = 0; edgeIndex < _edges.size(); ++edgeIndex) {
const auto& edge = _edges[edgeIndex]; const auto& edge = _edges[edgeIndex];
if (((left & edge.left).any() && (right & edge.right).any()) || if ((left[edge.left] && right[edge.right]) || (left[edge.right] && right[edge.left])) {
((left & edge.right).any() && (right & edge.left).any())) {
result.push_back(static_cast<EdgeId>(edgeIndex)); result.push_back(static_cast<EdgeId>(edgeIndex));
} }
} }
@ -128,10 +121,10 @@ std::vector<EdgeId> JoinGraph::getJoinEdges(NodeSet left, NodeSet right) const {
NodeSet JoinGraph::getNeighbors(NodeId nodeIndex) const { NodeSet JoinGraph::getNeighbors(NodeId nodeIndex) const {
NodeSet neighbors; NodeSet neighbors;
for (const JoinEdge& edge : _edges) { for (const JoinEdge& edge : _edges) {
if (edge.left.test(nodeIndex)) { if (edge.left == nodeIndex) {
neighbors |= edge.right; neighbors.set(edge.right);
} else if (edge.right.test(nodeIndex)) { } else if (edge.right == nodeIndex) {
neighbors |= edge.left; neighbors.set(edge.left);
} }
} }
return neighbors; return neighbors;
@ -148,15 +141,12 @@ boost::optional<NodeId> JoinGraph::addNode(NamespaceString collectionName,
return static_cast<NodeId>(_nodes.size()) - 1; return static_cast<NodeId>(_nodes.size()) - 1;
} }
boost::optional<EdgeId> JoinGraph::addEdge(NodeSet left, boost::optional<EdgeId> JoinGraph::addEdge(NodeId left,
NodeSet right, NodeId right,
JoinEdge::PredicateList predicates) { JoinEdge::PredicateList predicates) {
// Self-edges are not permitted; when joining a collection to itself, we should use a different // Self-edges are not permitted; when joining a collection to itself, we should use a different
// node for each instance of the collection. // node for each instance of the collection.
if (const auto common = (left & right); common.any()) { tassert(11180001, "Self edges are not permitted", left != right);
tasserted(11180001,
"Self edges are not permitted, but both sides contain " + common.to_string());
}
if (auto edgeId = findEdge(left, right); edgeId.has_value()) { if (auto edgeId = findEdge(left, right); edgeId.has_value()) {
auto&& edge = _edges[*edgeId]; auto&& edge = _edges[*edgeId];
@ -170,21 +160,9 @@ boost::optional<EdgeId> JoinGraph::addEdge(NodeSet left,
return makeEdge(left, right, std::move(predicates)); return makeEdge(left, right, std::move(predicates));
} }
boost::optional<EdgeId> JoinGraph::addSimpleEqualityEdge(NodeId leftNode, boost::optional<EdgeId> JoinGraph::findEdge(NodeId u, NodeId v) const {
NodeId rightNode, NodeSet key = makeNodeSet(u, v);
PathId leftPathId, auto pos = _edgeMap.find(key);
PathId rightPathId) {
NodeSet leftNodeSet{};
leftNodeSet.set(leftNode);
NodeSet rightNodeSet{};
rightNodeSet.set(rightNode);
return addEdge(leftNodeSet, rightNodeSet, {{JoinPredicate::Eq, leftPathId, rightPathId}});
}
boost::optional<EdgeId> JoinGraph::findEdge(NodeSet u, NodeSet v) const {
order(u, v); // make sure that u <= v
auto pos = _edgeMap.find(std::make_pair(u, v));
if (pos == _edgeMap.end()) { if (pos == _edgeMap.end()) {
return boost::none; return boost::none;
} }
@ -211,15 +189,15 @@ BSONObj JoinGraph::toBSON() const {
return result.obj(); return result.obj();
} }
boost::optional<EdgeId> JoinGraph::makeEdge(NodeSet left, boost::optional<EdgeId> JoinGraph::makeEdge(NodeId left,
NodeSet right, NodeId right,
JoinEdge::PredicateList predicates) { JoinEdge::PredicateList predicates) {
if (bitsetLess(right, left)) { if (right < left) {
swap(left, right); std::swap(left, right);
swapPredicateSides(predicates); swapPredicateSides(predicates);
} }
auto key = std::make_pair(left, right); NodeSet key = makeNodeSet(left, right);
tassert(11116501, "The edge has been already added", !_edgeMap.contains(key)); tassert(11116501, "The edge has been already added", !_edgeMap.contains(key));
EdgeId edgeId = static_cast<EdgeId>(_edges.size()); EdgeId edgeId = static_cast<EdgeId>(_edges.size());

View File

@ -53,6 +53,16 @@ constexpr size_t kMaxEdgesInJoin = std::numeric_limits<EdgeId>::max();
*/ */
using NodeSet = std::bitset<kMaxNodesInJoin>; using NodeSet = std::bitset<kMaxNodesInJoin>;
/**
* Creates NodeSet from the list of node ids.
*/
template <typename... NodeIds>
NodeSet makeNodeSet(NodeIds... nodeIds) {
NodeSet nodeSet;
((void)nodeSet.set(nodeIds), ...);
return nodeSet;
}
/** JoinNode represents a single occurrence of a collection in a query. A new join node is created /** JoinNode represents a single occurrence of a collection in a query. A new join node is created
for each time a collection appears. This ensures every instance is uniquely identified within the for each time a collection appears. This ensures every instance is uniquely identified within the
join graph. join graph.
@ -97,19 +107,20 @@ struct JoinPredicate {
/** /**
* Represents an undirected join edge between two sets of collections. * Represents an undirected join edge between two sets of collections.
* *
* Only one-to-one connections are currently supported. To prepare for future many-to-many join edge * These edges support only one to one connections and considered to be the first-class citizens of
* support, the left and right sides are defined as NodeSets. * the join graph, since complex not one-to-one edges cannot be used in join plan enumeration
* and to be stored separately with indexes >= kMaxNodesInJoin.
*/ */
struct JoinEdge { struct JoinEdge {
using PredicateList = absl::InlinedVector<JoinPredicate, 2>; using PredicateList = absl::InlinedVector<JoinPredicate, 2>;
PredicateList predicates; PredicateList predicates;
NodeSet left; NodeId left;
NodeSet right; NodeId right;
NodeSet getBitset() const { NodeSet getBitset() const {
return left | right; return makeNodeSet(left, right);
} }
/** Serializes the Join Edge to BSON. /** Serializes the Join Edge to BSON.
@ -167,9 +178,7 @@ public:
* Returns the id of the edge or boost::none if the maximum number of join edges has been * Returns the id of the edge or boost::none if the maximum number of join edges has been
* reached. * reached.
*/ */
boost::optional<EdgeId> addEdge(NodeSet left, boost::optional<EdgeId> addEdge(NodeId left, NodeId right, JoinEdge::PredicateList predicates);
NodeSet right,
JoinEdge::PredicateList predicates);
/** /**
* Adds a new edge or add predicates if the edge with the specified 'left' and 'right' exists. * Adds a new edge or add predicates if the edge with the specified 'left' and 'right' exists.
@ -179,21 +188,15 @@ public:
boost::optional<EdgeId> addSimpleEqualityEdge(NodeId leftNode, boost::optional<EdgeId> addSimpleEqualityEdge(NodeId leftNode,
NodeId rightNode, NodeId rightNode,
PathId leftPathId, PathId leftPathId,
PathId rightPathId); PathId rightPathId) {
return addEdge(leftNode, rightNode, {{JoinPredicate::Eq, leftPathId, rightPathId}});
}
/** /**
* Returns EdgeId of the edge that connects u and v. This check is order-independent, meaning * Returns EdgeId of the edge that connects u and v. This check is order-independent, meaning
* the returned edge might be (u, v) or (v, u). * the returned edge might be (u, v) or (v, u).
*/ */
boost::optional<EdgeId> findEdge(NodeSet u, NodeSet v) const; boost::optional<EdgeId> findEdge(NodeId u, NodeId v) const;
boost::optional<EdgeId> findSimpleEdge(NodeId u, NodeId v) const {
NodeSet uns{};
uns.set(u);
NodeSet vns{};
vns.set(v);
return findEdge(uns, vns);
}
const JoinNode& getNode(NodeId nodeId) const { const JoinNode& getNode(NodeId nodeId) const {
if constexpr (kDebugBuild) { if constexpr (kDebugBuild) {
@ -245,15 +248,12 @@ private:
* maintains the invariant that only a single edge exists between any two node sets containing * maintains the invariant that only a single edge exists between any two node sets containing
* the conjunction of all predicates. * the conjunction of all predicates.
*/ */
boost::optional<EdgeId> makeEdge(NodeSet left, boost::optional<EdgeId> makeEdge(NodeId left, NodeId right, JoinEdge::PredicateList predicates);
NodeSet right,
JoinEdge::PredicateList predicates);
std::vector<JoinNode> _nodes; std::vector<JoinNode> _nodes;
std::vector<JoinEdge> _edges; std::vector<JoinEdge> _edges;
// Maps a pair of nodesets to the edge that connects them, The node sets are stored // Maps a pair of nodeIds to the edge that connects them.
// in a key in the way that the first node is smaller than the second one. absl::flat_hash_map<NodeSet, EdgeId> _edgeMap;
absl::flat_hash_map<std::pair<NodeSet, NodeSet>, EdgeId> _edgeMap;
}; };
} // namespace mongo::join_ordering } // namespace mongo::join_ordering

View File

@ -65,17 +65,17 @@ TEST(JoinGraphTests, AddEdge) {
ASSERT_TRUE(firstSecond.has_value()); ASSERT_TRUE(firstSecond.has_value());
ASSERT_TRUE(secondThird.has_value()); ASSERT_TRUE(secondThird.has_value());
ASSERT_EQ(graph.getEdge(*firstSecond).left, 1 << first); ASSERT_EQ(graph.getEdge(*firstSecond).left, first);
ASSERT_EQ(graph.getEdge(*firstSecond).right, 1 << second); ASSERT_EQ(graph.getEdge(*firstSecond).right, second);
ASSERT_EQ(graph.getEdge(*secondThird).left, 1 << second); ASSERT_EQ(graph.getEdge(*secondThird).left, second);
ASSERT_EQ(graph.getEdge(*secondThird).right, 1 << third); ASSERT_EQ(graph.getEdge(*secondThird).right, third);
ASSERT_EQ(graph.findSimpleEdge(first, second), firstSecond); ASSERT_EQ(graph.findEdge(first, second), firstSecond);
ASSERT_EQ(graph.findSimpleEdge(second, first), firstSecond); ASSERT_EQ(graph.findEdge(second, first), firstSecond);
ASSERT_EQ(graph.findSimpleEdge(second, third), secondThird); ASSERT_EQ(graph.findEdge(second, third), secondThird);
ASSERT_EQ(graph.findSimpleEdge(third, second), secondThird); ASSERT_EQ(graph.findEdge(third, second), secondThird);
ASSERT_EQ(graph.findSimpleEdge(first, third), boost::none); ASSERT_EQ(graph.findEdge(first, third), boost::none);
ASSERT_EQ(graph.findSimpleEdge(third, first), boost::none); ASSERT_EQ(graph.findEdge(third, first), boost::none);
} }
DEATH_TEST(JoinGraphTestsDeathTest, DEATH_TEST(JoinGraphTestsDeathTest,
@ -90,19 +90,6 @@ DEATH_TEST(JoinGraphTestsDeathTest,
graph.addSimpleEqualityEdge(a, a, 0, 1); graph.addSimpleEqualityEdge(a, a, 0, 1);
} }
DEATH_TEST(JoinGraphTestsDeathTest,
AddEdgeComplexSelfEdgeForbidden,
"Self edges are not permitted") {
JoinGraph graph{};
auto a = *graph.addNode(makeNSS("a"), nullptr, boost::none);
auto b = *graph.addNode(makeNSS("b"), nullptr, boost::none);
auto c = *graph.addNode(makeNSS("c"), nullptr, boost::none);
// Try adding a complex self-edge (a,b) -- (b,c).
graph.addEdge(makeNodeSetFromIds({a, b}), makeNodeSetFromIds({b, c}), {});
}
TEST(JoinGraphTests, getJoinEdges) { TEST(JoinGraphTests, getJoinEdges) {
JoinGraph graph{}; JoinGraph graph{};
@ -140,16 +127,16 @@ TEST(JoinGraph, MultiplePredicatesSameEdge) {
ASSERT_EQ(ab, ab2); ASSERT_EQ(ab, ab2);
ASSERT_EQ(ab2, ab3); ASSERT_EQ(ab2, ab3);
auto edges = graph.getJoinEdges(makeNodeSetFromId(a), makeNodeSetFromId(b)); auto edges = graph.getJoinEdges(makeNodeSet(a), makeNodeSet(b));
ASSERT_EQ(1, edges.size()); ASSERT_EQ(1, edges.size());
// Edge returned when order of nodes reversed // Edge returned when order of nodes reversed
ASSERT_EQ(edges, graph.getJoinEdges(makeNodeSetFromId(b), makeNodeSetFromId(a))); ASSERT_EQ(edges, graph.getJoinEdges(makeNodeSet(b), makeNodeSet(a)));
auto edge = graph.getEdge(edges[0]); auto edge = graph.getEdge(edges[0]);
ASSERT_EQ(edge.left, makeNodeSetFromId(a)); ASSERT_EQ(edge.left, a);
ASSERT_EQ(edge.right, makeNodeSetFromId(b)); ASSERT_EQ(edge.right, b);
ASSERT_BSONOBJ_EQ_AUTO( ASSERT_BSONOBJ_EQ_AUTO(
R"({ R"({
"predicates": [ "predicates": [
@ -169,8 +156,8 @@ TEST(JoinGraph, MultiplePredicatesSameEdge) {
"right": 5 "right": 5
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000010" "right": {"$numberInt":"1"}
})", })",
edge.toBSON()); edge.toBSON());
} }
@ -197,41 +184,13 @@ TEST(JoinGraphTests, GetNeighborsSimpleEqualityEdges) {
graph.addSimpleEqualityEdge(c, d, 4, 5); graph.addSimpleEqualityEdge(c, d, 4, 5);
// A connected to b,c. B connected to a. C connected to a,d. D connected to c. E not connected. // A connected to b,c. B connected to a. C connected to a,d. D connected to c. E not connected.
ASSERT_EQ(graph.getNeighbors(a), makeNodeSetFromIds({b, c})); ASSERT_EQ(graph.getNeighbors(a), makeNodeSet(b, c));
ASSERT_EQ(graph.getNeighbors(b), makeNodeSetFromIds({a})); ASSERT_EQ(graph.getNeighbors(b), makeNodeSet(a));
ASSERT_EQ(graph.getNeighbors(c), makeNodeSetFromIds({a, d})); ASSERT_EQ(graph.getNeighbors(c), makeNodeSet(a, d));
ASSERT_EQ(graph.getNeighbors(d), makeNodeSetFromIds({c})); ASSERT_EQ(graph.getNeighbors(d), makeNodeSet(c));
ASSERT_EQ(graph.getNeighbors(e), NodeSet{}); ASSERT_EQ(graph.getNeighbors(e), NodeSet{});
} }
TEST(JoinGraphTests, GetNeighborsComplexEdge) {
JoinGraph graph{};
auto a = *graph.addNode(makeNSS("a"), nullptr, boost::none);
auto b = *graph.addNode(makeNSS("b"), nullptr, boost::none);
auto c = *graph.addNode(makeNSS("c"), nullptr, boost::none);
auto d = *graph.addNode(makeNSS("d"), nullptr, boost::none);
auto e = *graph.addNode(makeNSS("e"), nullptr, boost::none);
// Add a complex edge (a,b) <-> (c,d) which could represent, for example, the predicate (a.a=c.c
// AND b.b=d.d). Also add simple edge d -- e.
graph.addEdge(makeNodeSetFromIds({a, b}),
makeNodeSetFromIds({c, d}),
{
{JoinPredicate::Eq, 0, 1},
{JoinPredicate::Eq, 2, 3},
});
graph.addEdge(makeNodeSetFromIds({d}), makeNodeSetFromIds({e}), {});
// A connected to c,d. B connected to c,d. C connected to a,b. D connected to a,b. E connected
// to d. Note: a and b are not connected.
ASSERT_EQ(graph.getNeighbors(a), makeNodeSetFromIds({c, d}));
ASSERT_EQ(graph.getNeighbors(b), makeNodeSetFromIds({c, d}));
ASSERT_EQ(graph.getNeighbors(c), makeNodeSetFromIds({a, b}));
ASSERT_EQ(graph.getNeighbors(d), makeNodeSetFromIds({a, b, e}));
ASSERT_EQ(graph.getNeighbors(e), makeNodeSetFromIds({d}));
}
TEST(JoinGraph, GetNeighborsMultiEdges) { TEST(JoinGraph, GetNeighborsMultiEdges) {
JoinGraph graph{}; JoinGraph graph{};
@ -241,12 +200,12 @@ TEST(JoinGraph, GetNeighborsMultiEdges) {
// Now add two edges between "a" and "b". These could in theory be simplified into a single // Now add two edges between "a" and "b". These could in theory be simplified into a single
// complex edge with multiple predicates, but this demonstrates that getNeighbors supports it. // complex edge with multiple predicates, but this demonstrates that getNeighbors supports it.
graph.addEdge(makeNodeSetFromIds({a}), makeNodeSetFromIds({b}), {}); graph.addEdge(a, b, {});
graph.addEdge(makeNodeSetFromIds({b}), makeNodeSetFromIds({a}), {}); graph.addEdge(b, a, {});
// A connected to b. B connected to a. // A connected to b. B connected to a.
ASSERT_EQ(graph.getNeighbors(a), makeNodeSetFromIds({b})); ASSERT_EQ(graph.getNeighbors(a), makeNodeSet(b));
ASSERT_EQ(graph.getNeighbors(b), makeNodeSetFromIds({a})); ASSERT_EQ(graph.getNeighbors(b), makeNodeSet(a));
ASSERT_EQ(graph.getNeighbors(c), NodeSet{}); ASSERT_EQ(graph.getNeighbors(c), NodeSet{});
} }
@ -259,15 +218,15 @@ TEST(JoinGraph, GetNeighborsCycle) {
auto d = *graph.addNode(makeNSS("d"), nullptr, boost::none); auto d = *graph.addNode(makeNSS("d"), nullptr, boost::none);
// Introduce a cycle involving all four nodes. // Introduce a cycle involving all four nodes.
graph.addEdge(makeNodeSetFromIds({a}), makeNodeSetFromIds({b}), {}); graph.addEdge(a, b, {});
graph.addEdge(makeNodeSetFromIds({b}), makeNodeSetFromIds({c}), {}); graph.addEdge(b, c, {});
graph.addEdge(makeNodeSetFromIds({c}), makeNodeSetFromIds({d}), {}); graph.addEdge(c, d, {});
graph.addEdge(makeNodeSetFromIds({d}), makeNodeSetFromIds({a}), {}); graph.addEdge(d, a, {});
// Each node is connected to only two others. // Each node is connected to only two others.
ASSERT_EQ(graph.getNeighbors(a), makeNodeSetFromIds({b, d})); ASSERT_EQ(graph.getNeighbors(a), makeNodeSet(b, d));
ASSERT_EQ(graph.getNeighbors(b), makeNodeSetFromIds({a, c})); ASSERT_EQ(graph.getNeighbors(b), makeNodeSet(a, c));
ASSERT_EQ(graph.getNeighbors(c), makeNodeSetFromIds({b, d})); ASSERT_EQ(graph.getNeighbors(c), makeNodeSet(b, d));
ASSERT_EQ(graph.getNeighbors(d), makeNodeSetFromIds({a, c})); ASSERT_EQ(graph.getNeighbors(d), makeNodeSet(a, c));
} }
} // namespace mongo::join_ordering } // namespace mongo::join_ordering

View File

@ -84,15 +84,6 @@ JoinPredicateEstimator::JoinPredicateEstimator(const JoinGraph& graph,
_samplingEstimators(samplingEstimators), _samplingEstimators(samplingEstimators),
_tableCards(tableCards) {} _tableCards(tableCards) {}
namespace {
// Given a NodeSet with a single bit set, return the index of that bit.
std::size_t getIndexOfBit(const NodeSet& ns) {
return std::countr_zero(ns.to_ullong());
}
} // namespace
// This function makes a number of assumptions: // This function makes a number of assumptions:
// * Join predicate are independent from single table predicates. This allows us to estimate them // * Join predicate are independent from single table predicates. This allows us to estimate them
// separately, which can be seen by our use of NDV(join key) over the entire collection, as opposed // separately, which can be seen by our use of NDV(join key) over the entire collection, as opposed
@ -136,12 +127,9 @@ std::size_t getIndexOfBit(const NodeSet& ns) {
// both sides reference the primary key. Again, we use the side with the smaller CE for simplicity. // both sides reference the primary key. Again, we use the side with the smaller CE for simplicity.
cost_based_ranker::SelectivityEstimate JoinPredicateEstimator::joinPredicateSel( cost_based_ranker::SelectivityEstimate JoinPredicateEstimator::joinPredicateSel(
const JoinEdge& edge) { const JoinEdge& edge) {
tassert(11352501,
"join predicate selectivity estimation only supports single collection on both sides",
edge.left.count() == 1 && edge.right.count() == 1);
auto& leftNode = _graph.getNode(getIndexOfBit(edge.left)); auto& leftNode = _graph.getNode(edge.left);
auto& rightNode = _graph.getNode(getIndexOfBit(edge.right)); auto& rightNode = _graph.getNode(edge.right);
// Extract the cardinality estimates for left and right nodes before single table predicates are // Extract the cardinality estimates for left and right nodes before single table predicates are
// applied. // applied.

View File

@ -116,8 +116,6 @@ public:
std::vector<IndexedJoinPredicate> makeIndexedJoinPreds(const JoinEdge& edge, std::vector<IndexedJoinPredicate> makeIndexedJoinPreds(const JoinEdge& edge,
NodeId currentNode) const { NodeId currentNode) const {
tassert(11233804, "left edge expected only one node", edge.left.count() == 1);
tassert(11233805, "right edge expected only one node", edge.right.count() == 1);
std::vector<IndexedJoinPredicate> res; std::vector<IndexedJoinPredicate> res;
for (auto&& pred : edge.predicates) { for (auto&& pred : edge.predicates) {
res.push_back({ res.push_back({
@ -174,7 +172,7 @@ public:
// members. We are exploiting this implementation detail to avoid doing duplicate work // members. We are exploiting this implementation detail to avoid doing duplicate work
// of determining the orientation in making the 'IndexedJoinPredicate' and the // of determining the orientation in making the 'IndexedJoinPredicate' and the
// 'QSNJoinPredicate' below. // 'QSNJoinPredicate' below.
if ((edge.left & right).any()) { if (right.test(edge.left)) {
edge = edge.reverseEdge(); edge = edge.reverseEdge();
} }

View File

@ -117,12 +117,4 @@ std::unique_ptr<ce::SamplingEstimator> JoinOrderingTestFixture::samplingEstimato
NamespaceString makeNSS(StringData collName) { NamespaceString makeNSS(StringData collName) {
return NamespaceString::makeLocalCollection(collName); return NamespaceString::makeLocalCollection(collName);
} }
NodeSet makeNodeSetFromIds(std::set<NodeId> ids) {
NodeSet result;
for (auto id : ids) {
result.set(id);
}
return result;
}
} // namespace mongo::join_ordering } // namespace mongo::join_ordering

View File

@ -123,16 +123,4 @@ private:
* Small utility function to make a namepace string from collection name. * Small utility function to make a namepace string from collection name.
*/ */
NamespaceString makeNSS(StringData collName); NamespaceString makeNSS(StringData collName);
/**
* Creates a join graph node from the set of ids.
*/
NodeSet makeNodeSetFromIds(std::set<NodeId> ids);
/**
* Creates a join graph node from a single id.
*/
inline NodeSet makeNodeSetFromId(NodeId id) {
return makeNodeSetFromIds({id});
}
} // namespace mongo::join_ordering } // namespace mongo::join_ordering

View File

@ -83,8 +83,8 @@ output: {
"right": {"$numberInt":"1"} "right": {"$numberInt":"1"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000010" "right": {"$numberInt":"1"}
}, },
{ {
"predicates": [ "predicates": [
@ -94,8 +94,8 @@ output: {
"right": {"$numberInt":"2"} "right": {"$numberInt":"2"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000010", "left": {"$numberInt":"1"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
}, },
{ {
"predicates": [ "predicates": [
@ -105,8 +105,8 @@ output: {
"right": {"$numberInt":"3"} "right": {"$numberInt":"3"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000100", "left": {"$numberInt":"2"},
"right": "0000000000000000000000000000000000000000000000000000000000001000" "right": {"$numberInt":"3"}
}, },
{ {
"predicates": [ "predicates": [
@ -116,8 +116,8 @@ output: {
"right": {"$numberInt":"2"} "right": {"$numberInt":"2"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
}, },
{ {
"predicates": [ "predicates": [
@ -127,8 +127,8 @@ output: {
"right": {"$numberInt":"3"} "right": {"$numberInt":"3"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000001000" "right": {"$numberInt":"3"}
}, },
{ {
"predicates": [ "predicates": [
@ -138,8 +138,8 @@ output: {
"right": {"$numberInt":"3"} "right": {"$numberInt":"3"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000010", "left": {"$numberInt":"1"},
"right": "0000000000000000000000000000000000000000000000000000000000001000" "right": {"$numberInt":"3"}
} }
] ]
}, },

View File

@ -123,8 +123,8 @@ output: {
"right": {"$numberInt":"1"} "right": {"$numberInt":"1"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000010" "right": {"$numberInt":"1"}
}, },
{ {
"predicates": [ "predicates": [
@ -134,8 +134,8 @@ output: {
"right": {"$numberInt":"3"} "right": {"$numberInt":"3"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000010", "left": {"$numberInt":"1"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
}, },
{ {
"predicates": [ "predicates": [
@ -145,8 +145,8 @@ output: {
"right": {"$numberInt":"5"} "right": {"$numberInt":"5"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000100", "left": {"$numberInt":"2"},
"right": "0000000000000000000000000000000000000000000000000000000000001000" "right": {"$numberInt":"3"}
}, },
{ {
"predicates": [ "predicates": [
@ -156,8 +156,8 @@ output: {
"right": {"$numberInt":"7"} "right": {"$numberInt":"7"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000001000", "left": {"$numberInt":"3"},
"right": "0000000000000000000000000000000000000000000000000000000000010000" "right": {"$numberInt":"4"}
}, },
{ {
"predicates": [ "predicates": [
@ -167,8 +167,8 @@ output: {
"right": {"$numberInt":"9"} "right": {"$numberInt":"9"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000010000", "left": {"$numberInt":"4"},
"right": "0000000000000000000000000000000000000000000000000000000000100000" "right": {"$numberInt":"5"}
} }
] ]
}, },

View File

@ -63,8 +63,8 @@ output: {
"right": {"$numberInt":"1"} "right": {"$numberInt":"1"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000010" "right": {"$numberInt":"1"}
}, },
{ {
"predicates": [ "predicates": [
@ -74,8 +74,8 @@ output: {
"right": {"$numberInt":"2"} "right": {"$numberInt":"2"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
}, },
{ {
"predicates": [ "predicates": [
@ -85,8 +85,8 @@ output: {
"right": {"$numberInt":"2"} "right": {"$numberInt":"2"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000010", "left": {"$numberInt":"1"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
} }
] ]
}, },

View File

@ -123,8 +123,8 @@ output: {
"right": {"$numberInt":"1"} "right": {"$numberInt":"1"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000010" "right": {"$numberInt":"1"}
}, },
{ {
"predicates": [ "predicates": [
@ -134,8 +134,8 @@ output: {
"right": {"$numberInt":"2"} "right": {"$numberInt":"2"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000010", "left": {"$numberInt":"1"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
}, },
{ {
"predicates": [ "predicates": [
@ -145,8 +145,8 @@ output: {
"right": {"$numberInt":"3"} "right": {"$numberInt":"3"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000100", "left": {"$numberInt":"2"},
"right": "0000000000000000000000000000000000000000000000000000000000001000" "right": {"$numberInt":"3"}
}, },
{ {
"predicates": [ "predicates": [
@ -156,8 +156,8 @@ output: {
"right": {"$numberInt":"5"} "right": {"$numberInt":"5"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000001000", "left": {"$numberInt":"3"},
"right": "0000000000000000000000000000000000000000000000000000000000010000" "right": {"$numberInt":"4"}
}, },
{ {
"predicates": [ "predicates": [
@ -167,8 +167,8 @@ output: {
"right": {"$numberInt":"6"} "right": {"$numberInt":"6"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000010000", "left": {"$numberInt":"4"},
"right": "0000000000000000000000000000000000000000000000000000000000100000" "right": {"$numberInt":"5"}
}, },
{ {
"predicates": [ "predicates": [
@ -178,8 +178,8 @@ output: {
"right": {"$numberInt":"2"} "right": {"$numberInt":"2"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
}, },
{ {
"predicates": [ "predicates": [
@ -189,8 +189,8 @@ output: {
"right": {"$numberInt":"3"} "right": {"$numberInt":"3"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000001000" "right": {"$numberInt":"3"}
}, },
{ {
"predicates": [ "predicates": [
@ -200,8 +200,8 @@ output: {
"right": {"$numberInt":"3"} "right": {"$numberInt":"3"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000010", "left": {"$numberInt":"1"},
"right": "0000000000000000000000000000000000000000000000000000000000001000" "right": {"$numberInt":"3"}
}, },
{ {
"predicates": [ "predicates": [
@ -211,8 +211,8 @@ output: {
"right": {"$numberInt":"6"} "right": {"$numberInt":"6"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000001000", "left": {"$numberInt":"3"},
"right": "0000000000000000000000000000000000000000000000000000000000100000" "right": {"$numberInt":"5"}
} }
] ]
}, },

View File

@ -99,8 +99,8 @@ output: {
"right": {"$numberInt":"1"} "right": {"$numberInt":"1"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000010" "right": {"$numberInt":"1"}
}, },
{ {
"predicates": [ "predicates": [
@ -110,8 +110,8 @@ output: {
"right": {"$numberInt":"2"} "right": {"$numberInt":"2"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
}, },
{ {
"predicates": [ "predicates": [
@ -121,8 +121,8 @@ output: {
"right": {"$numberInt":"2"} "right": {"$numberInt":"2"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000010", "left": {"$numberInt":"1"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
} }
] ]
}, },

View File

@ -1335,8 +1335,8 @@ output: {
"right": {"$numberInt":"1"} "right": {"$numberInt":"1"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000010" "right": {"$numberInt":"1"}
}, },
{ {
"predicates": [ "predicates": [
@ -1346,8 +1346,8 @@ output: {
"right": {"$numberInt":"2"} "right": {"$numberInt":"2"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
}, },
{ {
"predicates": [ "predicates": [
@ -1357,8 +1357,8 @@ output: {
"right": {"$numberInt":"3"} "right": {"$numberInt":"3"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000001000" "right": {"$numberInt":"3"}
}, },
{ {
"predicates": [ "predicates": [
@ -1368,8 +1368,8 @@ output: {
"right": {"$numberInt":"4"} "right": {"$numberInt":"4"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000010000" "right": {"$numberInt":"4"}
}, },
{ {
"predicates": [ "predicates": [
@ -1379,8 +1379,8 @@ output: {
"right": {"$numberInt":"5"} "right": {"$numberInt":"5"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000100000" "right": {"$numberInt":"5"}
}, },
{ {
"predicates": [ "predicates": [
@ -1390,8 +1390,8 @@ output: {
"right": {"$numberInt":"6"} "right": {"$numberInt":"6"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000001000000" "right": {"$numberInt":"6"}
}, },
{ {
"predicates": [ "predicates": [
@ -1401,8 +1401,8 @@ output: {
"right": {"$numberInt":"7"} "right": {"$numberInt":"7"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000010000000" "right": {"$numberInt":"7"}
}, },
{ {
"predicates": [ "predicates": [
@ -1412,8 +1412,8 @@ output: {
"right": {"$numberInt":"8"} "right": {"$numberInt":"8"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000100000000" "right": {"$numberInt":"8"}
}, },
{ {
"predicates": [ "predicates": [
@ -1423,8 +1423,8 @@ output: {
"right": {"$numberInt":"9"} "right": {"$numberInt":"9"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000001000000000" "right": {"$numberInt":"9"}
}, },
{ {
"predicates": [ "predicates": [
@ -1434,8 +1434,8 @@ output: {
"right": {"$numberInt":"10"} "right": {"$numberInt":"10"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000010000000000" "right": {"$numberInt":"10"}
}, },
{ {
"predicates": [ "predicates": [
@ -1445,8 +1445,8 @@ output: {
"right": {"$numberInt":"11"} "right": {"$numberInt":"11"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000100000000000" "right": {"$numberInt":"11"}
}, },
{ {
"predicates": [ "predicates": [
@ -1456,8 +1456,8 @@ output: {
"right": {"$numberInt":"12"} "right": {"$numberInt":"12"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000001000000000000" "right": {"$numberInt":"12"}
}, },
{ {
"predicates": [ "predicates": [
@ -1467,8 +1467,8 @@ output: {
"right": {"$numberInt":"13"} "right": {"$numberInt":"13"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000010000000000000" "right": {"$numberInt":"13"}
}, },
{ {
"predicates": [ "predicates": [
@ -1478,8 +1478,8 @@ output: {
"right": {"$numberInt":"14"} "right": {"$numberInt":"14"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000100000000000000" "right": {"$numberInt":"14"}
}, },
{ {
"predicates": [ "predicates": [
@ -1489,8 +1489,8 @@ output: {
"right": {"$numberInt":"15"} "right": {"$numberInt":"15"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000001000000000000000" "right": {"$numberInt":"15"}
}, },
{ {
"predicates": [ "predicates": [
@ -1500,8 +1500,8 @@ output: {
"right": {"$numberInt":"16"} "right": {"$numberInt":"16"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000010000000000000000" "right": {"$numberInt":"16"}
}, },
{ {
"predicates": [ "predicates": [
@ -1511,8 +1511,8 @@ output: {
"right": {"$numberInt":"17"} "right": {"$numberInt":"17"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000100000000000000000" "right": {"$numberInt":"17"}
}, },
{ {
"predicates": [ "predicates": [
@ -1522,8 +1522,8 @@ output: {
"right": {"$numberInt":"18"} "right": {"$numberInt":"18"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000001000000000000000000" "right": {"$numberInt":"18"}
}, },
{ {
"predicates": [ "predicates": [
@ -1533,8 +1533,8 @@ output: {
"right": {"$numberInt":"19"} "right": {"$numberInt":"19"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000010000000000000000000" "right": {"$numberInt":"19"}
}, },
{ {
"predicates": [ "predicates": [
@ -1544,8 +1544,8 @@ output: {
"right": {"$numberInt":"20"} "right": {"$numberInt":"20"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000100000000000000000000" "right": {"$numberInt":"20"}
}, },
{ {
"predicates": [ "predicates": [
@ -1555,8 +1555,8 @@ output: {
"right": {"$numberInt":"21"} "right": {"$numberInt":"21"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000001000000000000000000000" "right": {"$numberInt":"21"}
}, },
{ {
"predicates": [ "predicates": [
@ -1566,8 +1566,8 @@ output: {
"right": {"$numberInt":"22"} "right": {"$numberInt":"22"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000010000000000000000000000" "right": {"$numberInt":"22"}
}, },
{ {
"predicates": [ "predicates": [
@ -1577,8 +1577,8 @@ output: {
"right": {"$numberInt":"23"} "right": {"$numberInt":"23"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000100000000000000000000000" "right": {"$numberInt":"23"}
}, },
{ {
"predicates": [ "predicates": [
@ -1588,8 +1588,8 @@ output: {
"right": {"$numberInt":"24"} "right": {"$numberInt":"24"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000001000000000000000000000000" "right": {"$numberInt":"24"}
}, },
{ {
"predicates": [ "predicates": [
@ -1599,8 +1599,8 @@ output: {
"right": {"$numberInt":"25"} "right": {"$numberInt":"25"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000010000000000000000000000000" "right": {"$numberInt":"25"}
}, },
{ {
"predicates": [ "predicates": [
@ -1610,8 +1610,8 @@ output: {
"right": {"$numberInt":"26"} "right": {"$numberInt":"26"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000100000000000000000000000000" "right": {"$numberInt":"26"}
}, },
{ {
"predicates": [ "predicates": [
@ -1621,8 +1621,8 @@ output: {
"right": {"$numberInt":"27"} "right": {"$numberInt":"27"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000001000000000000000000000000000" "right": {"$numberInt":"27"}
}, },
{ {
"predicates": [ "predicates": [
@ -1632,8 +1632,8 @@ output: {
"right": {"$numberInt":"28"} "right": {"$numberInt":"28"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000010000000000000000000000000000" "right": {"$numberInt":"28"}
}, },
{ {
"predicates": [ "predicates": [
@ -1643,8 +1643,8 @@ output: {
"right": {"$numberInt":"29"} "right": {"$numberInt":"29"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000100000000000000000000000000000" "right": {"$numberInt":"29"}
}, },
{ {
"predicates": [ "predicates": [
@ -1654,8 +1654,8 @@ output: {
"right": {"$numberInt":"30"} "right": {"$numberInt":"30"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000001000000000000000000000000000000" "right": {"$numberInt":"30"}
}, },
{ {
"predicates": [ "predicates": [
@ -1665,8 +1665,8 @@ output: {
"right": {"$numberInt":"31"} "right": {"$numberInt":"31"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000010000000000000000000000000000000" "right": {"$numberInt":"31"}
}, },
{ {
"predicates": [ "predicates": [
@ -1676,8 +1676,8 @@ output: {
"right": {"$numberInt":"32"} "right": {"$numberInt":"32"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000100000000000000000000000000000000" "right": {"$numberInt":"32"}
}, },
{ {
"predicates": [ "predicates": [
@ -1687,8 +1687,8 @@ output: {
"right": {"$numberInt":"33"} "right": {"$numberInt":"33"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000001000000000000000000000000000000000" "right": {"$numberInt":"33"}
}, },
{ {
"predicates": [ "predicates": [
@ -1698,8 +1698,8 @@ output: {
"right": {"$numberInt":"34"} "right": {"$numberInt":"34"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000010000000000000000000000000000000000" "right": {"$numberInt":"34"}
}, },
{ {
"predicates": [ "predicates": [
@ -1709,8 +1709,8 @@ output: {
"right": {"$numberInt":"35"} "right": {"$numberInt":"35"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000100000000000000000000000000000000000" "right": {"$numberInt":"35"}
}, },
{ {
"predicates": [ "predicates": [
@ -1720,8 +1720,8 @@ output: {
"right": {"$numberInt":"36"} "right": {"$numberInt":"36"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000001000000000000000000000000000000000000" "right": {"$numberInt":"36"}
}, },
{ {
"predicates": [ "predicates": [
@ -1731,8 +1731,8 @@ output: {
"right": {"$numberInt":"37"} "right": {"$numberInt":"37"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000010000000000000000000000000000000000000" "right": {"$numberInt":"37"}
}, },
{ {
"predicates": [ "predicates": [
@ -1742,8 +1742,8 @@ output: {
"right": {"$numberInt":"38"} "right": {"$numberInt":"38"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000100000000000000000000000000000000000000" "right": {"$numberInt":"38"}
}, },
{ {
"predicates": [ "predicates": [
@ -1753,8 +1753,8 @@ output: {
"right": {"$numberInt":"39"} "right": {"$numberInt":"39"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000001000000000000000000000000000000000000000" "right": {"$numberInt":"39"}
}, },
{ {
"predicates": [ "predicates": [
@ -1764,8 +1764,8 @@ output: {
"right": {"$numberInt":"40"} "right": {"$numberInt":"40"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000010000000000000000000000000000000000000000" "right": {"$numberInt":"40"}
}, },
{ {
"predicates": [ "predicates": [
@ -1775,8 +1775,8 @@ output: {
"right": {"$numberInt":"41"} "right": {"$numberInt":"41"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000100000000000000000000000000000000000000000" "right": {"$numberInt":"41"}
}, },
{ {
"predicates": [ "predicates": [
@ -1786,8 +1786,8 @@ output: {
"right": {"$numberInt":"42"} "right": {"$numberInt":"42"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000001000000000000000000000000000000000000000000" "right": {"$numberInt":"42"}
}, },
{ {
"predicates": [ "predicates": [
@ -1797,8 +1797,8 @@ output: {
"right": {"$numberInt":"43"} "right": {"$numberInt":"43"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000010000000000000000000000000000000000000000000" "right": {"$numberInt":"43"}
}, },
{ {
"predicates": [ "predicates": [
@ -1808,8 +1808,8 @@ output: {
"right": {"$numberInt":"44"} "right": {"$numberInt":"44"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000100000000000000000000000000000000000000000000" "right": {"$numberInt":"44"}
}, },
{ {
"predicates": [ "predicates": [
@ -1819,8 +1819,8 @@ output: {
"right": {"$numberInt":"45"} "right": {"$numberInt":"45"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000001000000000000000000000000000000000000000000000" "right": {"$numberInt":"45"}
}, },
{ {
"predicates": [ "predicates": [
@ -1830,8 +1830,8 @@ output: {
"right": {"$numberInt":"46"} "right": {"$numberInt":"46"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000010000000000000000000000000000000000000000000000" "right": {"$numberInt":"46"}
}, },
{ {
"predicates": [ "predicates": [
@ -1841,8 +1841,8 @@ output: {
"right": {"$numberInt":"47"} "right": {"$numberInt":"47"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000100000000000000000000000000000000000000000000000" "right": {"$numberInt":"47"}
}, },
{ {
"predicates": [ "predicates": [
@ -1852,8 +1852,8 @@ output: {
"right": {"$numberInt":"48"} "right": {"$numberInt":"48"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000001000000000000000000000000000000000000000000000000" "right": {"$numberInt":"48"}
}, },
{ {
"predicates": [ "predicates": [
@ -1863,8 +1863,8 @@ output: {
"right": {"$numberInt":"49"} "right": {"$numberInt":"49"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000010000000000000000000000000000000000000000000000000" "right": {"$numberInt":"49"}
}, },
{ {
"predicates": [ "predicates": [
@ -1874,8 +1874,8 @@ output: {
"right": {"$numberInt":"50"} "right": {"$numberInt":"50"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000100000000000000000000000000000000000000000000000000" "right": {"$numberInt":"50"}
}, },
{ {
"predicates": [ "predicates": [
@ -1885,8 +1885,8 @@ output: {
"right": {"$numberInt":"51"} "right": {"$numberInt":"51"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000001000000000000000000000000000000000000000000000000000" "right": {"$numberInt":"51"}
}, },
{ {
"predicates": [ "predicates": [
@ -1896,8 +1896,8 @@ output: {
"right": {"$numberInt":"52"} "right": {"$numberInt":"52"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000010000000000000000000000000000000000000000000000000000" "right": {"$numberInt":"52"}
}, },
{ {
"predicates": [ "predicates": [
@ -1907,8 +1907,8 @@ output: {
"right": {"$numberInt":"53"} "right": {"$numberInt":"53"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000100000000000000000000000000000000000000000000000000000" "right": {"$numberInt":"53"}
}, },
{ {
"predicates": [ "predicates": [
@ -1918,8 +1918,8 @@ output: {
"right": {"$numberInt":"54"} "right": {"$numberInt":"54"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000001000000000000000000000000000000000000000000000000000000" "right": {"$numberInt":"54"}
}, },
{ {
"predicates": [ "predicates": [
@ -1929,8 +1929,8 @@ output: {
"right": {"$numberInt":"55"} "right": {"$numberInt":"55"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000010000000000000000000000000000000000000000000000000000000" "right": {"$numberInt":"55"}
}, },
{ {
"predicates": [ "predicates": [
@ -1940,8 +1940,8 @@ output: {
"right": {"$numberInt":"56"} "right": {"$numberInt":"56"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000100000000000000000000000000000000000000000000000000000000" "right": {"$numberInt":"56"}
}, },
{ {
"predicates": [ "predicates": [
@ -1951,8 +1951,8 @@ output: {
"right": {"$numberInt":"57"} "right": {"$numberInt":"57"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000001000000000000000000000000000000000000000000000000000000000" "right": {"$numberInt":"57"}
}, },
{ {
"predicates": [ "predicates": [
@ -1962,8 +1962,8 @@ output: {
"right": {"$numberInt":"58"} "right": {"$numberInt":"58"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000010000000000000000000000000000000000000000000000000000000000" "right": {"$numberInt":"58"}
}, },
{ {
"predicates": [ "predicates": [
@ -1973,8 +1973,8 @@ output: {
"right": {"$numberInt":"59"} "right": {"$numberInt":"59"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000100000000000000000000000000000000000000000000000000000000000" "right": {"$numberInt":"59"}
}, },
{ {
"predicates": [ "predicates": [
@ -1984,8 +1984,8 @@ output: {
"right": {"$numberInt":"60"} "right": {"$numberInt":"60"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0001000000000000000000000000000000000000000000000000000000000000" "right": {"$numberInt":"60"}
}, },
{ {
"predicates": [ "predicates": [
@ -1995,8 +1995,8 @@ output: {
"right": {"$numberInt":"61"} "right": {"$numberInt":"61"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0010000000000000000000000000000000000000000000000000000000000000" "right": {"$numberInt":"61"}
}, },
{ {
"predicates": [ "predicates": [
@ -2006,8 +2006,8 @@ output: {
"right": {"$numberInt":"62"} "right": {"$numberInt":"62"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0100000000000000000000000000000000000000000000000000000000000000" "right": {"$numberInt":"62"}
}, },
{ {
"predicates": [ "predicates": [
@ -2017,8 +2017,8 @@ output: {
"right": {"$numberInt":"63"} "right": {"$numberInt":"63"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "1000000000000000000000000000000000000000000000000000000000000000" "right": {"$numberInt":"63"}
}, },
{ {
"predicates": [ "predicates": [
@ -2028,8 +2028,8 @@ output: {
"right": {"$numberInt":"2"} "right": {"$numberInt":"2"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000010", "left": {"$numberInt":"1"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
}, },
{ {
"predicates": [ "predicates": [
@ -2039,8 +2039,8 @@ output: {
"right": {"$numberInt":"3"} "right": {"$numberInt":"3"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000010", "left": {"$numberInt":"1"},
"right": "0000000000000000000000000000000000000000000000000000000000001000" "right": {"$numberInt":"3"}
}, },
{ {
"predicates": [ "predicates": [
@ -2050,8 +2050,8 @@ output: {
"right": {"$numberInt":"3"} "right": {"$numberInt":"3"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000100", "left": {"$numberInt":"2"},
"right": "0000000000000000000000000000000000000000000000000000000000001000" "right": {"$numberInt":"3"}
} }
] ]
}, },

View File

@ -49,8 +49,8 @@ output: {
"right": {"$numberInt":"1"} "right": {"$numberInt":"1"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000010" "right": {"$numberInt":"1"}
}, },
{ {
"predicates": [ "predicates": [
@ -60,8 +60,8 @@ output: {
"right": {"$numberInt":"3"} "right": {"$numberInt":"3"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
}, },
{ {
"predicates": [ "predicates": [
@ -71,8 +71,8 @@ output: {
"right": {"$numberInt":"5"} "right": {"$numberInt":"5"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000100", "left": {"$numberInt":"2"},
"right": "0000000000000000000000000000000000000000000000000000000000001000" "right": {"$numberInt":"3"}
} }
] ]
} }

View File

@ -31,8 +31,8 @@
"right": {"$numberInt":"1"} "right": {"$numberInt":"1"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000010" "right": {"$numberInt":"1"}
} }
] ]
}, },

View File

@ -32,8 +32,8 @@
"right": {"$numberInt":"1"} "right": {"$numberInt":"1"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000010" "right": {"$numberInt":"1"}
}, },
{ {
"predicates": [ "predicates": [
@ -43,8 +43,8 @@
"right": {"$numberInt":"3"} "right": {"$numberInt":"3"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
} }
] ]
}, },

View File

@ -42,8 +42,8 @@
"right": {"$numberInt":"1"} "right": {"$numberInt":"1"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000010" "right": {"$numberInt":"1"}
}, },
{ {
"predicates": [ "predicates": [
@ -53,8 +53,8 @@
"right": {"$numberInt":"2"} "right": {"$numberInt":"2"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
} }
] ]
}, },

View File

@ -36,8 +36,8 @@
"right": {"$numberInt":"1"} "right": {"$numberInt":"1"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000010" "right": {"$numberInt":"1"}
}, },
{ {
"predicates": [ "predicates": [
@ -47,8 +47,8 @@
"right": {"$numberInt":"2"} "right": {"$numberInt":"2"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
} }
] ]
}, },

View File

@ -36,8 +36,8 @@
"right": {"$numberInt":"1"} "right": {"$numberInt":"1"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000010" "right": {"$numberInt":"1"}
}, },
{ {
"predicates": [ "predicates": [
@ -47,8 +47,8 @@
"right": {"$numberInt":"2"} "right": {"$numberInt":"2"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
} }
] ]
}, },

View File

@ -25,8 +25,8 @@
"right": {"$numberInt":"1"} "right": {"$numberInt":"1"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000010" "right": {"$numberInt":"1"}
} }
] ]
}, },

View File

@ -25,8 +25,8 @@
"right": {"$numberInt":"1"} "right": {"$numberInt":"1"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000010" "right": {"$numberInt":"1"}
} }
] ]
}, },

View File

@ -32,8 +32,8 @@
"right": {"$numberInt":"1"} "right": {"$numberInt":"1"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000010" "right": {"$numberInt":"1"}
}, },
{ {
"predicates": [ "predicates": [
@ -43,8 +43,8 @@
"right": {"$numberInt":"2"} "right": {"$numberInt":"2"}
} }
], ],
"left": "0000000000000000000000000000000000000000000000000000000000000001", "left": {"$numberInt":"0"},
"right": "0000000000000000000000000000000000000000000000000000000000000100" "right": {"$numberInt":"2"}
} }
] ]
}, },