mirror of https://gitee.com/bigwinds/arangodb
added SKIPLIST AQL function
This commit is contained in:
parent
dc1d28fe5d
commit
fe9464afec
29
CHANGELOG
29
CHANGELOG
|
@ -146,6 +146,35 @@ v1.5.0 (XXXX-XX-XX)
|
|||
v1.4.9 (XXXX-XX-XX)
|
||||
-------------------
|
||||
|
||||
* added AQL function `SKIPLIST` to directly access skiplist indexes from AQL
|
||||
|
||||
This is a shortcut method to use a skiplist index for retrieving specific documents in
|
||||
indexed order. The function capability is rather limited, but it may be used
|
||||
for several cases to speed up queries. The documents are returned in index order if
|
||||
only one condition is used.
|
||||
|
||||
/* return all documents with mycollection.created > 12345678 */
|
||||
FOR doc IN SKIPLIST(mycollection, { created: [[ '>', 12345678 ]] })
|
||||
RETURN doc
|
||||
|
||||
/* return first document with mycollection.created > 12345678 */
|
||||
FOR doc IN SKIPLIST(mycollection, { created: [[ '>', 12345678 ]] }, 0, 1)
|
||||
RETURN doc
|
||||
|
||||
/* return all documents with mycollection.created between 12345678 and 123456790 */
|
||||
FOR doc IN SKIPLIST(mycollection, { created: [[ '>', 12345678 ], [ '<=', 123456790 ]] })
|
||||
RETURN doc
|
||||
|
||||
/* return all documents with mycollection.a equal 1 and .b equal 2 */
|
||||
FOR doc IN SKIPLIST(mycollection, { a: [[ '==', 1 ]], b: [[ '==', 2 ]] })
|
||||
RETURN doc
|
||||
|
||||
The function requires a skiplist index with the exact same attributes to
|
||||
be present on the specified colelction. All attributes present in the skiplist
|
||||
index must be specified in the conditions specified for the `SKIPLIST` function.
|
||||
Attribute declaration order is important, too: attributes must be specified in the
|
||||
same order in the condition as they have been declared in the skiplist index.
|
||||
|
||||
* added command-line option `--server.disable-authentication-unix-sockets`
|
||||
|
||||
with this option, authentication can be disabled for all requests coming
|
||||
|
|
|
@ -1617,6 +1617,23 @@ function categories:
|
|||
DOCUMENT("users/john")
|
||||
DOCUMENT([ "users/john", "users/amy" ])
|
||||
|
||||
- @FN{SKIPLIST(@FA{collection}, @FA{condition}, @FA{skip}, @FA{limit})}: return all documents
|
||||
from a skiplist index on collection @FA{collection} that match the specified @FA{condition}.
|
||||
This is a shortcut method to use a skiplist index for retrieving specific documents in
|
||||
indexed order. The skiplist index supports equality and less than/greater than queries. The
|
||||
@FA{skip} and @FA{limit} parameters are optional but can be specified to further limit the
|
||||
results:
|
||||
|
||||
SKIPLIST(test, { created: [[ '>', 0 ]] }, 0, 100)
|
||||
SKIPLIST(test, { age: [[ '>', 25 ], [ '<=', 65 ]] })
|
||||
SKIPLIST(test, { a: [[ '==', 10 ]], b: [[ '==', 25 ]] }
|
||||
|
||||
The @FA{condition} document must contain an entry for each attribute that is contained in the
|
||||
index. It is not allowed to specify just a subset of attributes that are present in an index.
|
||||
Additionally the attributes in the @FA{condition} document must be specified in the same order
|
||||
as in the index.
|
||||
If no suitable skiplist index is found, an error will be raised and the query will be aborted.
|
||||
|
||||
High-level operations {#AqlOperations}
|
||||
======================================
|
||||
|
||||
|
|
|
@ -713,6 +713,7 @@ TRI_associative_pointer_t* TRI_CreateFunctionsAql (void) {
|
|||
REGISTER_FUNCTION("FIRST_LIST", "FIRST_LIST", true, false, ".|+", NULL);
|
||||
REGISTER_FUNCTION("FIRST_DOCUMENT", "FIRST_DOCUMENT", true, false, ".|+", NULL);
|
||||
REGISTER_FUNCTION("PARSE_IDENTIFIER", "PARSE_IDENTIFIER", true, false, ".", NULL);
|
||||
REGISTER_FUNCTION("SKIPLIST", "SKIPLIST_QUERY", false, false, "h,a|n,n", NULL);
|
||||
|
||||
if (! result) {
|
||||
TRI_FreeFunctionsAql(functions);
|
||||
|
|
|
@ -3246,6 +3246,51 @@ function PARSE_IDENTIFIER (value) {
|
|||
THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "PARSE_IDENTIFIER");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief query a skiplist index
|
||||
///
|
||||
/// returns a documents from a skiplist index on the specified collection. Only
|
||||
/// documents that match the specified condition will be returned.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function SKIPLIST_QUERY (collection, condition, skip, limit) {
|
||||
"use strict";
|
||||
|
||||
var keys = [ ], key, idx;
|
||||
|
||||
for (key in condition) {
|
||||
if (condition.hasOwnProperty(key)) {
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
var c = COLLECTION(collection);
|
||||
if (c === null) {
|
||||
THROW(INTERNAL.errors.ERROR_ARANGO_COLLECTION_NOT_FOUND, collection);
|
||||
}
|
||||
|
||||
idx = c.lookupSkiplist.apply(c, keys);
|
||||
|
||||
if (idx === null) {
|
||||
THROW(INTERNAL.errors.ERROR_ARANGO_NO_INDEX);
|
||||
}
|
||||
|
||||
if (skip === undefined || skip === null) {
|
||||
skip = 0;
|
||||
}
|
||||
|
||||
if (limit === undefined || limit === null) {
|
||||
limit = null;
|
||||
}
|
||||
|
||||
try {
|
||||
return c.BY_CONDITION_SKIPLIST(idx.id, condition, skip, limit).documents;
|
||||
}
|
||||
catch (err) {
|
||||
THROW(INTERNAL.errors.ERROR_ARANGO_NO_INDEX);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief check whether a document has a specific attribute
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -4109,6 +4154,7 @@ exports.NOT_NULL = NOT_NULL;
|
|||
exports.FIRST_LIST = FIRST_LIST;
|
||||
exports.FIRST_DOCUMENT = FIRST_DOCUMENT;
|
||||
exports.PARSE_IDENTIFIER = PARSE_IDENTIFIER;
|
||||
exports.SKIPLIST_QUERY = SKIPLIST_QUERY;
|
||||
exports.HAS = HAS;
|
||||
exports.ATTRIBUTES = ATTRIBUTES;
|
||||
exports.UNSET = UNSET;
|
||||
|
|
|
@ -2004,6 +2004,106 @@ function ahuacatlFunctionsTestSuite () {
|
|||
internal.db._drop(cn);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test skiplist function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testSkiplist1 : function () {
|
||||
var cn = "UnitTestsAhuacatlFunctions";
|
||||
|
||||
internal.db._drop(cn);
|
||||
var cx = internal.db._create(cn);
|
||||
cx.ensureSkiplist("created");
|
||||
|
||||
var i;
|
||||
for (i = 0; i < 1000; ++i) {
|
||||
cx.save({ created: i });
|
||||
}
|
||||
|
||||
expected = [ { created: 0 } ];
|
||||
actual = getQueryResults("FOR x IN SKIPLIST(" + cn + ", { created: [[ '>=', 0 ]] }, 0, 1) RETURN x");
|
||||
assertEqual(expected, actual);
|
||||
actual = getQueryResults("FOR x IN SKIPLIST(" + cn + ", { created: [[ '>=', 0 ], [ '<', 1 ]] }) RETURN x");
|
||||
assertEqual(expected, actual);
|
||||
|
||||
expected = [ { created: 1 } ];
|
||||
actual = getQueryResults("FOR x IN SKIPLIST(" + cn + ", { created: [[ '>', 0 ]] }, 0, 1) RETURN x");
|
||||
assertEqual(expected, actual);
|
||||
actual = getQueryResults("FOR x IN SKIPLIST(" + cn + ", { created: [[ '>', 0 ], [ '<=', 1 ]] }) RETURN x");
|
||||
assertEqual(expected, actual);
|
||||
|
||||
expected = [ { created: 0 }, { created: 1 }, { created: 2 } ];
|
||||
actual = getQueryResults("FOR x IN SKIPLIST(" + cn + ", { created: [[ '>=', 0 ]] }, 0, 3) RETURN x");
|
||||
assertEqual(expected, actual);
|
||||
|
||||
expected = [ { created: 5 }, { created: 6 } ];
|
||||
actual = getQueryResults("FOR x IN SKIPLIST(" + cn + ", { created: [[ '>=', 0 ]] }, 5, 2) RETURN x");
|
||||
assertEqual(expected, actual);
|
||||
|
||||
expected = [ { created: 5 }, { created: 6 } ];
|
||||
actual = getQueryResults("FOR x IN SKIPLIST(" + cn + ", { created: [[ '>=', 5 ], [ '<=', 6 ]] }, 0, 5) RETURN x");
|
||||
assertEqual(expected, actual);
|
||||
|
||||
expected = [ { created: 5 } ];
|
||||
actual = getQueryResults("FOR x IN SKIPLIST(" + cn + ", { created: [[ '>=', 5 ], [ '<=', 6 ]] }, 0, 1) RETURN x");
|
||||
assertEqual(expected, actual);
|
||||
|
||||
expected = [ { created: 2 }, { created: 3 } ];
|
||||
actual = getQueryResults("FOR x IN SKIPLIST(" + cn + ", { created: [[ '<', 4 ]] }, 2, 10) RETURN x");
|
||||
assertEqual(expected, actual);
|
||||
|
||||
expected = [ ];
|
||||
actual = getQueryResults("FOR x IN SKIPLIST(" + cn + ", { created: [[ '>', 0 ]] }, 10000, 10) RETURN x");
|
||||
assertEqual(expected, actual);
|
||||
|
||||
assertQueryError(errors.ERROR_ARANGO_NO_INDEX.code, "RETURN SKIPLIST(" + cn + ", { a: [[ '==', 1 ]] })");
|
||||
|
||||
internal.db._drop(cn);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test skiplist function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testSkiplist2 : function () {
|
||||
var cn = "UnitTestsAhuacatlFunctions";
|
||||
|
||||
internal.db._drop(cn);
|
||||
var cx = internal.db._create(cn);
|
||||
|
||||
assertQueryError(errors.ERROR_ARANGO_NO_INDEX.code, "RETURN SKIPLIST(" + cn + ", { a: [[ '==', 1 ]], b: [[ '==', 0 ]] })");
|
||||
|
||||
cx.ensureSkiplist("a", "b");
|
||||
|
||||
var i;
|
||||
for (i = 0; i < 1000; ++i) {
|
||||
cx.save({ a: i, b: i + 1 });
|
||||
}
|
||||
|
||||
expected = [ { a: 1, b: 2 } ];
|
||||
actual = getQueryResults("FOR x IN SKIPLIST(" + cn + ", { a: [[ '==', 1 ]], b: [[ '>=', 2 ], [ '<=', 3 ]] }) RETURN x");
|
||||
assertEqual(expected, actual);
|
||||
|
||||
expected = [ { a: 1, b: 2 } ];
|
||||
actual = getQueryResults("FOR x IN SKIPLIST(" + cn + ", { a: [[ '==', 1 ]], b: [[ '==', 2 ]] }) RETURN x");
|
||||
assertEqual(expected, actual);
|
||||
|
||||
assertQueryError(errors.ERROR_ARANGO_NO_INDEX.code, "RETURN SKIPLIST(" + cn + ", { b: [[ '==', 2 ]], a: [[ '==', 1 ]] })");
|
||||
|
||||
expected = [ ];
|
||||
actual = getQueryResults("FOR x IN SKIPLIST(" + cn + ", { a: [[ '==', 2 ]], b: [[ '==', 1 ]] }, 1, 1) RETURN x");
|
||||
assertEqual(expected, actual);
|
||||
actual = getQueryResults("FOR x IN SKIPLIST(" + cn + ", { a: [[ '==', 99 ]], b: [[ '==', 17 ]] }, 1, 1) RETURN x");
|
||||
assertEqual(expected, actual);
|
||||
|
||||
assertQueryError(errors.ERROR_ARANGO_NO_INDEX.code, "RETURN SKIPLIST(" + cn + ", { a: [[ '==', 1 ]] })");
|
||||
assertQueryError(errors.ERROR_ARANGO_NO_INDEX.code, "RETURN SKIPLIST(" + cn + ", { b: [[ '==', 1 ]] })");
|
||||
assertQueryError(errors.ERROR_ARANGO_NO_INDEX.code, "RETURN SKIPLIST(" + cn + ", { c: [[ '==', 1 ]] })");
|
||||
|
||||
internal.db._drop(cn);
|
||||
},
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test min function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Loading…
Reference in New Issue