Skip to content

Commit bd62561

Browse files
committed
Added support function for l2_normalize to ivfflat
1 parent f14c217 commit bd62561

8 files changed

Lines changed: 43 additions & 32 deletions

File tree

sql/vector--0.6.2--0.7.0.sql

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,15 +318,17 @@ CREATE OPERATOR CLASS halfvec_ip_ops
318318
OPERATOR 1 <#> (halfvec, halfvec) FOR ORDER BY float_ops,
319319
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
320320
FUNCTION 3 halfvec_spherical_distance(halfvec, halfvec),
321-
FUNCTION 4 l2_norm(halfvec);
321+
FUNCTION 4 l2_norm(halfvec),
322+
FUNCTION 5 l2_normalize(halfvec);
322323

323324
CREATE OPERATOR CLASS halfvec_cosine_ops
324325
FOR TYPE halfvec USING ivfflat AS
325326
OPERATOR 1 <=> (halfvec, halfvec) FOR ORDER BY float_ops,
326327
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
327328
FUNCTION 2 l2_norm(halfvec),
328329
FUNCTION 3 halfvec_spherical_distance(halfvec, halfvec),
329-
FUNCTION 4 l2_norm(halfvec);
330+
FUNCTION 4 l2_norm(halfvec),
331+
FUNCTION 5 l2_normalize(halfvec);
330332

331333
CREATE OPERATOR CLASS halfvec_l2_ops
332334
FOR TYPE halfvec USING hnsw AS

sql/vector.sql

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -627,15 +627,17 @@ CREATE OPERATOR CLASS halfvec_ip_ops
627627
OPERATOR 1 <#> (halfvec, halfvec) FOR ORDER BY float_ops,
628628
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
629629
FUNCTION 3 halfvec_spherical_distance(halfvec, halfvec),
630-
FUNCTION 4 l2_norm(halfvec);
630+
FUNCTION 4 l2_norm(halfvec),
631+
FUNCTION 5 l2_normalize(halfvec);
631632

632633
CREATE OPERATOR CLASS halfvec_cosine_ops
633634
FOR TYPE halfvec USING ivfflat AS
634635
OPERATOR 1 <=> (halfvec, halfvec) FOR ORDER BY float_ops,
635636
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
636637
FUNCTION 2 l2_norm(halfvec),
637638
FUNCTION 3 halfvec_spherical_distance(halfvec, halfvec),
638-
FUNCTION 4 l2_norm(halfvec);
639+
FUNCTION 4 l2_norm(halfvec),
640+
FUNCTION 5 l2_normalize(halfvec);
639641

640642
CREATE OPERATOR CLASS halfvec_l2_ops
641643
FOR TYPE halfvec USING hnsw AS

src/ivfbuild.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,10 @@ AddSample(Datum *values, IvfflatBuildState * buildstate)
6060
*/
6161
if (buildstate->kmeansnormprocinfo != NULL)
6262
{
63-
if (!IvfflatNormValue(buildstate->kmeansnormprocinfo, buildstate->collation, &value, buildstate->type))
63+
if (!IvfflatCheckNorm(buildstate->kmeansnormprocinfo, buildstate->collation, value))
6464
return;
65+
66+
value = IvfflatNormValue(buildstate->normalizeprocinfo, buildstate->collation, value);
6567
}
6668

6769
if (samples->length < targsamples)
@@ -156,8 +158,10 @@ AddTupleToSort(Relation index, ItemPointer tid, Datum *values, IvfflatBuildState
156158
/* Normalize if needed */
157159
if (buildstate->normprocinfo != NULL)
158160
{
159-
if (!IvfflatNormValue(buildstate->normprocinfo, buildstate->collation, &value, buildstate->type))
161+
if (!IvfflatCheckNorm(buildstate->normprocinfo, buildstate->collation, value))
160162
return;
163+
164+
value = IvfflatNormValue(buildstate->normalizeprocinfo, buildstate->collation, value);
161165
}
162166

163167
/* Find the list that minimizes the distance */
@@ -379,6 +383,7 @@ InitBuildState(IvfflatBuildState * buildstate, Relation heap, Relation index, In
379383
buildstate->procinfo = index_getprocinfo(index, 1, IVFFLAT_DISTANCE_PROC);
380384
buildstate->normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORM_PROC);
381385
buildstate->kmeansnormprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_KMEANS_NORM_PROC);
386+
buildstate->normalizeprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORMALIZE_PROC);
382387
buildstate->collation = index->rd_indcollation[0];
383388

384389
/* Require more than one dimension for spherical k-means */

src/ivfflat.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ ivfflathandler(PG_FUNCTION_ARGS)
188188
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
189189

190190
amroutine->amstrategies = 0;
191-
amroutine->amsupport = 4;
191+
amroutine->amsupport = 5;
192192
#if PG_VERSION_NUM >= 130000
193193
amroutine->amoptsprocnum = 0;
194194
#endif

src/ivfflat.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#define IVFFLAT_NORM_PROC 2
2929
#define IVFFLAT_KMEANS_DISTANCE_PROC 3
3030
#define IVFFLAT_KMEANS_NORM_PROC 4
31+
#define IVFFLAT_NORMALIZE_PROC 5
3132

