1
0
Fork 0
arangodb/tests/js/server/aql/aql-optimizer-rule-views-so...

528 lines
19 KiB
JavaScript

/*jshint globalstrict:false, strict:false, maxlen: 500 */
/*global assertEqual, assertNotEqual, assertTrue, AQL_EXPLAIN, AQL_EXECUTE */
////////////////////////////////////////////////////////////////////////////////
/// @brief tests for optimizer rules
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
let jsunity = require("jsunity");
let db = require("@arangodb").db;
/// @brief test suite
function optimizerRuleTestSuite () {
const ruleName = "handle-arangosearch-views";
const cn = "UnitTestsCollection";
const cn1 = "UnitTestsCollection1";
const vn = "UnitTestsView";
return {
setUp : function () {
db._dropView(vn);
db._drop(cn);
db._drop(cn1);
db._create(cn, { numberOfShards: 3 });
db._create(cn1, { numberOfShards: 3 });
},
tearDown : function () {
db._dropView(vn);
db._drop(cn);
db._drop(cn1);
},
/// @brief test that rule has no effect
testNoSortedness : function () {
db._createView(vn, "arangosearch", { links: { [cn] : { includeAllFields: true } } });
let queries = [
"FOR doc IN " + vn + " SORT doc.value RETURN doc",
"FOR doc IN " + vn + " SORT doc.value ASC RETURN doc",
"FOR doc IN " + vn + " SORT doc.value DESC RETURN doc",
"FOR doc IN " + vn + " SORT doc RETURN doc",
"FOR doc IN " + vn + " SORT doc._key RETURN doc",
"FOR doc IN " + vn + " SORT doc._key ASC RETURN doc",
"FOR doc IN " + vn + " SORT doc._key DESC RETURN doc",
"FOR doc IN " + vn + " SORT doc.value1, doc.value2 RETURN doc",
];
queries.forEach(function(query) {
let result = AQL_EXPLAIN(query);
assertNotEqual(-1, result.plan.nodes.map(function(node) { return node.type; }).indexOf("SortNode"));
assertNotEqual(-1, result.plan.nodes.filter(node => node.type === "SortNode").map(function(node) { return node.strategy; }).indexOf("standard"));
});
},
/// @brief test that rule has no effect
testRuleSingleAttributeNoEffect : function () {
db._createView(vn, "arangosearch", { links: { [cn] : { includeAllFields: true } }, primarySort : [ { field : "value", direction: "asc" } ] });
let queries = [
"FOR doc IN " + vn + " SORT doc.value1 RETURN doc",
"FOR doc IN " + vn + " SORT doc.value1 ASC RETURN doc",
"FOR doc IN " + vn + " SORT doc.value1 DESC RETURN doc",
"FOR doc IN " + vn + " SORT doc.value1, doc.value2 RETURN doc",
"FOR doc IN " + vn + " SORT doc.value2, doc.value1 RETURN doc",
"FOR doc IN " + vn + " SORT doc.value2, doc.value1 RETURN doc",
"FOR doc IN " + vn + " SORT doc.value, doc.value1 RETURN doc",
"FOR doc IN " + vn + " SORT doc.value1, doc.value RETURN doc",
];
queries.forEach(function(query) {
let result = AQL_EXPLAIN(query);
assertNotEqual(-1, result.plan.nodes.map(function(node) { return node.type; }).indexOf("SortNode"));
assertNotEqual(-1, result.plan.nodes.filter(node => node.type === "SortNode").map(function(node) { return node.strategy; }).indexOf("standard"));
});
},
/// @brief test that rule has no effect
testRuleMultipleAttributesNoEffect : function () {
db._createView(vn, "arangosearch", { links: { [cn] : { includeAllFields: true } }, primarySort : [ { field : "value1", direction: "asc" }, { field: "value2", direction: "asc" } ] });
let queries = [
"FOR doc IN " + vn + " SORT doc.value1, doc.value2 DESC RETURN doc",
"FOR doc IN " + vn + " SORT doc.value1 ASC, doc.value2 DESC RETURN doc",
"FOR doc IN " + vn + " SORT doc.value1 DESC, doc.value2 RETURN doc",
"FOR doc IN " + vn + " SORT doc.value1 DESC, doc.value2 ASC RETURN doc",
"FOR doc IN " + vn + " SORT doc.value2, doc.value1 RETURN doc",
"FOR doc IN " + vn + " SORT doc.value1, doc.value3 RETURN doc",
"FOR doc IN " + vn + " SORT doc.value1, doc.value1 RETURN doc",
"FOR doc IN " + vn + " SORT doc.value2, doc.value2 RETURN doc",
"FOR doc IN " + vn + " SORT doc.value3, doc.value4 RETURN doc",
"FOR doc IN " + vn + " SORT doc.value1, doc.value2, doc.value3 RETURN doc",
];
queries.forEach(function(query) {
let result = AQL_EXPLAIN(query);
assertNotEqual(-1, result.plan.nodes.map(function(node) { return node.type; }).indexOf("SortNode"), query);
assertNotEqual(-1, result.plan.nodes.filter(node => node.type === "SortNode").map(function(node) { return node.strategy; }).indexOf("standard"));
});
},
/// @brief test that rule has no effect
testRuleSingleAttributeDifferentOrderNoEffect : function () {
db._createView(vn, "arangosearch", { links: { [cn] : { includeAllFields: true } }, primarySort : [ { field : "value", direction: "asc" } ] });
let queries = [
"FOR doc IN " + vn + " SORT doc.value DESC RETURN doc",
"FOR doc IN " + vn + " SORT doc.value DESC, doc.value DESC RETURN doc",
];
queries.forEach(function(query) {
let result = AQL_EXPLAIN(query);
assertNotEqual(-1, result.plan.nodes.map(function(node) { return node.type; }).indexOf("SortNode"));
assertNotEqual(-1, result.plan.nodes.filter(node => node.type === "SortNode").map(function(node) { return node.strategy; }).indexOf("standard"));
});
},
/// @brief test that rule has no effect
testRuleMultipleAttributesDifferentOrderNoEffect : function () {
db._createView(vn, "arangosearch", { links: { [cn] : { includeAllFields: true } }, primarySort : [ { field : "value1", direction: "asc" }, { field: "value2", direction: "asc" } ] });
let queries = [
"FOR doc IN " + vn + " SORT doc.value1 DESC RETURN doc",
"FOR doc IN " + vn + " SORT doc.value2 ASC RETURN doc",
"FOR doc IN " + vn + " SORT doc.value2 DESC RETURN doc",
"FOR doc IN " + vn + " SORT doc.value1 ASC, doc.value2 DESC RETURN doc",
"FOR doc IN " + vn + " SORT doc.value1 DESC, doc.value2 ASC RETURN doc",
];
queries.forEach(function(query) {
let result = AQL_EXPLAIN(query);
assertNotEqual(-1, result.plan.nodes.map(function(node) { return node.type; }).indexOf("SortNode"));
assertNotEqual(-1, result.plan.nodes.filter(node => node.type === "SortNode").map(function(node) { return node.strategy; }).indexOf("standard"));
});
},
/// @brief test that rule has an effect
testRuleSingleAttributeHasEffect : function () {
db._createView(vn, "arangosearch", {
links: { [cn] : { includeAllFields: true }, [cn1] : { includeAllFields: true } },
primarySort : [ { field : "value", direction: "asc" } ]
});
let queries = [
"FOR doc IN " + vn + " SORT doc.value RETURN doc",
"FOR doc IN " + vn + " SORT doc.value ASC RETURN doc",
];
queries.forEach(function(query) {
let result = AQL_EXPLAIN(query);
assertEqual(-1, result.plan.nodes.map(function(node) { return node.type; }).indexOf("SortNode"));
});
},
/// @brief test that rule has an effect
testRuleMultipleAttributesHasEffect : function () {
db._createView(vn, "arangosearch", {
links: { [cn] : { includeAllFields: true }, [cn1] : { includeAllFields: true } },
primarySort : [ { field : "value1", direction: "asc" }, { field: "value2", direction: "asc" } ]
});
let queries = [
"FOR doc IN " + vn + " SORT doc.value1 RETURN doc",
"FOR doc IN " + vn + " SORT doc.value1 ASC RETURN doc",
"FOR doc IN " + vn + " SORT doc.value1, doc.value2 RETURN doc",
"FOR doc IN " + vn + " SORT doc.value1, doc.value2 ASC RETURN doc",
];
queries.forEach(function(query) {
let result = AQL_EXPLAIN(query);
assertEqual(-1, result.plan.nodes.map(function(node) { return node.type; }).indexOf("SortNode"));
});
},
/// @brief test that rule has an effect
testRuleSingleAttributeResults : function () {
db._createView(vn, "arangosearch", {
links: { [cn] : { includeAllFields: true }, [cn1] : { includeAllFields: true } },
primarySort : [ { field : "value", direction: "asc" } ]
});
// insert in reverse order
let values = [];
for (let i = 0; i < 2000; ++i) {
values.push({ value: "test" + (4000 - i) });
}
db[cn].insert(values);
values = [];
for (let i = 2000; i < 4000; ++i) {
values.push({ value: "test" + (4000 - i) });
}
db[cn1].insert(values);
let query = "FOR doc IN " + vn + " OPTIONS { waitForSync: true } SORT doc.value RETURN doc";
let result = AQL_EXPLAIN(query);
assertEqual(-1, result.plan.nodes.map(function(node) { return node.type; }).indexOf("SortNode"));
result = AQL_EXECUTE(query).json;
assertEqual(4000, result.length);
let last = "";
result.forEach(function(doc) {
assertTrue(doc.value > last);
last = doc.value;
});
},
/// @brief test that rule has an effect
testRuleSingleAttributeResultsDesc : function () {
db._createView(vn, "arangosearch", {
links: { [cn] : { includeAllFields: true }, [cn1] : { includeAllFields: true } },
primarySort : [ { field : "value", direction: "desc" } ]
});
// insert in forward order
let values = [];
for (let i = 0; i < 2000; ++i) {
values.push({ value: "test" + i });
}
db[cn].insert(values);
values = [];
for (let i = 2000; i < 4000; ++i) {
values.push({ value: "test" + i });
}
db[cn1].insert(values);
let query = "FOR doc IN " + vn + " OPTIONS { waitForSync: true } SORT doc.value DESC RETURN doc";
let result = AQL_EXPLAIN(query);
assertEqual(-1, result.plan.nodes.map(function(node) { return node.type; }).indexOf("SortNode"));
result = AQL_EXECUTE(query).json;
assertEqual(4000, result.length);
let last = "test999999999";
result.forEach(function(doc) {
assertTrue(doc.value < last);
last = doc.value;
});
},
/// @brief test that rule has an effect
testRuleMultipleAttributesResults : function () {
db._createView(vn, "arangosearch", {
links: { [cn] : { includeAllFields: true }, [cn1] : { includeAllFields: true } },
primarySort : [ { field : "value1", direction: "asc" }, { field: "value2", direction: "asc" } ]
});
// insert in reverse order
let values = [];
for (let i = 0; i < 2000; ++i) {
values.push({ value1: (4000 - i), value2: i });
}
db[cn].insert(values);
values = [];
for (let i = 2000; i < 4000; ++i) {
values.push({ value1: (4000 - i), value2: i });
}
db[cn1].insert(values);
let query = "FOR doc IN " + vn + " OPTIONS { waitForSync: true } SORT doc.value1, doc.value2 RETURN doc";
let result = AQL_EXPLAIN(query);
assertEqual(-1, result.plan.nodes.map(function(node) { return node.type; }).indexOf("SortNode"));
result = AQL_EXECUTE(query).json;
assertEqual(4000, result.length);
let last1 = -1;
let last2 = 99999;
result.forEach(function(doc) {
assertTrue(doc.value1 > last1);
assertTrue(doc.value2 < last2);
last1 = doc.value1;
last2 = doc.value2;
});
},
/// @brief test that rule has an effect
testRuleMultipleAttributesResultsDesc : function () {
db._createView(vn, "arangosearch", {
links: { [cn] : { includeAllFields: true }, [cn1] : { includeAllFields: true } },
primarySort : [ { field : "value1", direction: "desc" }, { field: "value2", direction: "asc" } ]
});
// insert in forward order
let values = [];
for (let i = 0; i < 2000; ++i) {
values.push({ value1: i, value2: i });
}
db[cn].insert(values);
values = [];
for (let i = 2000; i < 4000; ++i) {
values.push({ value1: i, value2: i });
}
db[cn1].insert(values);
let query = "FOR doc IN " + vn + " OPTIONS { waitForSync: true } SORT doc.value1 DESC, doc.value2 RETURN doc";
let result = AQL_EXPLAIN(query);
assertEqual(-1, result.plan.nodes.map(function(node) { return node.type; }).indexOf("SortNode"));
result = AQL_EXECUTE(query).json;
assertEqual(4000, result.length);
let last1 = 99999;
let last2 = 99999;
result.forEach(function(doc) {
assertTrue(doc.value1 < last1);
assertTrue(doc.value2 < last2);
last1 = doc.value1;
last2 = doc.value2;
});
},
/// @brief test that rule has an effect
testRuleSameAttributeValuesDesc : function () {
db._createView(vn, "arangosearch", {
links: { [cn] : { includeAllFields: true }, [cn1] : { includeAllFields: true } },
primarySort : [ { field : "value1", direction: "desc" }, { field: "value2", direction: "asc" } ]
});
// insert in forward order
let values = [];
for (let i = 0; i < 2000; ++i) {
values.push({ value1: "same", value2: (4000 - i) });
}
db[cn].insert(values);
values = [];
for (let i = 2000; i < 4000; ++i) {
values.push({ value1: "same", value2: (4000 - i) });
}
db[cn1].insert(values);
let query = "FOR doc IN " + vn + " OPTIONS { waitForSync: true } SORT doc.value1 DESC, doc.value2 RETURN doc";
let result = AQL_EXPLAIN(query);
assertEqual(-1, result.plan.nodes.map(function(node) { return node.type; }).indexOf("SortNode"));
result = AQL_EXECUTE(query).json;
assertEqual(4000, result.length);
let last2 = -1;
result.forEach(function(doc) {
assertEqual("same", doc.value1);
assertTrue(doc.value2 > last2);
last2 = doc.value2;
});
},
/// @brief test that rule has an effect
testRuleSameAttributeValuesDescFullCount : function () {
db._createView(vn, "arangosearch", {
links: { [cn] : { includeAllFields: true }, [cn1] : { includeAllFields: true } },
primarySort : [ { field : "value1", direction: "desc" }, { field: "value2", direction: "asc" } ]
});
// insert in forward order
let values = [];
for (let i = 0; i < 2000; ++i) {
values.push({ value1: "same", value2: (4000 - i) });
}
db[cn].insert(values);
values = [];
for (let i = 2000; i < 4000; ++i) {
values.push({ value1: "same", value2: (4000 - i) });
}
db[cn1].insert(values);
let query = "FOR doc IN " + vn + " OPTIONS { waitForSync: true } SORT doc.value1 DESC, doc.value2 RETURN doc";
let result = AQL_EXPLAIN(query);
assertEqual(-1, result.plan.nodes.map(function(node) { return node.type; }).indexOf("SortNode"));
result = AQL_EXECUTE(query, {}, { fullCount: true });
assertEqual(4000, result.json.length);
assertEqual(4000, result.stats.fullCount);
let last2 = -1;
result.json.forEach(function(doc) {
assertEqual("same", doc.value1);
assertTrue(doc.value2 > last2);
last2 = doc.value2;
});
},
/// @brief test that rule has an effect
testRuleMultipleAttributesResultsDescWithOffset : function () {
db._createView(vn, "arangosearch", {
links: { [cn] : { includeAllFields: true }, [cn1] : { includeAllFields: true } },
primarySort : [ { field : "value1", direction: "desc" }, { field: "value2", direction: "asc" } ]
});
// insert in forward order
let firstHalf = [];
for (let i = 0; i < 2000; ++i) {
firstHalf.push({ value1: i, value2: i });
}
db[cn].insert(firstHalf);
let secondHalf = [];
for (let i = 2000; i < 4000; ++i) {
secondHalf.push({ value1: i, value2: i });
}
db[cn1].insert(secondHalf);
let query = "FOR doc IN " + vn + " OPTIONS { waitForSync: true } SORT doc.value1 DESC, doc.value2 LIMIT 2000, 100000 RETURN doc";
let result = AQL_EXPLAIN(query);
assertEqual(-1, result.plan.nodes.map(function(node) { return node.type; }).indexOf("SortNode"));
firstHalf.sort(function(lhs, rhs) {
if (lhs.value1 === rhs.value1) {
if (lhs.value2 === rhs.value2) {
return 0;
}
if (lhs.value2 < rhs.value2) {
return -1;
}
return 1;
}
if (lhs.value1 < rhs.value1) {
return 1;
}
return -1;
});
result = AQL_EXECUTE(query).json;
assertEqual(firstHalf.length, result.length);
let last1 = 99999;
let last2 = 99999;
let i = 0;
result.forEach(function(doc) {
assertEqual(doc.value1, firstHalf[i].value1);
assertEqual(doc.value2, firstHalf[i].value2);
assertTrue(doc.value1 < last1);
assertTrue(doc.value2 < last2);
last1 = doc.value1;
last2 = doc.value2;
++i;
});
},
testRuleMultipleAttributesResultsDescWithOffsetFullCount : function () {
db._createView(vn, "arangosearch", {
links: { [cn] : { includeAllFields: true }, [cn1] : { includeAllFields: true } },
primarySort : [ { field : "value1", direction: "desc" }, { field: "value2", direction: "asc" } ]
});
// insert in forward order
let firstHalf = [];
for (let i = 0; i < 2000; ++i) {
firstHalf.push({ value1: i, value2: i });
}
db[cn].insert(firstHalf);
let secondHalf = [];
for (let i = 2000; i < 4000; ++i) {
secondHalf.push({ value1: i, value2: i });
}
db[cn1].insert(secondHalf);
let query = "FOR doc IN " + vn + " OPTIONS { waitForSync: true } SORT doc.value1 DESC, doc.value2 LIMIT 2000, 100 RETURN doc";
let result = AQL_EXPLAIN(query);
assertEqual(-1, result.plan.nodes.map(function(node) { return node.type; }).indexOf("SortNode"));
firstHalf.sort(function(lhs, rhs) {
if (lhs.value1 === rhs.value1) {
if (lhs.value2 === rhs.value2) {
return 0;
}
if (lhs.value2 < rhs.value2) {
return -1;
}
return 1;
}
if (lhs.value1 < rhs.value1) {
return 1;
}
return -1;
});
result = AQL_EXECUTE(query, {}, { fullCount: true});
assertEqual(100, result.json.length);
assertEqual(4000, result.stats.fullCount);
let last1 = 99999;
let last2 = 99999;
let i = 0;
result.json.forEach(function(doc) {
assertEqual(doc.value1, firstHalf[i].value1);
assertEqual(doc.value2, firstHalf[i].value2);
assertTrue(doc.value1 < last1);
assertTrue(doc.value2 < last2);
last1 = doc.value1;
last2 = doc.value2;
++i;
});
},
};
}
jsunity.run(optimizerRuleTestSuite);
return jsunity.done();