Skip to content

Commit d6d4588

Browse files
jbajicdothebart
andauthored
Add vector performance test (#58)
* Add vector performance test * Add vector subquery test * Rename dimensions to dimension * enable vector tests * reduce memory usage * round * disable for older versions * add _key so the documents are distributed properly across the shards * Fix vector index setup * Add additional print --------- Co-authored-by: Wilfried Goesgens <willi@arangodb.com>
1 parent 5fc4de6 commit d6d4588

File tree

9 files changed

+175
-9
lines changed

9 files changed

+175
-9
lines changed

simple/run-big-all-runs1.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ function main () {
1414
crud: true,
1515
crudSearch: true,
1616
subqueryTests: true,
17-
mditests: true
17+
mditests: true,
18+
vectorTests: true
1819
});
1920
return GLOBAL.returnValue;
2021
}

simple/run-big-all.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ function main () {
1414
crud: true,
1515
crudSearch: true,
1616
subqueryTests: true,
17-
mditests: true
17+
mditests: true,
18+
vectorTests: true
1819
});
1920
print('oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo')
2021
print(GLOBAL.returnValue)

simple/run-medium-all-runs1.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ function main () {
1414
crud: true,
1515
crudSearch: true,
1616
subqueryTests: true,
17-
mditests: true
17+
mditests: true,
18+
vectorTests: true
1819
});
1920
return GLOBAL.returnValue;
2021
}

simple/run-medium-all.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ function main () {
1414
crud: true,
1515
crudSearch: true,
1616
subqueryTests: true,
17-
mditests: true
17+
mditests: true,
18+
vectorTests: true
1819
});
1920
return GLOBAL.returnValue;
2021
}

simple/run-small-all-junit.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ function main () {
1313
phrase: true,
1414
crud: true,
1515
crudSearch: true,
16-
mditests: true
16+
mditests: true,
17+
vectorTests: true
1718
});
1819
return GLOBAL.returnValue;
1920
}

simple/run-small-all.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ function main () {
1313
noMaterializationSearch: true,
1414
crud: true,
1515
crudSearch: true,
16-
mditests: true
16+
mditests: true,
17+
vectorTests: true
1718
});
1819
return GLOBAL.returnValue;
1920
}

simple/run-tiny-all.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ function main () {
1515
crud: true,
1616
crudSearch: true,
1717
subqueryTests: true,
18-
mditests: true
18+
mditests: true,
19+
vectorTests: true
1920
});
2021
return GLOBAL.returnValue;
2122
}

simple/run-vector.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
function main () {
2+
global.returnValue = 0;
3+
require("./simple/test").test({
4+
outputCsv: false,
5+
small: true,
6+
runs: 3,
7+
documents: false,
8+
ioless: false,
9+
edges: false,
10+
search: false,
11+
phrase: false,
12+
noMaterializationSearch: false,
13+
crud: false,
14+
crudSearch: false,
15+
subqueryTests: false,
16+
mditests: false,
17+
vectorTests: true
18+
});
19+
return global.returnValue;
20+
}
21+
if (typeof arango !== "undefined") {
22+
process.exit(main());
23+
}

simple/test.js

Lines changed: 138 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,19 @@ function sum (values) {
1919
}
2020
}
2121