3233
#define IVFFLAT_VERSION 1
3334
#define IVFFLAT_MAGIC_NUMBER 0x14FF1A7
@@ -175,6 +176,7 @@ typedef struct IvfflatBuildState
175176
FmgrInfo *procinfo;
176177
FmgrInfo *normprocinfo;
177178
FmgrInfo *kmeansnormprocinfo;
179+
FmgrInfo *normalizeprocinfo;
178180
Oid collation;
179181

180182
/* Variables */
@@ -255,6 +257,7 @@ typedef struct IvfflatScanOpaqueData
255257
/* Support functions */
256258
FmgrInfo *procinfo;
257259
FmgrInfo *normprocinfo;
260+
FmgrInfo *normalizeprocinfo;
258261
Oid collation;
259262
Datum (*distfunc) (FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2);
260263

@@ -276,7 +279,8 @@ void VectorArrayFree(VectorArray arr);
276279
void IvfflatKmeans(Relation index, VectorArray samples, VectorArray centers, IvfflatType type);
277280
FmgrInfo *IvfflatOptionalProcInfo(Relation index, uint16 procnum);
278281
IvfflatType IvfflatGetType(Relation index);
279-
bool IvfflatNormValue(FmgrInfo *procinfo, Oid collation, Datum *value, IvfflatType type);
282+
Datum IvfflatNormValue(FmgrInfo *procinfo, Oid collation, Datum value);
283+
bool IvfflatCheckNorm(FmgrInfo *procinfo, Oid collation, Datum value);
280284
int IvfflatGetLists(Relation index);
281285
void IvfflatGetMetaPageInfo(Relation index, int *lists, int *dimensions);
282286
void IvfflatUpdateList(Relation index, ListInfo listInfo, BlockNumber insertPage, BlockNumber originalInsertPage, BlockNumber startPage, ForkNumber forkNum);

src/ivfinsert.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,12 @@ InsertTuple(Relation index, Datum *values, bool *isnull, ItemPointer heap_tid, R
8585
normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORM_PROC);
8686
if (normprocinfo != NULL)
8787
{
88-
if (!IvfflatNormValue(normprocinfo, index->rd_indcollation[0], &value, IvfflatGetType(index)))
88+
Oid collation = index->rd_indcollation[0];
89+
90+
if (!IvfflatCheckNorm(normprocinfo, collation, value))
8991
return;
92+
93+
value = IvfflatNormValue(IvfflatOptionalProcInfo(index, IVFFLAT_NORMALIZE_PROC), collation, value);
9094
}
9195

9296
/* Find the insert page - sets the page and list info */

src/ivfscan.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,9 @@ GetScanValue(IndexScanDesc scan)
209209
Assert(!VARATT_IS_COMPRESSED(DatumGetPointer(value)));
210210
Assert(!VARATT_IS_EXTENDED(DatumGetPointer(value)));
211211

212-
/* Fine if normalization fails */
212+
/* Check normprocinfo since normalizeprocinfo not set for vector */
213213
if (so->normprocinfo != NULL)
214-
IvfflatNormValue(so->normprocinfo, so->collation, &value, IvfflatGetType(scan->indexRelation));
214+
value = IvfflatNormValue(so->normalizeprocinfo, so->collation, value);
215215
}
216216

217217
return value;
@@ -249,6 +249,7 @@ ivfflatbeginscan(Relation index, int nkeys, int norderbys)
249249
/* Set support functions */
250250
so->procinfo = index_getprocinfo(index, 1, IVFFLAT_DISTANCE_PROC);
251251
so->normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORM_PROC);
252+
so->normalizeprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORMALIZE_PROC);
252253
so->collation = index->rd_indcollation[0];
253254

254255
/* Create tuple description for sorting */

src/ivfutils.c

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -99,31 +99,24 @@ IvfflatGetType(Relation index)
9999
}
100100

101101
/*
102-
* Divide by the norm
103-
*
104-
* Returns false if value should not be indexed
105-
*
106-
* The caller needs to free the pointer stored in value
107-
* if it's different than the original value
102+
* Normalize value
108103
*/
109-
bool
110-
IvfflatNormValue(FmgrInfo *procinfo, Oid collation, Datum *value, IvfflatType type)
104+
Datum
105+
IvfflatNormValue(FmgrInfo *procinfo, Oid collation, Datum value)
111106
{
112-
double norm = DatumGetFloat8(FunctionCall1Coll(procinfo, collation, *value));
107+
if (procinfo == NULL)
108+
return DirectFunctionCall1(l2_normalize, value);
113109

114-
if (norm > 0)
115-
{
116-
if (type == IVFFLAT_TYPE_VECTOR)
117-
*value = DirectFunctionCall1(l2_normalize, *value);
118-
else if (type == IVFFLAT_TYPE_HALFVEC)
119-
*value = DirectFunctionCall1(halfvec_l2_normalize, *value);
120-
else
121-
elog(ERROR, "Unsupported type");
122-
123-
return true;
124-
}
110+
return FunctionCall1Coll(procinfo, collation, value);
111+
}
125112

126-
return false;
113+
/*
114+
* Check if non-zero norm
115+
*/
116+
bool
117+
IvfflatCheckNorm(FmgrInfo *procinfo, Oid collation, Datum value)
118+
{
119+
return DatumGetFloat8(FunctionCall1Coll(procinfo, collation, value)) > 0;
127120
}
128121

129122
/*

0 commit comments

Comments
 (0)