mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-24 21:02:40 +08:00
Compare commits
1 Commits
hnsw-datum
...
hnsw-datum
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f858705293 |
@@ -33,12 +33,6 @@ HnswInit(void)
|
|||||||
HNSW_DEFAULT_EF_CONSTRUCTION, HNSW_MIN_EF_CONSTRUCTION, HNSW_MAX_EF_CONSTRUCTION
|
HNSW_DEFAULT_EF_CONSTRUCTION, HNSW_MIN_EF_CONSTRUCTION, HNSW_MAX_EF_CONSTRUCTION
|
||||||
#if PG_VERSION_NUM >= 130000
|
#if PG_VERSION_NUM >= 130000
|
||||||
,AccessExclusiveLock
|
,AccessExclusiveLock
|
||||||
#endif
|
|
||||||
);
|
|
||||||
add_int_reloption(hnsw_relopt_kind, "dimensions", "Number of dimensions",
|
|
||||||
HNSW_DEFAULT_DIMENSIONS, HNSW_MIN_DIMENSIONS, HNSW_MAX_DIMENSIONS
|
|
||||||
#if PG_VERSION_NUM >= 130000
|
|
||||||
,AccessExclusiveLock
|
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -131,7 +125,6 @@ hnswoptions(Datum reloptions, bool validate)
|
|||||||
static const relopt_parse_elt tab[] = {
|
static const relopt_parse_elt tab[] = {
|
||||||
{"m", RELOPT_TYPE_INT, offsetof(HnswOptions, m)},
|
{"m", RELOPT_TYPE_INT, offsetof(HnswOptions, m)},
|
||||||
{"ef_construction", RELOPT_TYPE_INT, offsetof(HnswOptions, efConstruction)},
|
{"ef_construction", RELOPT_TYPE_INT, offsetof(HnswOptions, efConstruction)},
|
||||||
{"dimensions", RELOPT_TYPE_INT, offsetof(HnswOptions, dimensions)},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#if PG_VERSION_NUM >= 130000
|
#if PG_VERSION_NUM >= 130000
|
||||||
|
|||||||
@@ -42,9 +42,6 @@
|
|||||||
#define HNSW_DEFAULT_EF_SEARCH 40
|
#define HNSW_DEFAULT_EF_SEARCH 40
|
||||||
#define HNSW_MIN_EF_SEARCH 1
|
#define HNSW_MIN_EF_SEARCH 1
|
||||||
#define HNSW_MAX_EF_SEARCH 1000
|
#define HNSW_MAX_EF_SEARCH 1000
|
||||||
#define HNSW_DEFAULT_DIMENSIONS -1
|
|
||||||
#define HNSW_MIN_DIMENSIONS 1
|
|
||||||
#define HNSW_MAX_DIMENSIONS HNSW_MAX_DIM
|
|
||||||
|
|
||||||
/* Tuple types */
|
/* Tuple types */
|
||||||
#define HNSW_ELEMENT_TUPLE_TYPE 1
|
#define HNSW_ELEMENT_TUPLE_TYPE 1
|
||||||
@@ -101,6 +98,7 @@ typedef struct HnswElementData
|
|||||||
List *heaptids;
|
List *heaptids;
|
||||||
uint8 level;
|
uint8 level;
|
||||||
uint8 deleted;
|
uint8 deleted;
|
||||||
|
bool loaded;
|
||||||
HnswNeighborArray *neighbors;
|
HnswNeighborArray *neighbors;
|
||||||
BlockNumber blkno;
|
BlockNumber blkno;
|
||||||
OffsetNumber offno;
|
OffsetNumber offno;
|
||||||
@@ -137,7 +135,6 @@ typedef struct HnswOptions
|
|||||||
int32 vl_len_; /* varlena header (do not touch directly!) */
|
int32 vl_len_; /* varlena header (do not touch directly!) */
|
||||||
int m; /* number of connections */
|
int m; /* number of connections */
|
||||||
int efConstruction; /* size of dynamic candidate list */
|
int efConstruction; /* size of dynamic candidate list */
|
||||||
int dimensions;
|
|
||||||
} HnswOptions;
|
} HnswOptions;
|
||||||
|
|
||||||
typedef struct HnswBuildState
|
typedef struct HnswBuildState
|
||||||
@@ -266,7 +263,6 @@ typedef struct HnswVacuumState
|
|||||||
/* Methods */
|
/* Methods */
|
||||||
int HnswGetM(Relation index);
|
int HnswGetM(Relation index);
|
||||||
int HnswGetEfConstruction(Relation index);
|
int HnswGetEfConstruction(Relation index);
|
||||||
int HnswGetDimensions(Relation index);
|
|
||||||
FmgrInfo *HnswOptionalProcInfo(Relation index, uint16 procnum);
|
FmgrInfo *HnswOptionalProcInfo(Relation index, uint16 procnum);
|
||||||
bool HnswNormValue(FmgrInfo *procinfo, Oid collation, Datum *value, Vector * result);
|
bool HnswNormValue(FmgrInfo *procinfo, Oid collation, Datum *value, Vector * result);
|
||||||
void HnswCommitBuffer(Buffer buf, GenericXLogState *state);
|
void HnswCommitBuffer(Buffer buf, GenericXLogState *state);
|
||||||
|
|||||||
@@ -375,13 +375,11 @@ BuildCallback(Relation index, CALLBACK_ITEM_POINTER, Datum *values,
|
|||||||
if (inserted)
|
if (inserted)
|
||||||
{
|
{
|
||||||
element->value = datumCopy(element->value, false, -1);
|
element->value = datumCopy(element->value, false, -1);
|
||||||
|
element->loaded = true;
|
||||||
buildstate->elements = lappend(buildstate->elements, element);
|
buildstate->elements = lappend(buildstate->elements, element);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
element->value = PointerGetDatum(NULL);
|
|
||||||
HnswFreeElement(element);
|
HnswFreeElement(element);
|
||||||
}
|
|
||||||
|
|
||||||
/* Reset memory context */
|
/* Reset memory context */
|
||||||
MemoryContextReset(buildstate->tmpCtx);
|
MemoryContextReset(buildstate->tmpCtx);
|
||||||
@@ -417,14 +415,7 @@ InitBuildState(HnswBuildState * buildstate, Relation heap, Relation index, Index
|
|||||||
|
|
||||||
buildstate->m = HnswGetM(index);
|
buildstate->m = HnswGetM(index);
|
||||||
buildstate->efConstruction = HnswGetEfConstruction(index);
|
buildstate->efConstruction = HnswGetEfConstruction(index);
|
||||||
buildstate->dimensions = HnswGetDimensions(index);
|
buildstate->dimensions = TupleDescAttr(index->rd_att, 0)->atttypmod;
|
||||||
|
|
||||||
if (buildstate->dimensions < 0)
|
|
||||||
buildstate->dimensions = TupleDescAttr(index->rd_att, 0)->atttypmod;
|
|
||||||
|
|
||||||
/* Require column to have dimensions to be indexed */
|
|
||||||
if (buildstate->dimensions < 0)
|
|
||||||
elog(ERROR, "column does not have dimensions");
|
|
||||||
|
|
||||||
if (buildstate->dimensions > HNSW_MAX_DIM)
|
if (buildstate->dimensions > HNSW_MAX_DIM)
|
||||||
elog(ERROR, "column cannot have more than %d dimensions for hnsw index", HNSW_MAX_DIM);
|
elog(ERROR, "column cannot have more than %d dimensions for hnsw index", HNSW_MAX_DIM);
|
||||||
@@ -448,6 +439,7 @@ InitBuildState(HnswBuildState * buildstate, Relation heap, Relation index, Index
|
|||||||
buildstate->flushed = false;
|
buildstate->flushed = false;
|
||||||
|
|
||||||
/* Reuse for each tuple */
|
/* Reuse for each tuple */
|
||||||
|
/* TODO Fix / replace with support function */
|
||||||
buildstate->normvec = InitVector(buildstate->dimensions);
|
buildstate->normvec = InitVector(buildstate->dimensions);
|
||||||
|
|
||||||
buildstate->tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
|
buildstate->tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
|
||||||
|
|||||||
@@ -35,20 +35,6 @@ HnswGetEfConstruction(Relation index)
|
|||||||
return HNSW_DEFAULT_EF_CONSTRUCTION;
|
return HNSW_DEFAULT_EF_CONSTRUCTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the number of dimensions in the index
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
HnswGetDimensions(Relation index)
|
|
||||||
{
|
|
||||||
HnswOptions *opts = (HnswOptions *) index->rd_options;
|
|
||||||
|
|
||||||
if (opts)
|
|
||||||
return opts->dimensions;
|
|
||||||
|
|
||||||
return HNSW_DEFAULT_DIMENSIONS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get proc
|
* Get proc
|
||||||
*/
|
*/
|
||||||
@@ -202,7 +188,7 @@ HnswFreeElement(HnswElement element)
|
|||||||
{
|
{
|
||||||
HnswFreeNeighbors(element);
|
HnswFreeNeighbors(element);
|
||||||
list_free_deep(element->heaptids);
|
list_free_deep(element->heaptids);
|
||||||
if (DatumGetPointer(element->value))
|
if (element->loaded)
|
||||||
pfree(DatumGetPointer(element->value));
|
pfree(DatumGetPointer(element->value));
|
||||||
pfree(element);
|
pfree(element);
|
||||||
}
|
}
|
||||||
@@ -230,7 +216,7 @@ HnswInitElementFromBlock(BlockNumber blkno, OffsetNumber offno)
|
|||||||
element->blkno = blkno;
|
element->blkno = blkno;
|
||||||
element->offno = offno;
|
element->offno = offno;
|
||||||
element->neighbors = NULL;
|
element->neighbors = NULL;
|
||||||
element->value = PointerGetDatum(NULL);
|
element->loaded = false;
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,6 +452,7 @@ HnswLoadElementFromTuple(HnswElement element, HnswElementTuple etup, bool loadHe
|
|||||||
Datum value = PointerGetDatum(&etup->value);
|
Datum value = PointerGetDatum(&etup->value);
|
||||||
|
|
||||||
element->value = datumCopy(value, false, -1);
|
element->value = datumCopy(value, false, -1);
|
||||||
|
element->loaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -953,7 +940,7 @@ HnswUpdateConnection(HnswElement element, HnswCandidate * hc, int m, int lc, int
|
|||||||
{
|
{
|
||||||
HnswCandidate *hc3 = ¤tNeighbors->items[i];
|
HnswCandidate *hc3 = ¤tNeighbors->items[i];
|
||||||
|
|
||||||
if (!DatumGetPointer(hc3->element->value))
|
if (!hc3->element->loaded)
|
||||||
HnswLoadElement(hc3->element, &hc3->distance, &q, index, procinfo, collation, true);
|
HnswLoadElement(hc3->element, &hc3->distance, &q, index, procinfo, collation, true);
|
||||||
else
|
else
|
||||||
hc3->distance = GetCandidateDistance(hc3, q, procinfo, collation);
|
hc3->distance = GetCandidateDistance(hc3, q, procinfo, collation);
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ for my $i (0 .. $#operators)
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Add index
|
# Add index
|
||||||
$node->safe_psql("postgres", "CREATE INDEX ON tst USING hnsw (v $opclass) WITH (dimensions = 3);");
|
$node->safe_psql("postgres", "CREATE INDEX ON tst USING hnsw (v $opclass);");
|
||||||
|
|
||||||
my $min = $operator eq "<#>" ? 0.80 : 0.99;
|
my $min = $operator eq "<#>" ? 0.80 : 0.99;
|
||||||
test_recall($min, $operator);
|
test_recall($min, $operator);
|
||||||
|
|||||||
Reference in New Issue
Block a user