22+
function randomNumberGeneratorFloat(seed) {
23+
const rng = (function* (seed) {
24+
while (true) {
25+
const nextVal = Math.cos(seed++);
26+
yield nextVal;
27+
}
28+
})(seed);
29+
30+
return function () {
31+
return rng.next().value;
32+
};
33+
}
34+
2235
function calc (values, options) {
2336
values.sort((a, b) => a - b);
2437

@@ -135,7 +148,8 @@ exports.test = function (testParams) {
135148

136149
// Substring first 5 characters to limit to A.B.C format and not use any `nightly`, `rc`, `preview` etc.
137150
const serverVersion = (((typeof arango) !== "undefined") ? arango.getVersion() : internal.version).split("-")[0];
138-
testParams.zkdMdiRenamed = semver.satisfies(serverVersion, ">3.11.99") ;
151+
testParams.zkdMdiRenamed = semver.satisfies(serverVersion, ">3.11.99");
152+
testParams.vectorTests = testParams.vectorTests && semver.satisfies(serverVersion, ">3.12.4");
139153
const isEnterprise = internal.isEnterprise();
140154
const isCluster = internal.isCluster();
141155

@@ -156,6 +170,10 @@ exports.test = function (testParams) {
156170
if (options.hasOwnProperty("iterations")) {
157171
params.iterations = options.iterations;
158172
}
173+
if (options.hasOwnProperty("extras")) {
174+
params.extras = options.extras;
175+
}
176+
159177
return params;
160178
};
161179

@@ -214,7 +232,7 @@ exports.test = function (testParams) {
214232
let errors = [];
215233
for (let i = 0; i < tests.length; ++i) {
216234
let test = tests[i];
217-
print(test)
235+
print(test);
218236
try {
219237
if (!(test['version'] === undefined || semver.satisfies(serverVersion, test['version']))) {
220238
print(`skipping test ${test['name']}, requires version ${test['version']}`);
@@ -3333,6 +3351,59 @@ exports.test = function (testParams) {
33333351
},
33343352
];
33353353

3354+
function vectorTest (params) {
3355+
let bindParam = { "@col": params.collection, "qp": params.extras.queryPoint };
3356+
if ("bindParamModifier" in params) {
3357+
params.bindParamModifier(params, bindParam);
3358+
}
3359+
db._query(
3360+
params.queryString,
3361+
bindParam,
3362+
);
3363+
}
3364+
3365+
function vectorTestNoParams (params) {
3366+
let bindParam = { "@col": params.collection };
3367+
if ("bindParamModifier" in params) {
3368+
params.bindParamModifier(params, bindParam);
3369+
}
3370+
db._query(
3371+
params.queryString,
3372+
bindParam,
3373+
);
3374+
}
3375+
3376+
let VectorTests = [
3377+
{
3378+
name: "aql-vector-top-k",
3379+
params: {
3380+
func: vectorTest,
3381+
queryString: `
3382+
FOR d IN @@col
3383+
SORT APPROX_NEAR_L2(d.vector, @qp)
3384+
LIMIT 5
3385+
RETURN d`
3386+
}
3387+
},
3388+
{
3389+
name: "aql-vector-subquery-10-points",
3390+
params: {
3391+
func: vectorTestNoParams,
3392+
queryString: `
3393+
FOR docOuter IN @@col
3394+
LIMIT 10
3395+
LET neibhours = (
3396+
FOR docInner IN @@col
3397+
LET dist = APPROX_NEAR_L2(docInner.vector, docOuter.vector)
3398+
SORT dist
3399+
LIMIT 10
3400+
RETURN {dist, doc: docInner._key}
3401+
)
3402+
RETURN {doc: docOuter._key, neibhours: neibhours}`
3403+
}
3404+
},
3405+
];
3406+
33363407
const runSatelliteGraphTests = (testParams.satelliteGraphTests && isEnterprise && isCluster);
33373408

33383409
if (testParams.documents || testParams.edges || testParams.noMaterializationSearch || testParams.subqueryTests || runSatelliteGraphTests) {
@@ -3441,6 +3512,71 @@ exports.test = function (testParams) {
34413512
runTestSuite("MDI", MdiTests, options);
34423513
}
34433514

3515+
// vector tests
3516+
if (testParams.vectorTests) {
3517+
const dimension = 500;
3518+
let gen = randomNumberGeneratorFloat(3243758343);
3519+
let randomPoint = Array.from({ length: dimension }, () => gen());
3520+
3521+
options = {
3522+
runs: testParams.runs,
3523+
digits: testParams.digits,
3524+
setup: function (params) {
3525+
db._drop(params.collection);
3526+
let col = db._create(params.collection);
3527+
3528+
const batchSize = 1000;
3529+
const n = Math.round(params.collectionSize / batchSize);
3530+
print("Preparing vector collection with " + params.collectionSize + " documents and batchSize: " + batchSize);
3531+
for (let i = 0; i < n; ++i) {
3532+
internal.wait(0, true); // garbage collect...
3533+
let docs = [];
3534+
for (let j = 0; j < batchSize; ++j) {
3535+
const vector = Array.from({ length: dimension }, () => gen());
3536+
if (i * batchSize + j === 2000) {
3537+
randomPoint = vector;
3538+
}
3539+
docs.push({_key: "test_" + (j + i* batchSize), vector: vector });
3540+
}
3541+
col.insert(docs);
3542+
}
3543+
print("Number of docs in vector index collection: " + col.count());
3544+
3545+
print("Creating vector index");
3546+
col.ensureIndex({
3547+
name: "vector_l2",
3548+
type: "vector",
3549+
fields: ["vector"],
3550+
inBackground: false,
3551+
params: { metric: "l2", dimension: dimension, nLists: params.extras.nLists },
3552+
});
3553+
print("Vector index created: " + JSON.stringify(col.indexes()));
3554+
},
3555+
teardown: function () {},
3556+
collections: [],
3557+
removeFromResult: 1
3558+
};
3559+
3560+
let extras = { queryPoint: randomPoint };
3561+
3562+
if (testParams.tiny) {
3563+
options.collections.push({ name: "Vectorvalues1000", label: "1k", size: 1000 });
3564+
extras["nLists"] = 10;
3565+
} else if (testParams.small) {
3566+
options.collections.push({ name: "Vectorvalues10000", label: "10k", size: 10000 });
3567+
extras["nLists"] = 100;
3568+
} else if (testParams.medium) {
3569+
options.collections.push({ name: "Vectorvalues100000", label: "100k", size: 100000 });
3570+
extras["nLists"] = 1000;
3571+
} else if (testParams.big) {
3572+
options.collections.push({ name: "Vectorvalues1000000", label: "1000k", size: 1000000 });
3573+
extras["nLists"] = 10000;
3574+
}
3575+
options.extras = extras;
3576+
3577+
runTestSuite("Vector", VectorTests, options);
3578+
}
3579+
34443580
if (testParams.ioless) {
34453581
options = {
34463582
runs: testParams.runs,

0 commit comments

Comments
 (0)