Skip to content

Commit 2e02829

Browse files
committed
add first draft vector index test
1 parent 2a6018d commit 2e02829

File tree

2 files changed

+124
-37
lines changed

2 files changed

+124
-37
lines changed

simple/run-small-indexes.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
function main () {
2+
require("./simple/test").test({
3+
outputCsv: true,
4+
small: true,
5+
indexes: true
6+
});
7+
}
8+
if (typeof arango !== "undefined") {
9+
main();
10+
}

simple/test.js

Lines changed: 114 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
/* jshint globalstrict:false, strict:false, maxlen: 500 */
2+
/* global aql, GLOBAL, makeGraph, makeTree, */
13
"use strict";
24
const internal = require("internal");
35
const arango = internal.arango;
@@ -96,7 +98,7 @@ function toAsciiTable (title, out) {
9698

9799
return table.toString();
98100
}
99-
101+
let randomPoint;
100102
exports.test = function (testParams) {
101103
testParams.tiny = testParams.tiny || false;
102104
testParams.small = testParams.small || false;
@@ -135,7 +137,8 @@ exports.test = function (testParams) {
135137

136138
// Substring first 5 characters to limit to A.B.C format and not use any `nightly`, `rc`, `preview` etc.
137139
const serverVersion = (((typeof arango) !== "undefined") ? arango.getVersion() : internal.version).split("-")[0];
138-
testParams.zkdMdiRenamed = semver.satisfies(serverVersion, ">3.11.99") ;
140+
print(serverVersion)
141+
testParams.zkdMdiRenamed = semver.satisfies(serverVersion, ">3.11.99");
139142
const isEnterprise = internal.isEnterprise();
140143
const isCluster = internal.isCluster();
141144

@@ -214,14 +217,14 @@ exports.test = function (testParams) {
214217
let errors = [];
215218
for (let i = 0; i < tests.length; ++i) {
216219
let test = tests[i];
217-
print(test)
220+
print(test);
218221
try {
219-
if (!(test['version'] === undefined || semver.satisfies(serverVersion, test['version']))) {
220-
print(`skipping test ${test['name']}, requires version ${test['version']}`);
221-
} else if (test['legacy'] && !testParams.legacy) {
222-
print(`skipping legacy test ${test['name']}`);
222+
if (!(test["version"] === undefined || semver.satisfies(serverVersion, test["version"]))) {
223+
print(`skipping test ${test["name"]}, requires version ${test["version"]}`);
224+
} else if (test["legacy"] && !testParams.legacy) {
225+
print(`skipping legacy test ${test["name"]}`);
223226
} else {
224-
print(`running test ${test['name']}`);
227+
print(`running test ${test["name"]}`);
225228
for (let j = 0; j < options.collections.length; ++j) {
226229
let collection = options.collections[j];
227230

@@ -231,7 +234,7 @@ exports.test = function (testParams) {
231234
const stats = calc(results, options);
232235

233236
const result = {
234-
name: test['name'],
237+
name: test["name"],
235238
runs: options.runs,
236239
min: stats.min.toFixed(options.digits),
237240
max: stats.max.toFixed(options.digits),
@@ -253,8 +256,8 @@ exports.test = function (testParams) {
253256
} // for j
254257
}
255258
} catch (ex) {
256-
print(`exception in test ${test['name']}: ${String(ex)}\n${String(ex.stack)}`);
257-
errors.push({ name: test['name'], error: ex });
259+
print(`exception in test ${test["name"]}: ${String(ex)}\n${String(ex.stack)}`);
260+
errors.push({ name: test["name"], error: ex });
258261
GLOBAL.returnValue = 1;
259262
}
260263
} // for i
@@ -810,7 +813,6 @@ exports.test = function (testParams) {
810813
createArangoSearch(viewParams);
811814
}
812815
},
813-
814816
fill = function (params) {
815817
let c = db._collection(params.collection),
816818
n = parseInt(params.collection.replace(/[a-z]+/g, ""), 10),
@@ -819,34 +821,78 @@ exports.test = function (testParams) {
819821
for (let i = 0; i < docSize; ++i) {
820822
doc["value" + i] = i;
821823
}
824+
let vectors = [];
825+
if (params.type === "vector") {
826+
const seed = 12132390894;
827+
const randomNumberGeneratorFloat = function (seed) {
828+
const rng = (function *(seed) {
829+
while (true) {
830+
const nextVal = Math.cos(seed++);
831+
yield nextVal;
832+
}
833+
})(seed);
834+
835+
return function () {
836+
return rng.next().value;
837+
};
838+
};
839+
let gen = randomNumberGeneratorFloat(seed);
840+
841+
for (let i = 0; i < n; ++i) {
842+
const vector = Array.from({
843+
length: params.dimension
844+
}, () => gen());
845+
if (i === 250) {
846+
randomPoint = vector;
847+
}
848+
vectors.push({
849+
vector,
850+
nonVector: i,
851+
unIndexedVector: vector
852+
});
853+
}
854+
}
822855

823856
const batchSize = params.batchSize;
824857
if (batchSize) {
825858
// perform babies operations
826859
for (let i = 0; i < n / batchSize; ++i) {
827860
let docs = [];
828861
for (let j = 0; j < batchSize; ++j) {
829-
docs.push({ _key: "test" + (i * batchSize + j), ...doc });
862+
let oneDoc = { _key: "test" + (i * batchSize + j), ...doc };
863+
if (params.type === "vector") {
864+
let vec = vectors[i * batchSize + j];
865+
oneDoc["vector"] = vec.vector;
866+
oneDoc["nonVector"] = vec.nonVector;
867+
oneDoc["unIndexedVector"] = vec.unIndexedVector;
868+
}
869+
docs.push(oneDoc);
830870
}
831871
c.insert(docs);
832872
}
833873
} else {
834874
// perform single document operations
835875
for (let i = 0; i < n; ++i) {
836876
doc._key = "test" + i;
877+
if (params.type === "vector") {
878+
let vec = vectors[i];
879+
doc["vector"] = vec.vector;
880+
doc["nonVector"] = vec.nonVector;
881+
doc["unIndexedVector"] = vec.unIndexedVector;
882+
}
837883
c.insert(doc);
838884
}
839885
}
840886
},
841-
887+
842888
// /////////////////////////////////////////////////////////////////////////////
843889
// indexes tests
844890
// /////////////////////////////////////////////////////////////////////////////
845891

846892
insertIndexOne = function (params) {
847893
let c = db._collection(params.collection),
848894
n = parseInt(params.collection.replace(/[a-z]+/g, ""), 10);
849-
895+
850896
// perform small batch document operations
851897
const batchSize = params.batchSize || 100;
852898
let docs = [];
@@ -868,11 +914,11 @@ exports.test = function (testParams) {
868914
}
869915
}
870916
},
871-
917+
872918
insertIndexTwo = function (params) {
873919
let c = db._collection(params.collection),
874920
n = parseInt(params.collection.replace(/[a-z]+/g, ""), 10);
875-
921+
876922
// perform small batch document operations
877923
const batchSize = params.batchSize || 100;
878924
let docs = [];
@@ -1002,10 +1048,10 @@ exports.test = function (testParams) {
10021048
// edgeTests
10031049
// /////////////////////////////////////////////////////////////////////////////
10041050

1005-
traversalProjections = function(params) {
1051+
traversalProjections = function () {
10061052
// Note that depth 8 is good for all three sizes small (6), medium (7)
10071053
// and big (8). Depending on the size, we create a different tree.
1008-
db._query(`FOR v IN 0..8 OUTBOUND "TreeV/S1:K1" GRAPH "Tree" RETURN v.data`, {}, {}, {silent});
1054+
db._query("FOR v IN 0..8 OUTBOUND \"TreeV/S1:K1\" GRAPH \"Tree\" RETURN v.data", {}, {}, {silent});
10091055
},
10101056

10111057
outbound = function (params) {
@@ -2171,7 +2217,7 @@ exports.test = function (testParams) {
21712217
setup: function (params) {
21722218
drop(params);
21732219
create(params);
2174-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1", "value2"] });
2220+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1", "value2"] });
21752221
}
21762222
}
21772223
},
@@ -2394,7 +2440,7 @@ exports.test = function (testParams) {
23942440
setup: function (params) {
23952441
drop(params);
23962442
create(params);
2397-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"] });
2443+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"] });
23982444
},
23992445
type: "number",
24002446
teardown: drop
@@ -2407,7 +2453,7 @@ exports.test = function (testParams) {
24072453
setup: function (params) {
24082454
drop(params);
24092455
create(params);
2410-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"], estimates: false });
2456+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"], estimates: false });
24112457
},
24122458
type: "number",
24132459
teardown: drop
@@ -2420,7 +2466,7 @@ exports.test = function (testParams) {
24202466
setup: function (params) {
24212467
drop(params);
24222468
create(params);
2423-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"] });
2469+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"] });
24242470
},
24252471
type: "string",
24262472
teardown: drop
@@ -2433,7 +2479,7 @@ exports.test = function (testParams) {
24332479
setup: function (params) {
24342480
drop(params);
24352481
create(params);
2436-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"], estimates: false });
2482+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"], estimates: false });
24372483
},
24382484
type: "string",
24392485
teardown: drop
@@ -2446,8 +2492,8 @@ exports.test = function (testParams) {
24462492
setup: function (params) {
24472493
drop(params);
24482494
create(params);
2449-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"] });
2450-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value2"] });
2495+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"] });
2496+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value2"] });
24512497
},
24522498
type: "number",
24532499
teardown: drop
@@ -2460,8 +2506,8 @@ exports.test = function (testParams) {
24602506
setup: function (params) {
24612507
drop(params);
24622508
create(params);
2463-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"], estimates: false });
2464-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value2"], estimates: false });
2509+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"], estimates: false });
2510+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value2"], estimates: false });
24652511
},
24662512
type: "number",
24672513
teardown: drop
@@ -2474,8 +2520,8 @@ exports.test = function (testParams) {
24742520
setup: function (params) {
24752521
drop(params);
24762522
create(params);
2477-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"] });
2478-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value2"] });
2523+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"] });
2524+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value2"] });
24792525
},
24802526
type: "string",
24812527
teardown: drop
@@ -2488,13 +2534,44 @@ exports.test = function (testParams) {
24882534
setup: function (params) {
24892535
drop(params);
24902536
create(params);
2491-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"], estimates: false });
2492-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value2"], estimates: false });
2537+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"], estimates: false });
2538+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value2"], estimates: false });
24932539
},
24942540
type: "string",
24952541
teardown: drop
24962542
}
24972543
},
2544+
{
2545+
name: "indexes-vector",
2546+
params: {
2547+
vector: true,
2548+
dimension: 500,
2549+
setup: function (params) {
2550+
drop(params);
2551+
create(params);
2552+
fill(params);
2553+
db[params.collection].ensureIndex({
2554+
name: "vector_l2",
2555+
type: "vector",
2556+
fields: ["vector"],
2557+
inBackground: false,
2558+
params: {
2559+
metric: "l2",
2560+
dimension: params.dimension,
2561+
nLists: 10,
2562+
trainingIterations: 10
2563+
}
2564+
});
2565+
},
2566+
func: function (params) {
2567+
db._query(aql`FOR d IN
2568+
${db[params.collection]}
2569+
SORT APPROX_NEAR_L2(d.vector, ${randomPoint}) LIMIT 5 RETURN {key: d._key}`).toArray();
2570+
},
2571+
type: "vector",
2572+
teardown: drop
2573+
}
2574+
}
24982575
];
24992576

25002577
// Tests without collections/IO, to focus on aql block performance.
@@ -2553,7 +2630,7 @@ exports.test = function (testParams) {
25532630
{
25542631
name: "traversal-projections",
25552632
params: { func: traversalProjections }
2556-
},
2633+
},
25572634
{
25582635
name: "traversal-outbound-1",
25592636
params: { func: outbound, minDepth: 1, maxDepth: 1, loops: 1000 }
@@ -3280,7 +3357,7 @@ exports.test = function (testParams) {
32803357
}
32813358
db._query(
32823359
params.queryString,
3283-
bindParam,
3360+
bindParam
32843361
);
32853362
}
32863363

@@ -3334,7 +3411,7 @@ exports.test = function (testParams) {
33343411
FILTER d.x == 9 and d.y >= 52
33353412
RETURN d`
33363413
}
3337-
},
3414+
}
33383415
];
33393416

33403417
const runSatelliteGraphTests = (testParams.satelliteGraphTests && isEnterprise && isCluster);
@@ -3418,7 +3495,7 @@ exports.test = function (testParams) {
34183495
setup: function (params) {
34193496
db._drop(params.collection);
34203497
let col = db._create(params.collection);
3421-
let type = (testParams.zkdMdiRenamed) ? "mdi":"zkd";
3498+
let type = (testParams.zkdMdiRenamed) ? "mdi" : "zkd";
34223499
col.ensureIndex({type: type, name: "mdiIndex", fields: ["x", "y"], fieldValueTypes: "double"});
34233500
db._query(`
34243501
FOR i IN 0..${params.collectionSize}
@@ -3590,7 +3667,7 @@ exports.test = function (testParams) {
35903667

35913668
runTestSuite("Arango Search No Materialization", arangosearchNoMaterializationTests, options);
35923669
}
3593-
3670+
35943671
// indexes tests
35953672
if (testParams.indexes) {
35963673
options = {

0 commit comments

Comments
 (0)