@@ -85036,6 +85036,8 @@ typedef u8 MetricType;
85036
85036
#define VECTOR_SEARCH_L_PARAM_ID 9
85037
85037
#define VECTOR_SEARCH_L_DEFAULT 200
85038
85038
85039
+ #define VECTOR_MAX_NEIGHBORS_PARAM_ID 10
85040
+
85039
85041
/* total amount of vector index parameters */
85040
85042
#define VECTOR_PARAM_IDS_COUNT 9
85041
85043
@@ -209459,6 +209461,7 @@ SQLITE_PRIVATE void sqlite3RegisterVectorFunctions(void){
209459
209461
*/
209460
209462
#ifndef SQLITE_OMIT_VECTOR
209461
209463
209464
+ /* #include "math.h" */
209462
209465
/* #include "sqliteInt.h" */
209463
209466
/* #include "vectorIndexInt.h" */
209464
209467
@@ -209474,6 +209477,11 @@ SQLITE_PRIVATE void sqlite3RegisterVectorFunctions(void){
209474
209477
// stack simplify memory managment code and also doesn't impose very strict limits here since 128 bytes for column names should be enough for almost all use cases
209475
209478
#define DISKANN_SQL_RENDER_LIMIT 128
209476
209479
209480
+ // limit to the maximum size of DiskANN block (128 MB)
209481
+ // even with 1MB we can store tens of thousands of nodes in several GBs - which is already too much
209482
+ // but we are "generous" here and allow user to store up to 128MB blobs
209483
+ #define DISKANN_MAX_BLOCK_SZ 134217728
209484
+
209477
209485
/*
209478
209486
* Due to historical reasons parameter for index block size were stored as u16 value and divided by 512 (2^9)
209479
209487
* So, we will make inverse transform before initializing index from stored parameters
@@ -209673,8 +209681,16 @@ void blobSpotFree(BlobSpot *pBlobSpot) {
209673
209681
** Layout specific utilities
209674
209682
**************************************************************************/
209675
209683
209684
+ int nodeEdgeOverhead(int nEdgeVectorSize){
209685
+ return nEdgeVectorSize + VECTOR_EDGE_METADATA_SIZE;
209686
+ }
209687
+
209688
+ int nodeOverhead(int nNodeVectorSize){
209689
+ return nNodeVectorSize + VECTOR_NODE_METADATA_SIZE;
209690
+ }
209691
+
209676
209692
int nodeEdgesMaxCount(const DiskAnnIndex *pIndex){
209677
- unsigned int nMaxEdges = (pIndex->nBlockSize - pIndex->nNodeVectorSize - VECTOR_NODE_METADATA_SIZE) / (pIndex->nEdgeVectorSize + VECTOR_EDGE_METADATA_SIZE );
209693
+ unsigned int nMaxEdges = (pIndex->nBlockSize - nodeOverhead( pIndex->nNodeVectorSize)) / nodeEdgeOverhead (pIndex->nEdgeVectorSize);
209678
209694
assert( nMaxEdges > 0);
209679
209695
return nMaxEdges;
209680
209696
}
@@ -209829,6 +209845,8 @@ int diskAnnCreateIndex(
209829
209845
VectorIdxParams *pParams
209830
209846
){
209831
209847
int rc;
209848
+ int type, dims;
209849
+ u64 maxNeighborsParam, blockSizeBytes;
209832
209850
char *zSql;
209833
209851
char columnSqlDefs[DISKANN_SQL_RENDER_LIMIT]; // definition of columns (e.g. index_key INTEGER BINARY, index_key1 TEXT, ...)
209834
209852
char columnSqlNames[DISKANN_SQL_RENDER_LIMIT]; // just column names (e.g. index_key, index_key1, index_key2, ...)
@@ -209841,16 +209859,34 @@ int diskAnnCreateIndex(
209841
209859
if( vectorIdxParamsPutU64(pParams, VECTOR_INDEX_TYPE_PARAM_ID, VECTOR_INDEX_TYPE_DISKANN) != 0 ){
209842
209860
return SQLITE_ERROR;
209843
209861
}
209862
+ type = vectorIdxParamsGetU64(pParams, VECTOR_TYPE_PARAM_ID);
209863
+ if( type == 0 ){
209864
+ return SQLITE_ERROR;
209865
+ }
209866
+ dims = vectorIdxParamsGetU64(pParams, VECTOR_DIM_PARAM_ID);
209867
+ if( dims == 0 ){
209868
+ return SQLITE_ERROR;
209869
+ }
209870
+ assert( 0 < dims && dims <= MAX_VECTOR_SZ );
209871
+
209872
+ maxNeighborsParam = vectorIdxParamsGetU64(pParams, VECTOR_MAX_NEIGHBORS_PARAM_ID);
209873
+ if( maxNeighborsParam == 0 ){
209874
+ // 3 D**(1/2) gives good recall values (90%+)
209875
+ // we also want to keep disk overhead at moderate level - 50x of the disk size increase is the current upper bound
209876
+ maxNeighborsParam = MIN(3 * ((int)(sqrt(dims)) + 1), (50 * nodeOverhead(vectorDataSize(type, dims))) / nodeEdgeOverhead(vectorDataSize(type, dims)) + 1);
209877
+ }
209878
+ blockSizeBytes = nodeOverhead(vectorDataSize(type, dims)) + maxNeighborsParam * (u64)nodeEdgeOverhead(vectorDataSize(type, dims));
209879
+ if( blockSizeBytes > DISKANN_MAX_BLOCK_SZ ){
209880
+ return SQLITE_ERROR;
209881
+ }
209882
+ if( vectorIdxParamsPutU64(pParams, VECTOR_BLOCK_SIZE_PARAM_ID, MAX(256, blockSizeBytes)) != 0 ){
209883
+ return SQLITE_ERROR;
209884
+ }
209844
209885
if( vectorIdxParamsGetU64(pParams, VECTOR_METRIC_TYPE_PARAM_ID) == 0 ){
209845
209886
if( vectorIdxParamsPutU64(pParams, VECTOR_METRIC_TYPE_PARAM_ID, VECTOR_METRIC_TYPE_COS) != 0 ){
209846
209887
return SQLITE_ERROR;
209847
209888
}
209848
209889
}
209849
- if( vectorIdxParamsGetU64(pParams, VECTOR_BLOCK_SIZE_PARAM_ID) == 0 ){
209850
- if( vectorIdxParamsPutU64(pParams, VECTOR_BLOCK_SIZE_PARAM_ID, VECTOR_BLOCK_SIZE_DEFAULT) != 0 ){
209851
- return SQLITE_ERROR;
209852
- }
209853
- }
209854
209890
if( vectorIdxParamsGetF64(pParams, VECTOR_PRUNING_ALPHA_PARAM_ID) == 0 ){
209855
209891
if( vectorIdxParamsPutF64(pParams, VECTOR_PRUNING_ALPHA_PARAM_ID, VECTOR_PRUNING_ALPHA_DEFAULT) != 0 ){
209856
209892
return SQLITE_ERROR;
@@ -210840,6 +210876,7 @@ int diskAnnOpenIndex(
210840
210876
DiskAnnIndex **ppIndex /* OUT: Index */
210841
210877
){
210842
210878
DiskAnnIndex *pIndex;
210879
+ u64 nBlockSize;
210843
210880
pIndex = sqlite3DbMallocRaw(db, sizeof(DiskAnnIndex));
210844
210881
if( pIndex == NULL ){
210845
210882
return SQLITE_NOMEM;
@@ -210852,9 +210889,15 @@ int diskAnnOpenIndex(
210852
210889
diskAnnCloseIndex(pIndex);
210853
210890
return SQLITE_NOMEM_BKPT;
210854
210891
}
210892
+ nBlockSize = vectorIdxParamsGetU64(pParams, VECTOR_BLOCK_SIZE_PARAM_ID);
210893
+ // preserve backward compatibility: treat block size > 128 literally, but <= 128 with shift
210894
+ if( nBlockSize <= 128 ){
210895
+ nBlockSize <<= DISKANN_BLOCK_SIZE_SHIFT;
210896
+ }
210897
+
210855
210898
pIndex->nFormatVersion = vectorIdxParamsGetU64(pParams, VECTOR_FORMAT_PARAM_ID);
210856
210899
pIndex->nDistanceFunc = vectorIdxParamsGetU64(pParams, VECTOR_METRIC_TYPE_PARAM_ID);
210857
- pIndex->nBlockSize = vectorIdxParamsGetU64(pParams, VECTOR_BLOCK_SIZE_PARAM_ID) << DISKANN_BLOCK_SIZE_SHIFT ;
210900
+ pIndex->nBlockSize = nBlockSize ;
210858
210901
pIndex->nNodeVectorType = vectorIdxParamsGetU64(pParams, VECTOR_TYPE_PARAM_ID);
210859
210902
pIndex->nVectorDims = vectorIdxParamsGetU64(pParams, VECTOR_DIM_PARAM_ID);
210860
210903
pIndex->pruningAlpha = vectorIdxParamsGetF64(pParams, VECTOR_PRUNING_ALPHA_PARAM_ID);
@@ -211810,18 +211853,19 @@ static struct VectorColumnType VECTOR_COLUMN_TYPES[] = {
211810
211853
struct VectorParamName {
211811
211854
const char *zName;
211812
211855
int tag;
211813
- int type; // 0 - enum, 1 - integer, 2 - float
211856
+ int type; // 0 - string enum, 1 - integer, 2 - float
211814
211857
const char *zValueStr;
211815
211858
u64 value;
211816
211859
};
211817
211860
211818
211861
static struct VectorParamName VECTOR_PARAM_NAMES[] = {
211819
- { "type", VECTOR_INDEX_TYPE_PARAM_ID, 0, "diskann", VECTOR_INDEX_TYPE_DISKANN },
211820
- { "metric", VECTOR_METRIC_TYPE_PARAM_ID, 0, "cosine", VECTOR_METRIC_TYPE_COS },
211821
- { "metric", VECTOR_METRIC_TYPE_PARAM_ID, 0, "l2", VECTOR_METRIC_TYPE_L2 },
211822
- { "alpha", VECTOR_PRUNING_ALPHA_PARAM_ID, 2, 0, 0 },
211823
- { "search_l", VECTOR_SEARCH_L_PARAM_ID, 1, 0, 0 },
211824
- { "insert_l", VECTOR_INSERT_L_PARAM_ID, 2, 0, 0 },
211862
+ { "type", VECTOR_INDEX_TYPE_PARAM_ID, 0, "diskann", VECTOR_INDEX_TYPE_DISKANN },
211863
+ { "metric", VECTOR_METRIC_TYPE_PARAM_ID, 0, "cosine", VECTOR_METRIC_TYPE_COS },
211864
+ { "metric", VECTOR_METRIC_TYPE_PARAM_ID, 0, "l2", VECTOR_METRIC_TYPE_L2 },
211865
+ { "alpha", VECTOR_PRUNING_ALPHA_PARAM_ID, 2, 0, 0 },
211866
+ { "search_l", VECTOR_SEARCH_L_PARAM_ID, 1, 0, 0 },
211867
+ { "insert_l", VECTOR_INSERT_L_PARAM_ID, 1, 0, 0 },
211868
+ { "max_neighbors", VECTOR_MAX_NEIGHBORS_PARAM_ID, 1, 0, 0 },
211825
211869
};
211826
211870
211827
211871
static int parseVectorIdxParam(const char *zParam, VectorIdxParams *pParams, const char **pErrMsg) {
@@ -211841,11 +211885,15 @@ static int parseVectorIdxParam(const char *zParam, VectorIdxParams *pParams, con
211841
211885
continue;
211842
211886
}
211843
211887
if( VECTOR_PARAM_NAMES[i].type == 1 ){
211844
- u64 value = sqlite3Atoi(zValue);
211888
+ int value = sqlite3Atoi(zValue);
211845
211889
if( value == 0 ){
211846
211890
*pErrMsg = "invalid representation of integer vector index parameter";
211847
211891
return -1;
211848
211892
}
211893
+ if( value < 0 ){
211894
+ *pErrMsg = "integer vector index parameter must be positive";
211895
+ return -1;
211896
+ }
211849
211897
if( vectorIdxParamsPutU64(pParams, VECTOR_PARAM_NAMES[i].tag, value) != 0 ){
211850
211898
*pErrMsg = "unable to serialize integer vector index parameter";
211851
211899
return -1;
0 commit comments