@@ -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+
2235function 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