Skip to content

Commit 664ea21

Browse files
committed
add first draft vector index test
1 parent 5fc4de6 commit 664ea21

File tree

2 files changed

+130
-37
lines changed

2 files changed

+130
-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: 120 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,7 @@ 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+
testParams.zkdMdiRenamed = semver.satisfies(serverVersion, ">3.11.99");
139141
const isEnterprise = internal.isEnterprise();
140142
const isCluster = internal.isCluster();
141143

@@ -214,14 +216,14 @@ exports.test = function (testParams) {
214216
let errors = [];
215217
for (let i = 0; i < tests.length; ++i) {
216218
let test = tests[i];
217-
print(test)
219+
print(test);
218220
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']}`);
221+
if (!(test["version"] === undefined || semver.satisfies(serverVersion, test["version"]))) {
222+
print(`skipping test ${test["name"]}, requires version ${test["version"]}`);
223+
} else if (test["legacy"] && !testParams.legacy) {
224+
print(`skipping legacy test ${test["name"]}`);
223225
} else {
224-
print(`running test ${test['name']}`);
226+
print(`running test ${test["name"]}`);
225227
for (let j = 0; j < options.collections.length; ++j) {
226228
let collection = options.collections[j];
227229

@@ -231,7 +233,7 @@ exports.test = function (testParams) {
231233
const stats = calc(results, options);
232234

233235
const result = {
234-
name: test['name'],
236+
name: test["name"],
235237
runs: options.runs,
236238
min: stats.min.toFixed(options.digits),
237239
max: stats.max.toFixed(options.digits),
@@ -253,8 +255,8 @@ exports.test = function (testParams) {
253255
} // for j
254256
}
255257
} catch (ex) {
256-
print(`exception in test ${test['name']}: ${String(ex)}\n${String(ex.stack)}`);
257-
errors.push({ name: test['name'], error: ex });
258+
print(`exception in test ${test["name"]}: ${String(ex)}\n${String(ex.stack)}`);
259+
errors.push({ name: test["name"], error: ex });
258260
GLOBAL.returnValue = 1;
259261
}
260262
} // for i
@@ -810,7 +812,6 @@ exports.test = function (testParams) {
810812
createArangoSearch(viewParams);
811813
}
812814
},
813-
814815
fill = function (params) {
815816
let c = db._collection(params.collection),
816817
n = parseInt(params.collection.replace(/[a-z]+/g, ""), 10),
@@ -819,34 +820,78 @@ exports.test = function (testParams) {
819820
for (let i = 0; i < docSize; ++i) {
820821
doc["value" + i] = i;
821822
}
823+
let vectors = [];
824+
if (params.type === "vector") {
825+
const seed = 12132390894;
826+
const randomNumberGeneratorFloat = function (seed) {
827+
const rng = (function *(seed) {
828+
while (true) {
829+
const nextVal = Math.cos(seed++);
830+
yield nextVal;
831+
}
832+
})(seed);
833+
834+
return function () {
835+
return rng.next().value;
836+
};
837+
};
838+
let gen = randomNumberGeneratorFloat(seed);
839+
840+
for (let i = 0; i < n; ++i) {
841+
const vector = Array.from({
842+
length: params.dimension
843+
}, () => gen());
844+
if (i === 250) {
845+
randomPoint = vector;
846+
}
847+
vectors.push({
848+
vector,
849+
nonVector: i,
850+
unIndexedVector: vector
851+
});
852+
}
853+
}
822854

823855
const batchSize = params.batchSize;
824856
if (batchSize) {
825857
// perform babies operations
826858
for (let i = 0; i < n / batchSize; ++i) {
827859
let docs = [];
828860
for (let j = 0; j < batchSize; ++j) {
829-
docs.push({ _key: "test" + (i * batchSize + j), ...doc });
861+
let oneDoc = { _key: "test" + (i * batchSize + j), ...doc };
862+
if (params.type === "vector") {
863+
let vec = vectors[i * batchSize + j];
864+
oneDoc["vector"] = vec.vector;
865+
oneDoc["nonVector"] = vec.nonVector;
866+
oneDoc["unIndexedVector"] = vec.unIndexedVector;
867+
}
868+
docs.push(oneDoc);
830869
}
831870
c.insert(docs);
832871
}
833872
} else {
834873
// perform single document operations
835874
for (let i = 0; i < n; ++i) {
836875
doc._key = "test" + i;
876+
if (params.type === "vector") {
877+
let vec = vectors[i];
878+
doc["vector"] = vec.vector;
879+
doc["nonVector"] = vec.nonVector;
880+
doc["unIndexedVector"] = vec.unIndexedVector;
881+
}
837882
c.insert(doc);
838883
}
839884
}
840885
},
841-
886+
842887
// /////////////////////////////////////////////////////////////////////////////
843888
// indexes tests
844889
// /////////////////////////////////////////////////////////////////////////////
845890

846891
insertIndexOne = function (params) {
847892
let c = db._collection(params.collection),
848893
n = parseInt(params.collection.replace(/[a-z]+/g, ""), 10);
849-
894+
850895
// perform small batch document operations
851896
const batchSize = params.batchSize || 100;
852897
let docs = [];
@@ -868,11 +913,11 @@ exports.test = function (testParams) {
868913
}
869914
}
870915
},
871-
916+
872917
insertIndexTwo = function (params) {
873918
let c = db._collection(params.collection),
874919
n = parseInt(params.collection.replace(/[a-z]+/g, ""), 10);
875-
920+
876921
// perform small batch document operations
877922
const batchSize = params.batchSize || 100;
878923
let docs = [];
@@ -1002,10 +1047,10 @@ exports.test = function (testParams) {
10021047
// edgeTests
10031048
// /////////////////////////////////////////////////////////////////////////////
10041049

1005-
traversalProjections = function(params) {
1050+
traversalProjections = function () {
10061051
// Note that depth 8 is good for all three sizes small (6), medium (7)
10071052
// 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});
1053+
db._query("FOR v IN 0..8 OUTBOUND \"TreeV/S1:K1\" GRAPH \"Tree\" RETURN v.data", {}, {}, {silent});
10091054
},
10101055

10111056
outbound = function (params) {
@@ -2169,7 +2214,14 @@ exports.test = function (testParams) {
21692214
},
21702215
{
21712216
name: "aql-index-collect-aggregate",
2172-
params: { func: indexCollectAggregate, attr: "value1" }
2217+
params: {
2218+
func: indexCollectAggregate,
2219+
setup: function (params) {
2220+
drop(params);
2221+
create(params);
2222+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1", "value2"] });
2223+
}
2224+
}
21732225
},
21742226
{
21752227
name: "aql-subquery",
@@ -2390,7 +2442,7 @@ exports.test = function (testParams) {
23902442
setup: function (params) {
23912443
drop(params);
23922444
create(params);
2393-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"] });
2445+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"] });
23942446
},
23952447
type: "number",
23962448
teardown: drop
@@ -2403,7 +2455,7 @@ exports.test = function (testParams) {
24032455
setup: function (params) {
24042456
drop(params);
24052457
create(params);
2406-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"], estimates: false });
2458+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"], estimates: false });
24072459
},
24082460
type: "number",
24092461
teardown: drop
@@ -2416,7 +2468,7 @@ exports.test = function (testParams) {
24162468
setup: function (params) {
24172469
drop(params);
24182470
create(params);
2419-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"] });
2471+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"] });
24202472
},
24212473
type: "string",
24222474
teardown: drop
@@ -2429,7 +2481,7 @@ exports.test = function (testParams) {
24292481
setup: function (params) {
24302482
drop(params);
24312483
create(params);
2432-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"], estimates: false });
2484+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"], estimates: false });
24332485
},
24342486
type: "string",
24352487
teardown: drop
@@ -2442,8 +2494,8 @@ exports.test = function (testParams) {
24422494
setup: function (params) {
24432495
drop(params);
24442496
create(params);
2445-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"] });
2446-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value2"] });
2497+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"] });
2498+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value2"] });
24472499
},
24482500
type: "number",
24492501
teardown: drop
@@ -2456,8 +2508,8 @@ exports.test = function (testParams) {
24562508
setup: function (params) {
24572509
drop(params);
24582510
create(params);
2459-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"], estimates: false });
2460-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value2"], estimates: false });
2511+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"], estimates: false });
2512+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value2"], estimates: false });
24612513
},
24622514
type: "number",
24632515
teardown: drop
@@ -2470,8 +2522,8 @@ exports.test = function (testParams) {
24702522
setup: function (params) {
24712523
drop(params);
24722524
create(params);
2473-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"] });
2474-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value2"] });
2525+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"] });
2526+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value2"] });
24752527
},
24762528
type: "string",
24772529
teardown: drop
@@ -2484,13 +2536,44 @@ exports.test = function (testParams) {
24842536
setup: function (params) {
24852537
drop(params);
24862538
create(params);
2487-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"], estimates: false });
2488-
db[params.collection].ensureIndex({ type: "persistent", fields: ["value2"], estimates: false });
2539+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value1"], estimates: false });
2540+
db[params.collection].ensureIndex({ type: "persistent", fields: ["value2"], estimates: false });
24892541
},
24902542
type: "string",
24912543
teardown: drop
24922544
}
24932545
},
2546+
{
2547+
name: "indexes-vector",
2548+
params: {
2549+
vector: true,
2550+
dimension: 500,
2551+
setup: function (params) {
2552+
drop(params);
2553+
create(params);
2554+
fill(params);
2555+
db[params.collection].ensureIndex({
2556+
name: "vector_l2",
2557+
type: "vector",
2558+
fields: ["vector"],
2559+
inBackground: false,
2560+
params: {
2561+
metric: "l2",
2562+
dimension: params.dimension,
2563+
nLists: 10,
2564+
trainingIterations: 10
2565+
}
2566+
});
2567+
},
2568+
func: function (params) {
2569+
db._query(aql`FOR d IN
2570+
${db[params.collection]}
2571+
SORT APPROX_NEAR_L2(d.vector, ${randomPoint}) LIMIT 5 RETURN {key: d._key}`).toArray();
2572+
},
2573+
type: "vector",
2574+
teardown: drop
2575+
}
2576+
}
24942577
];
24952578

24962579
// Tests without collections/IO, to focus on aql block performance.
@@ -2549,7 +2632,7 @@ exports.test = function (testParams) {
25492632
{
25502633
name: "traversal-projections",
25512634
params: { func: traversalProjections }
2552-
},
2635+
},
25532636
{
25542637
name: "traversal-outbound-1",
25552638
params: { func: outbound, minDepth: 1, maxDepth: 1, loops: 1000 }
@@ -3276,7 +3359,7 @@ exports.test = function (testParams) {
32763359
}
32773360
db._query(
32783361
params.queryString,
3279-
bindParam,
3362+
bindParam
32803363
);
32813364
}
32823365

@@ -3330,7 +3413,7 @@ exports.test = function (testParams) {
33303413
FILTER d.x == 9 and d.y >= 52
33313414
RETURN d`
33323415
}
3333-
},
3416+
}
33343417
];
33353418

33363419
const runSatelliteGraphTests = (testParams.satelliteGraphTests && isEnterprise && isCluster);
@@ -3414,7 +3497,7 @@ exports.test = function (testParams) {
34143497
setup: function (params) {
34153498
db._drop(params.collection);
34163499
let col = db._create(params.collection);
3417-
let type = (testParams.zkdMdiRenamed) ? "mdi":"zkd";
3500+
let type = (testParams.zkdMdiRenamed) ? "mdi" : "zkd";
34183501
col.ensureIndex({type: type, name: "mdiIndex", fields: ["x", "y"], fieldValueTypes: "double"});
34193502
db._query(`
34203503
FOR i IN 0..${params.collectionSize}
@@ -3586,7 +3669,7 @@ exports.test = function (testParams) {
35863669

35873670
runTestSuite("Arango Search No Materialization", arangosearchNoMaterializationTests, options);
35883671
}
3589-
3672+
35903673
// indexes tests
35913674
if (testParams.indexes) {
35923675
options = {

0 commit comments

Comments
 (0)