mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-22 03:57:34 +08:00
Compare commits
7 Commits
v0.8.5
...
normalize_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5bb59d9f6 | ||
|
|
dd609f200b | ||
|
|
9514c152bc | ||
|
|
b391e40765 | ||
|
|
0054a9c40a | ||
|
|
9ed7e63fb7 | ||
|
|
47e361a93d |
@@ -3,6 +3,7 @@
|
|||||||
- Added HNSW index type
|
- Added HNSW index type
|
||||||
- Added support for parallel index builds
|
- Added support for parallel index builds
|
||||||
- Added `l1_distance` function
|
- Added `l1_distance` function
|
||||||
|
- Added `normalize_l2` function
|
||||||
- Added element-wise multiplication for vectors
|
- Added element-wise multiplication for vectors
|
||||||
- Added `sum` aggregate
|
- Added `sum` aggregate
|
||||||
- Improved performance of distance functions
|
- Improved performance of distance functions
|
||||||
|
|||||||
@@ -392,6 +392,7 @@ cosine_distance(vector, vector) → double precision | cosine distance
|
|||||||
inner_product(vector, vector) → double precision | inner product
|
inner_product(vector, vector) → double precision | inner product
|
||||||
l2_distance(vector, vector) → double precision | Euclidean distance
|
l2_distance(vector, vector) → double precision | Euclidean distance
|
||||||
l1_distance(vector, vector) → double precision | taxicab distance [unreleased]
|
l1_distance(vector, vector) → double precision | taxicab distance [unreleased]
|
||||||
|
normalize_l2(vector) → vector | normalize with Euclidean norm [unreleased]
|
||||||
vector_dims(vector) → integer | number of dimensions
|
vector_dims(vector) → integer | number of dimensions
|
||||||
vector_norm(vector) → double precision | Euclidean norm
|
vector_norm(vector) → double precision | Euclidean norm
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
CREATE FUNCTION l1_distance(vector, vector) RETURNS float8
|
CREATE FUNCTION l1_distance(vector, vector) RETURNS float8
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE FUNCTION normalize_l2(vector) RETURNS vector
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
CREATE FUNCTION vector_mul(vector, vector) RETURNS vector
|
CREATE FUNCTION vector_mul(vector, vector) RETURNS vector
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ CREATE FUNCTION vector_dims(vector) RETURNS integer
|
|||||||
CREATE FUNCTION vector_norm(vector) RETURNS float8
|
CREATE FUNCTION vector_norm(vector) RETURNS float8
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE FUNCTION normalize_l2(vector) RETURNS vector
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
CREATE FUNCTION vector_add(vector, vector) RETURNS vector
|
CREATE FUNCTION vector_add(vector, vector) RETURNS vector
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
@@ -265,15 +268,15 @@ CREATE OPERATOR CLASS vector_ip_ops
|
|||||||
OPERATOR 1 <#> (vector, vector) FOR ORDER BY float_ops,
|
OPERATOR 1 <#> (vector, vector) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 vector_negative_inner_product(vector, vector),
|
FUNCTION 1 vector_negative_inner_product(vector, vector),
|
||||||
FUNCTION 3 vector_spherical_distance(vector, vector),
|
FUNCTION 3 vector_spherical_distance(vector, vector),
|
||||||
FUNCTION 4 vector_norm(vector);
|
FUNCTION 6 normalize_l2(vector);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS vector_cosine_ops
|
CREATE OPERATOR CLASS vector_cosine_ops
|
||||||
FOR TYPE vector USING ivfflat AS
|
FOR TYPE vector USING ivfflat AS
|
||||||
OPERATOR 1 <=> (vector, vector) FOR ORDER BY float_ops,
|
OPERATOR 1 <=> (vector, vector) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 vector_negative_inner_product(vector, vector),
|
FUNCTION 1 vector_negative_inner_product(vector, vector),
|
||||||
FUNCTION 2 vector_norm(vector),
|
|
||||||
FUNCTION 3 vector_spherical_distance(vector, vector),
|
FUNCTION 3 vector_spherical_distance(vector, vector),
|
||||||
FUNCTION 4 vector_norm(vector);
|
FUNCTION 5 normalize_l2(vector),
|
||||||
|
FUNCTION 6 normalize_l2(vector);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS vector_l2_ops
|
CREATE OPERATOR CLASS vector_l2_ops
|
||||||
FOR TYPE vector USING hnsw AS
|
FOR TYPE vector USING hnsw AS
|
||||||
@@ -289,4 +292,4 @@ CREATE OPERATOR CLASS vector_cosine_ops
|
|||||||
FOR TYPE vector USING hnsw AS
|
FOR TYPE vector USING hnsw AS
|
||||||
OPERATOR 1 <=> (vector, vector) FOR ORDER BY float_ops,
|
OPERATOR 1 <=> (vector, vector) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 vector_negative_inner_product(vector, vector),
|
FUNCTION 1 vector_negative_inner_product(vector, vector),
|
||||||
FUNCTION 2 vector_norm(vector);
|
FUNCTION 3 normalize_l2(vector);
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ hnswhandler(PG_FUNCTION_ARGS)
|
|||||||
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
|
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
|
||||||
|
|
||||||
amroutine->amstrategies = 0;
|
amroutine->amstrategies = 0;
|
||||||
amroutine->amsupport = 2;
|
amroutine->amsupport = 3;
|
||||||
#if PG_VERSION_NUM >= 130000
|
#if PG_VERSION_NUM >= 130000
|
||||||
amroutine->amoptsprocnum = 0;
|
amroutine->amoptsprocnum = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
/* Support functions */
|
/* Support functions */
|
||||||
#define HNSW_DISTANCE_PROC 1
|
#define HNSW_DISTANCE_PROC 1
|
||||||
#define HNSW_NORM_PROC 2
|
#define HNSW_NORM_PROC 2
|
||||||
|
#define HNSW_NORMALIZE_PROC 3
|
||||||
|
|
||||||
#define HNSW_VERSION 1
|
#define HNSW_VERSION 1
|
||||||
#define HNSW_MAGIC_NUMBER 0xA953A953
|
#define HNSW_MAGIC_NUMBER 0xA953A953
|
||||||
@@ -147,6 +148,7 @@ typedef struct HnswBuildState
|
|||||||
/* Support functions */
|
/* Support functions */
|
||||||
FmgrInfo *procinfo;
|
FmgrInfo *procinfo;
|
||||||
FmgrInfo *normprocinfo;
|
FmgrInfo *normprocinfo;
|
||||||
|
FmgrInfo *normalizeprocinfo;
|
||||||
Oid collation;
|
Oid collation;
|
||||||
|
|
||||||
/* Variables */
|
/* Variables */
|
||||||
@@ -220,6 +222,7 @@ typedef struct HnswScanOpaqueData
|
|||||||
/* Support functions */
|
/* Support functions */
|
||||||
FmgrInfo *procinfo;
|
FmgrInfo *procinfo;
|
||||||
FmgrInfo *normprocinfo;
|
FmgrInfo *normprocinfo;
|
||||||
|
FmgrInfo *normalizeprocinfo;
|
||||||
Oid collation;
|
Oid collation;
|
||||||
} HnswScanOpaqueData;
|
} HnswScanOpaqueData;
|
||||||
|
|
||||||
@@ -255,7 +258,7 @@ typedef struct HnswVacuumState
|
|||||||
int HnswGetM(Relation index);
|
int HnswGetM(Relation index);
|
||||||
int HnswGetEfConstruction(Relation index);
|
int HnswGetEfConstruction(Relation index);
|
||||||
FmgrInfo *HnswOptionalProcInfo(Relation rel, uint16 procnum);
|
FmgrInfo *HnswOptionalProcInfo(Relation rel, uint16 procnum);
|
||||||
bool HnswNormValue(FmgrInfo *procinfo, Oid collation, Datum *value, Vector * result);
|
void HnswNormValue(FmgrInfo *procinfo, FmgrInfo *normalizeprocinfo, Oid collation, Datum *value, Vector * result);
|
||||||
void HnswCommitBuffer(Buffer buf, GenericXLogState *state);
|
void HnswCommitBuffer(Buffer buf, GenericXLogState *state);
|
||||||
Buffer HnswNewBuffer(Relation index, ForkNumber forkNum);
|
Buffer HnswNewBuffer(Relation index, ForkNumber forkNum);
|
||||||
void HnswInitPage(Buffer buf, Page page);
|
void HnswInitPage(Buffer buf, Page page);
|
||||||
|
|||||||
@@ -278,11 +278,7 @@ InsertTuple(Relation index, Datum *values, HnswElement element, HnswBuildState *
|
|||||||
Datum value = PointerGetDatum(PG_DETOAST_DATUM(values[0]));
|
Datum value = PointerGetDatum(PG_DETOAST_DATUM(values[0]));
|
||||||
|
|
||||||
/* Normalize if needed */
|
/* Normalize if needed */
|
||||||
if (buildstate->normprocinfo != NULL)
|
HnswNormValue(buildstate->normprocinfo, buildstate->normalizeprocinfo, collation, &value, buildstate->normvec);
|
||||||
{
|
|
||||||
if (!HnswNormValue(buildstate->normprocinfo, collation, &value, buildstate->normvec))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy value to element so accessible outside of memory context */
|
/* Copy value to element so accessible outside of memory context */
|
||||||
memcpy(element->vec, DatumGetVector(value), VECTOR_SIZE(buildstate->dimensions));
|
memcpy(element->vec, DatumGetVector(value), VECTOR_SIZE(buildstate->dimensions));
|
||||||
@@ -413,6 +409,7 @@ InitBuildState(HnswBuildState * buildstate, Relation heap, Relation index, Index
|
|||||||
/* Get support functions */
|
/* Get support functions */
|
||||||
buildstate->procinfo = index_getprocinfo(index, 1, HNSW_DISTANCE_PROC);
|
buildstate->procinfo = index_getprocinfo(index, 1, HNSW_DISTANCE_PROC);
|
||||||
buildstate->normprocinfo = HnswOptionalProcInfo(index, HNSW_NORM_PROC);
|
buildstate->normprocinfo = HnswOptionalProcInfo(index, HNSW_NORM_PROC);
|
||||||
|
buildstate->normalizeprocinfo = HnswOptionalProcInfo(index, HNSW_NORMALIZE_PROC);
|
||||||
buildstate->collation = index->rd_indcollation[0];
|
buildstate->collation = index->rd_indcollation[0];
|
||||||
|
|
||||||
buildstate->elements = NIL;
|
buildstate->elements = NIL;
|
||||||
|
|||||||
@@ -417,6 +417,7 @@ HnswInsertTuple(Relation index, Datum *values, bool *isnull, ItemPointer heap_ti
|
|||||||
{
|
{
|
||||||
Datum value;
|
Datum value;
|
||||||
FmgrInfo *normprocinfo;
|
FmgrInfo *normprocinfo;
|
||||||
|
FmgrInfo *normalizeprocinfo;
|
||||||
HnswElement entryPoint;
|
HnswElement entryPoint;
|
||||||
HnswElement element;
|
HnswElement element;
|
||||||
int m = HnswGetM(index);
|
int m = HnswGetM(index);
|
||||||
@@ -432,11 +433,8 @@ HnswInsertTuple(Relation index, Datum *values, bool *isnull, ItemPointer heap_ti
|
|||||||
|
|
||||||
/* Normalize if needed */
|
/* Normalize if needed */
|
||||||
normprocinfo = HnswOptionalProcInfo(index, HNSW_NORM_PROC);
|
normprocinfo = HnswOptionalProcInfo(index, HNSW_NORM_PROC);
|
||||||
if (normprocinfo != NULL)
|
normalizeprocinfo = HnswOptionalProcInfo(index, HNSW_NORMALIZE_PROC);
|
||||||
{
|
HnswNormValue(normprocinfo, normalizeprocinfo, collation, &value, NULL);
|
||||||
if (!HnswNormValue(normprocinfo, collation, &value, NULL))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create an element */
|
/* Create an element */
|
||||||
element = HnswInitElement(heap_tid, m, ml, HnswGetMaxLevel(m));
|
element = HnswInitElement(heap_tid, m, ml, HnswGetMaxLevel(m));
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ hnswbeginscan(Relation index, int nkeys, int norderbys)
|
|||||||
/* Set support functions */
|
/* Set support functions */
|
||||||
so->procinfo = index_getprocinfo(index, 1, HNSW_DISTANCE_PROC);
|
so->procinfo = index_getprocinfo(index, 1, HNSW_DISTANCE_PROC);
|
||||||
so->normprocinfo = HnswOptionalProcInfo(index, HNSW_NORM_PROC);
|
so->normprocinfo = HnswOptionalProcInfo(index, HNSW_NORM_PROC);
|
||||||
|
so->normalizeprocinfo = HnswOptionalProcInfo(index, HNSW_NORMALIZE_PROC);
|
||||||
so->collation = index->rd_indcollation[0];
|
so->collation = index->rd_indcollation[0];
|
||||||
|
|
||||||
scan->opaque = so;
|
scan->opaque = so;
|
||||||
@@ -140,8 +141,7 @@ hnswgettuple(IndexScanDesc scan, ScanDirection dir)
|
|||||||
Assert(!VARATT_IS_EXTENDED(DatumGetPointer(value)));
|
Assert(!VARATT_IS_EXTENDED(DatumGetPointer(value)));
|
||||||
|
|
||||||
/* Fine if normalization fails */
|
/* Fine if normalization fails */
|
||||||
if (so->normprocinfo != NULL)
|
HnswNormValue(so->normprocinfo, so->normalizeprocinfo, so->collation, &value, NULL);
|
||||||
HnswNormValue(so->normprocinfo, so->collation, &value, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GetScanItems(scan, value);
|
GetScanItems(scan, value);
|
||||||
|
|||||||
@@ -47,17 +47,26 @@ HnswOptionalProcInfo(Relation rel, uint16 procnum)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Divide by the norm
|
* Normalize a vector
|
||||||
*
|
|
||||||
* Returns false if value should not be indexed
|
|
||||||
*
|
*
|
||||||
* The caller needs to free the pointer stored in value
|
* The caller needs to free the pointer stored in value
|
||||||
* if it's different than the original value
|
* if it's different than the original value
|
||||||
*/
|
*/
|
||||||
bool
|
void
|
||||||
HnswNormValue(FmgrInfo *procinfo, Oid collation, Datum *value, Vector * result)
|
HnswNormValue(FmgrInfo *procinfo, FmgrInfo *normalizeprocinfo, Oid collation, Datum *value, Vector * result)
|
||||||
{
|
{
|
||||||
double norm = DatumGetFloat8(FunctionCall1Coll(procinfo, collation, *value));
|
double norm;
|
||||||
|
|
||||||
|
if (normalizeprocinfo != NULL)
|
||||||
|
{
|
||||||
|
*value = FunctionCall1Coll(normalizeprocinfo, collation, *value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (procinfo == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
norm = DatumGetFloat8(FunctionCall1Coll(procinfo, collation, *value));
|
||||||
|
|
||||||
if (norm > 0)
|
if (norm > 0)
|
||||||
{
|
{
|
||||||
@@ -70,11 +79,7 @@ HnswNormValue(FmgrInfo *procinfo, Oid collation, Datum *value, Vector * result)
|
|||||||
result->x[i] = v->x[i] / norm;
|
result->x[i] = v->x[i] / norm;
|
||||||
|
|
||||||
*value = PointerGetDatum(result);
|
*value = PointerGetDatum(result);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -75,11 +75,7 @@ AddSample(Datum *values, IvfflatBuildState * buildstate)
|
|||||||
* Normalize with KMEANS_NORM_PROC since spherical distance function
|
* Normalize with KMEANS_NORM_PROC since spherical distance function
|
||||||
* expects unit vectors
|
* expects unit vectors
|
||||||
*/
|
*/
|
||||||
if (buildstate->kmeansnormprocinfo != NULL)
|
IvfflatNormValue(buildstate->kmeansnormprocinfo, buildstate->kmeansnormalizeprocinfo, buildstate->collation, &value, buildstate->normvec);
|
||||||
{
|
|
||||||
if (!IvfflatNormValue(buildstate->kmeansnormprocinfo, buildstate->collation, &value, buildstate->normvec))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (samples->length < targsamples)
|
if (samples->length < targsamples)
|
||||||
{
|
{
|
||||||
@@ -176,11 +172,7 @@ AddTupleToSort(Relation index, ItemPointer tid, Datum *values, IvfflatBuildState
|
|||||||
Datum value = PointerGetDatum(PG_DETOAST_DATUM(values[0]));
|
Datum value = PointerGetDatum(PG_DETOAST_DATUM(values[0]));
|
||||||
|
|
||||||
/* Normalize if needed */
|
/* Normalize if needed */
|
||||||
if (buildstate->normprocinfo != NULL)
|
IvfflatNormValue(buildstate->normprocinfo, buildstate->normalizeprocinfo, buildstate->collation, &value, buildstate->normvec);
|
||||||
{
|
|
||||||
if (!IvfflatNormValue(buildstate->normprocinfo, buildstate->collation, &value, buildstate->normvec))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the list that minimizes the distance */
|
/* Find the list that minimizes the distance */
|
||||||
for (int i = 0; i < centers->length; i++)
|
for (int i = 0; i < centers->length; i++)
|
||||||
@@ -368,6 +360,8 @@ InitBuildState(IvfflatBuildState * buildstate, Relation heap, Relation index, In
|
|||||||
buildstate->procinfo = index_getprocinfo(index, 1, IVFFLAT_DISTANCE_PROC);
|
buildstate->procinfo = index_getprocinfo(index, 1, IVFFLAT_DISTANCE_PROC);
|
||||||
buildstate->normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORM_PROC);
|
buildstate->normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORM_PROC);
|
||||||
buildstate->kmeansnormprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_KMEANS_NORM_PROC);
|
buildstate->kmeansnormprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_KMEANS_NORM_PROC);
|
||||||
|
buildstate->normalizeprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORMALIZE_PROC);
|
||||||
|
buildstate->kmeansnormalizeprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_KMEANS_NORMALIZE_PROC);
|
||||||
buildstate->collation = index->rd_indcollation[0];
|
buildstate->collation = index->rd_indcollation[0];
|
||||||
|
|
||||||
/* Require more than one dimension for spherical k-means */
|
/* Require more than one dimension for spherical k-means */
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ ivfflathandler(PG_FUNCTION_ARGS)
|
|||||||
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
|
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
|
||||||
|
|
||||||
amroutine->amstrategies = 0;
|
amroutine->amstrategies = 0;
|
||||||
amroutine->amsupport = 4;
|
amroutine->amsupport = 6;
|
||||||
#if PG_VERSION_NUM >= 130000
|
#if PG_VERSION_NUM >= 130000
|
||||||
amroutine->amoptsprocnum = 0;
|
amroutine->amoptsprocnum = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -31,6 +31,8 @@
|
|||||||
#define IVFFLAT_NORM_PROC 2
|
#define IVFFLAT_NORM_PROC 2
|
||||||
#define IVFFLAT_KMEANS_DISTANCE_PROC 3
|
#define IVFFLAT_KMEANS_DISTANCE_PROC 3
|
||||||
#define IVFFLAT_KMEANS_NORM_PROC 4
|
#define IVFFLAT_KMEANS_NORM_PROC 4
|
||||||
|
#define IVFFLAT_NORMALIZE_PROC 5
|
||||||
|
#define IVFFLAT_KMEANS_NORMALIZE_PROC 6
|
||||||
|
|
||||||
#define IVFFLAT_VERSION 1
|
#define IVFFLAT_VERSION 1
|
||||||
#define IVFFLAT_MAGIC_NUMBER 0x14FF1A7
|
#define IVFFLAT_MAGIC_NUMBER 0x14FF1A7
|
||||||
@@ -172,6 +174,8 @@ typedef struct IvfflatBuildState
|
|||||||
FmgrInfo *procinfo;
|
FmgrInfo *procinfo;
|
||||||
FmgrInfo *normprocinfo;
|
FmgrInfo *normprocinfo;
|
||||||
FmgrInfo *kmeansnormprocinfo;
|
FmgrInfo *kmeansnormprocinfo;
|
||||||
|
FmgrInfo *normalizeprocinfo;
|
||||||
|
FmgrInfo *kmeansnormalizeprocinfo;
|
||||||
Oid collation;
|
Oid collation;
|
||||||
|
|
||||||
/* Variables */
|
/* Variables */
|
||||||
@@ -253,6 +257,7 @@ typedef struct IvfflatScanOpaqueData
|
|||||||
/* Support functions */
|
/* Support functions */
|
||||||
FmgrInfo *procinfo;
|
FmgrInfo *procinfo;
|
||||||
FmgrInfo *normprocinfo;
|
FmgrInfo *normprocinfo;
|
||||||
|
FmgrInfo *normalizeprocinfo;
|
||||||
Oid collation;
|
Oid collation;
|
||||||
|
|
||||||
/* Lists */
|
/* Lists */
|
||||||
@@ -273,7 +278,7 @@ void VectorArrayFree(VectorArray arr);
|
|||||||
void PrintVectorArray(char *msg, VectorArray arr);
|
void PrintVectorArray(char *msg, VectorArray arr);
|
||||||
void IvfflatKmeans(Relation index, VectorArray samples, VectorArray centers);
|
void IvfflatKmeans(Relation index, VectorArray samples, VectorArray centers);
|
||||||
FmgrInfo *IvfflatOptionalProcInfo(Relation rel, uint16 procnum);
|
FmgrInfo *IvfflatOptionalProcInfo(Relation rel, uint16 procnum);
|
||||||
bool IvfflatNormValue(FmgrInfo *procinfo, Oid collation, Datum *value, Vector * result);
|
void IvfflatNormValue(FmgrInfo *procinfo, FmgrInfo *normalizeprocinfo, Oid collation, Datum *value, Vector * result);
|
||||||
int IvfflatGetLists(Relation index);
|
int IvfflatGetLists(Relation index);
|
||||||
void IvfflatUpdateList(Relation index, ListInfo listInfo, BlockNumber insertPage, BlockNumber originalInsertPage, BlockNumber startPage, ForkNumber forkNum);
|
void IvfflatUpdateList(Relation index, ListInfo listInfo, BlockNumber insertPage, BlockNumber originalInsertPage, BlockNumber startPage, ForkNumber forkNum);
|
||||||
void IvfflatCommitBuffer(Buffer buf, GenericXLogState *state);
|
void IvfflatCommitBuffer(Buffer buf, GenericXLogState *state);
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ InsertTuple(Relation rel, Datum *values, bool *isnull, ItemPointer heap_tid, Rel
|
|||||||
IndexTuple itup;
|
IndexTuple itup;
|
||||||
Datum value;
|
Datum value;
|
||||||
FmgrInfo *normprocinfo;
|
FmgrInfo *normprocinfo;
|
||||||
|
FmgrInfo *normalizeprocinfo;
|
||||||
Buffer buf;
|
Buffer buf;
|
||||||
Page page;
|
Page page;
|
||||||
GenericXLogState *state;
|
GenericXLogState *state;
|
||||||
@@ -81,11 +82,8 @@ InsertTuple(Relation rel, Datum *values, bool *isnull, ItemPointer heap_tid, Rel
|
|||||||
|
|
||||||
/* Normalize if needed */
|
/* Normalize if needed */
|
||||||
normprocinfo = IvfflatOptionalProcInfo(rel, IVFFLAT_NORM_PROC);
|
normprocinfo = IvfflatOptionalProcInfo(rel, IVFFLAT_NORM_PROC);
|
||||||
if (normprocinfo != NULL)
|
normalizeprocinfo = IvfflatOptionalProcInfo(rel, IVFFLAT_NORMALIZE_PROC);
|
||||||
{
|
IvfflatNormValue(normprocinfo, normalizeprocinfo, rel->rd_indcollation[0], &value, NULL);
|
||||||
if (!IvfflatNormValue(normprocinfo, rel->rd_indcollation[0], &value, NULL))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the insert page - sets the page and list info */
|
/* Find the insert page - sets the page and list info */
|
||||||
FindInsertPage(rel, values, &insertPage, &listInfo);
|
FindInsertPage(rel, values, &insertPage, &listInfo);
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ ivfflatbeginscan(Relation index, int nkeys, int norderbys)
|
|||||||
/* Set support functions */
|
/* Set support functions */
|
||||||
so->procinfo = index_getprocinfo(index, 1, IVFFLAT_DISTANCE_PROC);
|
so->procinfo = index_getprocinfo(index, 1, IVFFLAT_DISTANCE_PROC);
|
||||||
so->normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORM_PROC);
|
so->normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORM_PROC);
|
||||||
|
so->normalizeprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORMALIZE_PROC);
|
||||||
so->collation = index->rd_indcollation[0];
|
so->collation = index->rd_indcollation[0];
|
||||||
|
|
||||||
/* Create tuple description for sorting */
|
/* Create tuple description for sorting */
|
||||||
@@ -319,8 +320,7 @@ ivfflatgettuple(IndexScanDesc scan, ScanDirection dir)
|
|||||||
Assert(!VARATT_IS_EXTENDED(DatumGetPointer(value)));
|
Assert(!VARATT_IS_EXTENDED(DatumGetPointer(value)));
|
||||||
|
|
||||||
/* Fine if normalization fails */
|
/* Fine if normalization fails */
|
||||||
if (so->normprocinfo != NULL)
|
IvfflatNormValue(so->normprocinfo, so->normalizeprocinfo, so->collation, &value, NULL);
|
||||||
IvfflatNormValue(so->normprocinfo, so->collation, &value, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IvfflatBench("GetScanLists", GetScanLists(scan, value));
|
IvfflatBench("GetScanLists", GetScanLists(scan, value));
|
||||||
|
|||||||
@@ -66,17 +66,26 @@ IvfflatOptionalProcInfo(Relation rel, uint16 procnum)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Divide by the norm
|
* Normalize a vector
|
||||||
*
|
|
||||||
* Returns false if value should not be indexed
|
|
||||||
*
|
*
|
||||||
* The caller needs to free the pointer stored in value
|
* The caller needs to free the pointer stored in value
|
||||||
* if it's different than the original value
|
* if it's different than the original value
|
||||||
*/
|
*/
|
||||||
bool
|
void
|
||||||
IvfflatNormValue(FmgrInfo *procinfo, Oid collation, Datum *value, Vector * result)
|
IvfflatNormValue(FmgrInfo *procinfo, FmgrInfo *normalizeprocinfo, Oid collation, Datum *value, Vector * result)
|
||||||
{
|
{
|
||||||
double norm = DatumGetFloat8(FunctionCall1Coll(procinfo, collation, *value));
|
double norm;
|
||||||
|
|
||||||
|
if (normalizeprocinfo != NULL)
|
||||||
|
{
|
||||||
|
*value = FunctionCall1Coll(normalizeprocinfo, collation, *value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (procinfo == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
norm = DatumGetFloat8(FunctionCall1Coll(procinfo, collation, *value));
|
||||||
|
|
||||||
if (norm > 0)
|
if (norm > 0)
|
||||||
{
|
{
|
||||||
@@ -89,11 +98,7 @@ IvfflatNormValue(FmgrInfo *procinfo, Oid collation, Datum *value, Vector * resul
|
|||||||
result->x[i] = v->x[i] / norm;
|
result->x[i] = v->x[i] / norm;
|
||||||
|
|
||||||
*value = PointerGetDatum(result);
|
*value = PointerGetDatum(result);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
46
src/vector.c
46
src/vector.c
@@ -745,6 +745,52 @@ vector_norm(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_FLOAT8(sqrt((double) norm));
|
PG_RETURN_FLOAT8(sqrt((double) norm));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Normalize a vector with the L2 norm
|
||||||
|
*/
|
||||||
|
PGDLLEXPORT PG_FUNCTION_INFO_V1(normalize_l2);
|
||||||
|
Datum
|
||||||
|
normalize_l2(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Vector *a = PG_GETARG_VECTOR_P(0);
|
||||||
|
float *ax = a->x;
|
||||||
|
double norm = 0.0;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
/* Fix precision on Windows */
|
||||||
|
double normf;
|
||||||
|
#else
|
||||||
|
float normf;
|
||||||
|
#endif
|
||||||
|
Vector *result;
|
||||||
|
float *rx;
|
||||||
|
|
||||||
|
result = InitVector(a->dim);
|
||||||
|
rx = result->x;
|
||||||
|
|
||||||
|
/* Auto-vectorized */
|
||||||
|
for (int i = 0; i < a->dim; i++)
|
||||||
|
norm += (double) ax[i] * (double) ax[i];
|
||||||
|
|
||||||
|
norm = sqrt(norm);
|
||||||
|
normf = norm;
|
||||||
|
|
||||||
|
if (normf > 0)
|
||||||
|
{
|
||||||
|
/* Auto-vectorized */
|
||||||
|
for (int i = 0, imax = a->dim; i < imax; i++)
|
||||||
|
rx[i] = ax[i] / normf;
|
||||||
|
|
||||||
|
/* Check for overflow */
|
||||||
|
for (int i = 0, imax = a->dim; i < imax; i++)
|
||||||
|
{
|
||||||
|
if (isinf(rx[i]))
|
||||||
|
float_overflow_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PG_RETURN_POINTER(result);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add vectors
|
* Add vectors
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -48,6 +48,36 @@ SELECT vector_norm('[0,1]');
|
|||||||
1
|
1
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT normalize_l2('[3,4]');
|
||||||
|
normalize_l2
|
||||||
|
--------------
|
||||||
|
[0.6,0.8]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT normalize_l2('[3,0]');
|
||||||
|
normalize_l2
|
||||||
|
--------------
|
||||||
|
[1,0]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT normalize_l2('[0,0.1]');
|
||||||
|
normalize_l2
|
||||||
|
--------------
|
||||||
|
[0,1]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT normalize_l2('[0,0]');
|
||||||
|
normalize_l2
|
||||||
|
--------------
|
||||||
|
[0,0]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT normalize_l2('[3e38]');
|
||||||
|
normalize_l2
|
||||||
|
--------------
|
||||||
|
[1]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT l2_distance('[0,0]', '[3,4]');
|
SELECT l2_distance('[0,0]', '[3,4]');
|
||||||
l2_distance
|
l2_distance
|
||||||
-------------
|
-------------
|
||||||
|
|||||||
@@ -9,18 +9,19 @@ SELECT * FROM t ORDER BY val <=> '[3,3,3]';
|
|||||||
[1,1,1]
|
[1,1,1]
|
||||||
[1,2,3]
|
[1,2,3]
|
||||||
[1,2,4]
|
[1,2,4]
|
||||||
(3 rows)
|
[0,0,0]
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <=> '[0,0,0]') t2;
|
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <=> '[0,0,0]') t2;
|
||||||
count
|
count
|
||||||
-------
|
-------
|
||||||
3
|
4
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <=> (SELECT NULL::vector)) t2;
|
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <=> (SELECT NULL::vector)) t2;
|
||||||
count
|
count
|
||||||
-------
|
-------
|
||||||
3
|
4
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
DROP TABLE t;
|
DROP TABLE t;
|
||||||
|
|||||||
@@ -9,18 +9,19 @@ SELECT * FROM t ORDER BY val <=> '[3,3,3]';
|
|||||||
[1,1,1]
|
[1,1,1]
|
||||||
[1,2,3]
|
[1,2,3]
|
||||||
[1,2,4]
|
[1,2,4]
|
||||||
(3 rows)
|
[0,0,0]
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <=> '[0,0,0]') t2;
|
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <=> '[0,0,0]') t2;
|
||||||
count
|
count
|
||||||
-------
|
-------
|
||||||
3
|
4
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <=> (SELECT NULL::vector)) t2;
|
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <=> (SELECT NULL::vector)) t2;
|
||||||
count
|
count
|
||||||
-------
|
-------
|
||||||
3
|
4
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
DROP TABLE t;
|
DROP TABLE t;
|
||||||
|
|||||||
@@ -12,6 +12,12 @@ SELECT round(vector_norm('[1,1]')::numeric, 5);
|
|||||||
SELECT vector_norm('[3,4]');
|
SELECT vector_norm('[3,4]');
|
||||||
SELECT vector_norm('[0,1]');
|
SELECT vector_norm('[0,1]');
|
||||||
|
|
||||||
|
SELECT normalize_l2('[3,4]');
|
||||||
|
SELECT normalize_l2('[3,0]');
|
||||||
|
SELECT normalize_l2('[0,0.1]');
|
||||||
|
SELECT normalize_l2('[0,0]');
|
||||||
|
SELECT normalize_l2('[3e38]');
|
||||||
|
|
||||||
SELECT l2_distance('[0,0]', '[3,4]');
|
SELECT l2_distance('[0,0]', '[3,4]');
|
||||||
SELECT l2_distance('[0,0]', '[0,1]');
|
SELECT l2_distance('[0,0]', '[0,1]');
|
||||||
SELECT l2_distance('[1,2]', '[3]');
|
SELECT l2_distance('[1,2]', '[3]');
|
||||||
|
|||||||
Reference in New Issue
Block a user