mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-22 20:15:46 +08:00
Compare commits
15 Commits
pairinghea
...
v0.4.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69672cd84d | ||
|
|
300adba2f1 | ||
|
|
e362279199 | ||
|
|
53301021f6 | ||
|
|
8f589f6d09 | ||
|
|
dcf206128a | ||
|
|
3244d40e8a | ||
|
|
7d8dbcaa3c | ||
|
|
7f575f55fb | ||
|
|
94e7487d5f | ||
|
|
74a3cd597f | ||
|
|
db8ed738b8 | ||
|
|
54c550420b | ||
|
|
cc539a0a27 | ||
|
|
d885e2bcfa |
@@ -1,6 +1,7 @@
|
|||||||
## 0.4.2 (unreleased)
|
## 0.4.2 (2023-05-13)
|
||||||
|
|
||||||
- Added notice when index created with little data
|
- Added notice when index created with little data
|
||||||
|
- Fixed dimensions check for some direct function calls
|
||||||
- Fixed installation error with Postgres 12.0-12.2
|
- Fixed installation error with Postgres 12.0-12.2
|
||||||
|
|
||||||
## 0.4.1 (2023-03-21)
|
## 0.4.1 (2023-03-21)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "vector",
|
"name": "vector",
|
||||||
"abstract": "Open-source vector similarity search for Postgres",
|
"abstract": "Open-source vector similarity search for Postgres",
|
||||||
"description": "Supports L2 distance, inner product, and cosine distance",
|
"description": "Supports L2 distance, inner product, and cosine distance",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"maintainer": [
|
"maintainer": [
|
||||||
"Andrew Kane <andrew@ankane.org>"
|
"Andrew Kane <andrew@ankane.org>"
|
||||||
],
|
],
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
"vector": {
|
"vector": {
|
||||||
"file": "sql/vector.sql",
|
"file": "sql/vector.sql",
|
||||||
"docfile": "README.md",
|
"docfile": "README.md",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"abstract": "Open-source vector similarity search for Postgres"
|
"abstract": "Open-source vector similarity search for Postgres"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
8
Makefile
8
Makefile
@@ -1,5 +1,5 @@
|
|||||||
EXTENSION = vector
|
EXTENSION = vector
|
||||||
EXTVERSION = 0.4.1
|
EXTVERSION = 0.4.2
|
||||||
|
|
||||||
MODULE_big = vector
|
MODULE_big = vector
|
||||||
DATA = $(wildcard sql/*--*.sql)
|
DATA = $(wildcard sql/*--*.sql)
|
||||||
@@ -63,3 +63,9 @@ dist:
|
|||||||
|
|
||||||
docker:
|
docker:
|
||||||
docker build --pull --no-cache --platform linux/amd64 -t ankane/pgvector:latest .
|
docker build --pull --no-cache --platform linux/amd64 -t ankane/pgvector:latest .
|
||||||
|
|
||||||
|
.PHONY: docker-release
|
||||||
|
|
||||||
|
docker-release:
|
||||||
|
docker buildx build --push --pull --no-cache --platform linux/amd64,linux/arm64 -t ankane/pgvector:latest .
|
||||||
|
docker buildx build --push --platform linux/amd64,linux/arm64 -t ankane/pgvector:v$(EXTVERSION) .
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
EXTENSION = vector
|
EXTENSION = vector
|
||||||
EXTVERSION = 0.4.1
|
EXTVERSION = 0.4.2
|
||||||
|
|
||||||
OBJS = src\ivfbuild.obj src\ivfflat.obj src\ivfinsert.obj src\ivfkmeans.obj src\ivfscan.obj src\ivfutils.obj src\ivfvacuum.obj src\vector.obj
|
OBJS = src\ivfbuild.obj src\ivfflat.obj src\ivfinsert.obj src\ivfkmeans.obj src\ivfscan.obj src\ivfutils.obj src\ivfvacuum.obj src\vector.obj
|
||||||
|
|
||||||
|
|||||||
24
README.md
24
README.md
@@ -16,7 +16,7 @@ Compile and install the extension (supports Postgres 11+)
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd /tmp
|
cd /tmp
|
||||||
git clone --branch v0.4.1 https://github.com/pgvector/pgvector.git
|
git clone --branch v0.4.2 https://github.com/pgvector/pgvector.git
|
||||||
cd pgvector
|
cd pgvector
|
||||||
make
|
make
|
||||||
make install # may need sudo
|
make install # may need sudo
|
||||||
@@ -307,10 +307,11 @@ Yes, pgvector uses the write-ahead log (WAL), which allows for replication and p
|
|||||||
|
|
||||||
#### What if I want to index vectors with more than 2,000 dimensions?
|
#### What if I want to index vectors with more than 2,000 dimensions?
|
||||||
|
|
||||||
Two things you can try are:
|
You’ll need to use [dimensionality reduction](https://en.wikipedia.org/wiki/Dimensionality_reduction) at the moment.
|
||||||
|
|
||||||
1. use dimensionality reduction
|
#### Why am I seeing less results after adding an index?
|
||||||
2. compile Postgres with a larger block size (`./configure --with-blocksize=32`) and edit the limit in `src/ivfflat.h`
|
|
||||||
|
The index was likely created with too little data for the number of lists. Drop the index until the table has more data.
|
||||||
|
|
||||||
## Reference
|
## Reference
|
||||||
|
|
||||||
@@ -354,7 +355,11 @@ If your machine has multiple Postgres installations, specify the path to [pg_con
|
|||||||
export PG_CONFIG=/Applications/Postgres.app/Contents/Versions/latest/bin/pg_config
|
export PG_CONFIG=/Applications/Postgres.app/Contents/Versions/latest/bin/pg_config
|
||||||
```
|
```
|
||||||
|
|
||||||
Then re-run the installation instructions (run `make clean` before `make` if needed)
|
Then re-run the installation instructions (run `make clean` before `make` if needed). If `sudo` is needed for `make install`, use:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo --preserve-env=PG_CONFIG make install
|
||||||
|
```
|
||||||
|
|
||||||
### Missing Header
|
### Missing Header
|
||||||
|
|
||||||
@@ -374,7 +379,7 @@ Support for Windows is currently experimental. Use `nmake` to build:
|
|||||||
|
|
||||||
```cmd
|
```cmd
|
||||||
set "PGROOT=C:\Program Files\PostgreSQL\15"
|
set "PGROOT=C:\Program Files\PostgreSQL\15"
|
||||||
git clone --branch v0.4.1 https://github.com/pgvector/pgvector.git
|
git clone --branch v0.4.2 https://github.com/pgvector/pgvector.git
|
||||||
cd pgvector
|
cd pgvector
|
||||||
nmake /F Makefile.win
|
nmake /F Makefile.win
|
||||||
nmake /F Makefile.win install
|
nmake /F Makefile.win install
|
||||||
@@ -395,7 +400,7 @@ This adds pgvector to the [Postgres image](https://hub.docker.com/_/postgres) (r
|
|||||||
You can also build the image manually:
|
You can also build the image manually:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone --branch v0.4.1 https://github.com/pgvector/pgvector.git
|
git clone --branch v0.4.2 https://github.com/pgvector/pgvector.git
|
||||||
cd pgvector
|
cd pgvector
|
||||||
docker build -t pgvector .
|
docker build -t pgvector .
|
||||||
```
|
```
|
||||||
@@ -408,6 +413,8 @@ With Homebrew Postgres, you can use:
|
|||||||
brew install pgvector
|
brew install pgvector
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note: This only adds it to the `postgresql@14` formula
|
||||||
|
|
||||||
### PGXN
|
### PGXN
|
||||||
|
|
||||||
Install from the [PostgreSQL Extension Network](https://pgxn.org/dist/vector) with:
|
Install from the [PostgreSQL Extension Network](https://pgxn.org/dist/vector) with:
|
||||||
@@ -444,10 +451,9 @@ pgvector is available on [these providers](https://github.com/pgvector/pgvector/
|
|||||||
|
|
||||||
To request a new extension on other providers:
|
To request a new extension on other providers:
|
||||||
|
|
||||||
- Amazon RDS - follow the instructions on [this page](https://aws.amazon.com/rds/postgresql/faqs/)
|
|
||||||
- Google Cloud SQL - vote or comment on [this page](https://issuetracker.google.com/issues/265172065)
|
- Google Cloud SQL - vote or comment on [this page](https://issuetracker.google.com/issues/265172065)
|
||||||
- Azure Database - vote or comment on [this page](https://feedback.azure.com/d365community/idea/7b423322-6189-ed11-a81b-000d3ae49307)
|
- Azure Database - vote or comment on [this page](https://feedback.azure.com/d365community/idea/7b423322-6189-ed11-a81b-000d3ae49307)
|
||||||
- DigitalOcean Managed Databases - vote or comment on [this page](https://ideas.digitalocean.com/app-framework-services/p/pgvector-extension-for-postgresql)
|
- DigitalOcean Managed Databases - vote or comment on [this page](https://ideas.digitalocean.com/managed-database/p/pgvector-extension-for-postgresql)
|
||||||
- Heroku Postgres - vote or comment on [this page](https://github.com/heroku/roadmap/issues/156)
|
- Heroku Postgres - vote or comment on [this page](https://github.com/heroku/roadmap/issues/156)
|
||||||
|
|
||||||
## Upgrading
|
## Upgrading
|
||||||
|
|||||||
2
sql/vector--0.4.1--0.4.2.sql
Normal file
2
sql/vector--0.4.1--0.4.2.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||||
|
\echo Use "ALTER EXTENSION vector UPDATE TO '0.4.2'" to load this file. \quit
|
||||||
@@ -438,8 +438,8 @@ ComputeCenters(IvfflatBuildState * buildstate)
|
|||||||
{
|
{
|
||||||
ereport(NOTICE,
|
ereport(NOTICE,
|
||||||
(errmsg("ivfflat index created with little data"),
|
(errmsg("ivfflat index created with little data"),
|
||||||
errdetail("this will cause poor recall"),
|
errdetail("This will cause low recall."),
|
||||||
errhint("drop the index until the table has more data")));
|
errhint("Drop the index until the table has more data.")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -187,14 +187,6 @@ typedef struct IvfflatScanList
|
|||||||
double distance;
|
double distance;
|
||||||
} IvfflatScanList;
|
} IvfflatScanList;
|
||||||
|
|
||||||
typedef struct IvfflatScanItem
|
|
||||||
{
|
|
||||||
pairingheap_node ph_node;
|
|
||||||
BlockNumber searchPage;
|
|
||||||
double distance;
|
|
||||||
ItemPointerData tid;
|
|
||||||
} IvfflatScanItem;
|
|
||||||
|
|
||||||
typedef struct IvfflatScanOpaqueData
|
typedef struct IvfflatScanOpaqueData
|
||||||
{
|
{
|
||||||
int probes;
|
int probes;
|
||||||
@@ -212,13 +204,6 @@ typedef struct IvfflatScanOpaqueData
|
|||||||
FmgrInfo *normprocinfo;
|
FmgrInfo *normprocinfo;
|
||||||
Oid collation;
|
Oid collation;
|
||||||
|
|
||||||
/* Items */
|
|
||||||
int maxItems;
|
|
||||||
int itemCount;
|
|
||||||
pairingheap *itemQueue;
|
|
||||||
IvfflatScanItem *items;
|
|
||||||
IvfflatScanItem **sortedItems;
|
|
||||||
|
|
||||||
/* Lists */
|
/* Lists */
|
||||||
pairingheap *listQueue;
|
pairingheap *listQueue;
|
||||||
IvfflatScanList lists[FLEXIBLE_ARRAY_MEMBER]; /* must come last */
|
IvfflatScanList lists[FLEXIBLE_ARRAY_MEMBER]; /* must come last */
|
||||||
|
|||||||
139
src/ivfscan.c
139
src/ivfscan.c
@@ -26,21 +26,6 @@ CompareLists(const pairingheap_node *a, const pairingheap_node *b, void *arg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Compare item distances
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
CompareItems(const pairingheap_node *a, const pairingheap_node *b, void *arg)
|
|
||||||
{
|
|
||||||
if (((const IvfflatScanItem *) a)->distance > ((const IvfflatScanItem *) b)->distance)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (((const IvfflatScanItem *) a)->distance < ((const IvfflatScanItem *) b)->distance)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get lists and sort by distance
|
* Get lists and sort by distance
|
||||||
*/
|
*/
|
||||||
@@ -126,10 +111,13 @@ GetScanItems(IndexScanDesc scan, Datum value)
|
|||||||
Datum datum;
|
Datum datum;
|
||||||
bool isnull;
|
bool isnull;
|
||||||
TupleDesc tupdesc = RelationGetDescr(scan->indexRelation);
|
TupleDesc tupdesc = RelationGetDescr(scan->indexRelation);
|
||||||
int i;
|
double tuples = 0;
|
||||||
double distance;
|
|
||||||
IvfflatScanItem *scanitem;
|
#if PG_VERSION_NUM >= 120000
|
||||||
double maxDistance = DBL_MAX;
|
TupleTableSlot *slot = MakeSingleTupleTableSlot(so->tupdesc, &TTSOpsVirtual);
|
||||||
|
#else
|
||||||
|
TupleTableSlot *slot = MakeSingleTupleTableSlot(so->tupdesc);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reuse same set of shared buffers for scan
|
* Reuse same set of shared buffers for scan
|
||||||
@@ -155,40 +143,25 @@ GetScanItems(IndexScanDesc scan, Datum value)
|
|||||||
{
|
{
|
||||||
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offno));
|
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offno));
|
||||||
datum = index_getattr(itup, 1, tupdesc, &isnull);
|
datum = index_getattr(itup, 1, tupdesc, &isnull);
|
||||||
distance = DatumGetFloat8(FunctionCall2Coll(so->procinfo, so->collation, datum, value));
|
|
||||||
|
|
||||||
if (so->itemCount < so->maxItems)
|
/*
|
||||||
{
|
* Add virtual tuple
|
||||||
scanitem = &so->items[so->itemCount];
|
*
|
||||||
scanitem->searchPage = searchPage;
|
* Use procinfo from the index instead of scan key for
|
||||||
scanitem->tid = itup->t_tid;
|
* performance
|
||||||
scanitem->distance = distance;
|
*/
|
||||||
so->itemCount++;
|
ExecClearTuple(slot);
|
||||||
|
slot->tts_values[0] = FunctionCall2Coll(so->procinfo, so->collation, datum, value);
|
||||||
|
slot->tts_isnull[0] = false;
|
||||||
|
slot->tts_values[1] = PointerGetDatum(&itup->t_tid);
|
||||||
|
slot->tts_isnull[1] = false;
|
||||||
|
slot->tts_values[2] = Int32GetDatum((int) searchPage);
|
||||||
|
slot->tts_isnull[2] = false;
|
||||||
|
ExecStoreVirtualTuple(slot);
|
||||||
|
|
||||||
/* Add to heap */
|
tuplesort_puttupleslot(so->sortstate, slot);
|
||||||
pairingheap_add(so->itemQueue, &scanitem->ph_node);
|
|
||||||
|
|
||||||
/* Calculate max distance */
|
tuples++;
|
||||||
if (so->itemCount == so->maxItems)
|
|
||||||
{
|
|
||||||
maxDistance = ((IvfflatScanItem *) pairingheap_first(so->itemQueue))->distance;
|
|
||||||
scanitem = &so->items[so->itemCount];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (distance < maxDistance)
|
|
||||||
{
|
|
||||||
/* Reuse */
|
|
||||||
scanitem->searchPage = searchPage;
|
|
||||||
scanitem->tid = itup->t_tid;
|
|
||||||
scanitem->distance = distance;
|
|
||||||
pairingheap_add(so->itemQueue, &scanitem->ph_node);
|
|
||||||
|
|
||||||
/* Remove */
|
|
||||||
scanitem = (IvfflatScanItem *) pairingheap_remove_first(so->itemQueue);
|
|
||||||
|
|
||||||
/* Update max distance */
|
|
||||||
maxDistance = ((IvfflatScanItem *) pairingheap_first(so->itemQueue))->distance;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
searchPage = IvfflatPageGetOpaque(page)->nextblkno;
|
searchPage = IvfflatPageGetOpaque(page)->nextblkno;
|
||||||
@@ -197,10 +170,14 @@ GetScanItems(IndexScanDesc scan, Datum value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < so->itemCount; i++)
|
/* TODO Scan more lists */
|
||||||
so->sortedItems[i] = (IvfflatScanItem *) pairingheap_remove_first(so->itemQueue);
|
if (tuples < 100)
|
||||||
|
ereport(DEBUG1,
|
||||||
|
(errmsg("index scan found few tuples"),
|
||||||
|
errdetail("Index may have been created with little data."),
|
||||||
|
errhint("Recreate the index and possibly decrease lists.")));
|
||||||
|
|
||||||
Assert(pairingheap_is_empty(so->itemQueue));
|
tuplesort_performsort(so->sortstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -212,6 +189,10 @@ ivfflatbeginscan(Relation index, int nkeys, int norderbys)
|
|||||||
IndexScanDesc scan;
|
IndexScanDesc scan;
|
||||||
IvfflatScanOpaque so;
|
IvfflatScanOpaque so;
|
||||||
int lists;
|
int lists;
|
||||||
|
AttrNumber attNums[] = {1};
|
||||||
|
Oid sortOperators[] = {Float8LessOperator};
|
||||||
|
Oid sortCollations[] = {InvalidOid};
|
||||||
|
bool nullsFirstFlags[] = {false};
|
||||||
int probes = ivfflat_probes;
|
int probes = ivfflat_probes;
|
||||||
|
|
||||||
scan = RelationGetIndexScan(index, nkeys, norderbys);
|
scan = RelationGetIndexScan(index, nkeys, norderbys);
|
||||||
@@ -230,13 +211,26 @@ ivfflatbeginscan(Relation index, int nkeys, int norderbys)
|
|||||||
so->normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORM_PROC);
|
so->normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORM_PROC);
|
||||||
so->collation = index->rd_indcollation[0];
|
so->collation = index->rd_indcollation[0];
|
||||||
|
|
||||||
so->listQueue = pairingheap_allocate(CompareLists, scan);
|
/* Create tuple description for sorting */
|
||||||
|
#if PG_VERSION_NUM >= 120000
|
||||||
|
so->tupdesc = CreateTemplateTupleDesc(3);
|
||||||
|
#else
|
||||||
|
so->tupdesc = CreateTemplateTupleDesc(3, false);
|
||||||
|
#endif
|
||||||
|
TupleDescInitEntry(so->tupdesc, (AttrNumber) 1, "distance", FLOAT8OID, -1, 0);
|
||||||
|
TupleDescInitEntry(so->tupdesc, (AttrNumber) 2, "tid", TIDOID, -1, 0);
|
||||||
|
TupleDescInitEntry(so->tupdesc, (AttrNumber) 3, "indexblkno", INT4OID, -1, 0);
|
||||||
|
|
||||||
so->maxItems = 10;
|
/* Prep sort */
|
||||||
so->itemCount = 0;
|
so->sortstate = tuplesort_begin_heap(so->tupdesc, 1, attNums, sortOperators, sortCollations, nullsFirstFlags, work_mem, NULL, false);
|
||||||
so->itemQueue = pairingheap_allocate(CompareItems, scan);
|
|
||||||
so->items = palloc(sizeof(IvfflatScanItem) * (so->maxItems + 1));
|
#if PG_VERSION_NUM >= 120000
|
||||||
so->sortedItems = palloc(sizeof(IvfflatScanItem *) * so->maxItems);
|
so->slot = MakeSingleTupleTableSlot(so->tupdesc, &TTSOpsMinimalTuple);
|
||||||
|
#else
|
||||||
|
so->slot = MakeSingleTupleTableSlot(so->tupdesc);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
so->listQueue = pairingheap_allocate(CompareLists, scan);
|
||||||
|
|
||||||
scan->opaque = so;
|
scan->opaque = so;
|
||||||
|
|
||||||
@@ -251,10 +245,13 @@ ivfflatrescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int
|
|||||||
{
|
{
|
||||||
IvfflatScanOpaque so = (IvfflatScanOpaque) scan->opaque;
|
IvfflatScanOpaque so = (IvfflatScanOpaque) scan->opaque;
|
||||||
|
|
||||||
|
#if PG_VERSION_NUM >= 130000
|
||||||
|
if (!so->first)
|
||||||
|
tuplesort_reset(so->sortstate);
|
||||||
|
#endif
|
||||||
|
|
||||||
so->first = true;
|
so->first = true;
|
||||||
pairingheap_reset(so->listQueue);
|
pairingheap_reset(so->listQueue);
|
||||||
pairingheap_reset(so->itemQueue);
|
|
||||||
so->itemCount = 0;
|
|
||||||
|
|
||||||
if (keys && scan->numberOfKeys > 0)
|
if (keys && scan->numberOfKeys > 0)
|
||||||
memmove(scan->keyData, keys, scan->numberOfKeys * sizeof(ScanKeyData));
|
memmove(scan->keyData, keys, scan->numberOfKeys * sizeof(ScanKeyData));
|
||||||
@@ -314,18 +311,15 @@ ivfflatgettuple(IndexScanDesc scan, ScanDirection dir)
|
|||||||
pfree(DatumGetPointer(value));
|
pfree(DatumGetPointer(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (so->itemCount > 0)
|
if (tuplesort_gettupleslot(so->sortstate, true, false, so->slot, NULL))
|
||||||
{
|
{
|
||||||
IvfflatScanItem *scanitem;
|
ItemPointer tid = (ItemPointer) DatumGetPointer(slot_getattr(so->slot, 2, &so->isnull));
|
||||||
|
BlockNumber indexblkno = DatumGetInt32(slot_getattr(so->slot, 3, &so->isnull));
|
||||||
so->itemCount--;
|
|
||||||
|
|
||||||
scanitem = so->sortedItems[so->itemCount];
|
|
||||||
|
|
||||||
#if PG_VERSION_NUM >= 120000
|
#if PG_VERSION_NUM >= 120000
|
||||||
scan->xs_heaptid = scanitem->tid;
|
scan->xs_heaptid = *tid;
|
||||||
#else
|
#else
|
||||||
scan->xs_ctup.t_self = scanitem->tid;
|
scan->xs_ctup.t_self = *tid;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (BufferIsValid(so->buf))
|
if (BufferIsValid(so->buf))
|
||||||
@@ -337,7 +331,7 @@ ivfflatgettuple(IndexScanDesc scan, ScanDirection dir)
|
|||||||
*
|
*
|
||||||
* https://www.postgresql.org/docs/current/index-locking.html
|
* https://www.postgresql.org/docs/current/index-locking.html
|
||||||
*/
|
*/
|
||||||
so->buf = ReadBuffer(scan->indexRelation, scanitem->searchPage);
|
so->buf = ReadBuffer(scan->indexRelation, indexblkno);
|
||||||
|
|
||||||
scan->xs_recheckorderby = false;
|
scan->xs_recheckorderby = false;
|
||||||
return true;
|
return true;
|
||||||
@@ -359,10 +353,7 @@ ivfflatendscan(IndexScanDesc scan)
|
|||||||
ReleaseBuffer(so->buf);
|
ReleaseBuffer(so->buf);
|
||||||
|
|
||||||
pairingheap_free(so->listQueue);
|
pairingheap_free(so->listQueue);
|
||||||
|
tuplesort_end(so->sortstate);
|
||||||
pairingheap_free(so->itemQueue);
|
|
||||||
pfree(so->items);
|
|
||||||
pfree(so->sortedItems);
|
|
||||||
|
|
||||||
pfree(so);
|
pfree(so);
|
||||||
scan->opaque = NULL;
|
scan->opaque = NULL;
|
||||||
|
|||||||
@@ -396,10 +396,8 @@ array_to_vector(PG_FUNCTION_ARGS)
|
|||||||
get_typlenbyvalalign(ARR_ELEMTYPE(array), &typlen, &typbyval, &typalign);
|
get_typlenbyvalalign(ARR_ELEMTYPE(array), &typlen, &typbyval, &typalign);
|
||||||
deconstruct_array(array, ARR_ELEMTYPE(array), typlen, typbyval, typalign, &elemsp, &nullsp, &nelemsp);
|
deconstruct_array(array, ARR_ELEMTYPE(array), typlen, typbyval, typalign, &elemsp, &nullsp, &nelemsp);
|
||||||
|
|
||||||
if (typmod == -1)
|
CheckDim(nelemsp);
|
||||||
CheckDim(nelemsp);
|
CheckExpectedDim(typmod, nelemsp);
|
||||||
else
|
|
||||||
CheckExpectedDim(typmod, nelemsp);
|
|
||||||
|
|
||||||
result = InitVector(nelemsp);
|
result = InitVector(nelemsp);
|
||||||
for (i = 0; i < nelemsp; i++)
|
for (i = 0; i < nelemsp; i++)
|
||||||
@@ -952,6 +950,7 @@ vector_avg(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
/* Create vector */
|
/* Create vector */
|
||||||
dim = STATE_DIMS(statearray);
|
dim = STATE_DIMS(statearray);
|
||||||
|
CheckDim(dim);
|
||||||
result = InitVector(dim);
|
result = InitVector(dim);
|
||||||
for (int i = 0; i < dim; i++)
|
for (int i = 0; i < dim; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ SELECT '[1,2,3]'::vector::real[];
|
|||||||
|
|
||||||
SELECT array_agg(n)::vector FROM generate_series(1, 16001) n;
|
SELECT array_agg(n)::vector FROM generate_series(1, 16001) n;
|
||||||
ERROR: vector cannot have more than 16000 dimensions
|
ERROR: vector cannot have more than 16000 dimensions
|
||||||
|
SELECT array_to_vector(array_agg(n), 16001, false) FROM generate_series(1, 16001) n;
|
||||||
|
ERROR: vector cannot have more than 16000 dimensions
|
||||||
-- ensure no error
|
-- ensure no error
|
||||||
SELECT ARRAY[1,2,3] = ARRAY[1,2,3];
|
SELECT ARRAY[1,2,3] = ARRAY[1,2,3];
|
||||||
?column?
|
?column?
|
||||||
|
|||||||
@@ -102,3 +102,5 @@ SELECT avg(v) FROM unnest(ARRAY[]::vector[]) v;
|
|||||||
|
|
||||||
SELECT avg(v) FROM unnest(ARRAY['[1,2]'::vector, '[3]']) v;
|
SELECT avg(v) FROM unnest(ARRAY['[1,2]'::vector, '[3]']) v;
|
||||||
ERROR: expected 2 dimensions, not 1
|
ERROR: expected 2 dimensions, not 1
|
||||||
|
SELECT vector_avg(array_agg(n)) FROM generate_series(1, 16002) n;
|
||||||
|
ERROR: vector cannot have more than 16000 dimensions
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ SELECT '{-Infinity}'::real[]::vector;
|
|||||||
SELECT '{}'::real[]::vector;
|
SELECT '{}'::real[]::vector;
|
||||||
SELECT '[1,2,3]'::vector::real[];
|
SELECT '[1,2,3]'::vector::real[];
|
||||||
SELECT array_agg(n)::vector FROM generate_series(1, 16001) n;
|
SELECT array_agg(n)::vector FROM generate_series(1, 16001) n;
|
||||||
|
SELECT array_to_vector(array_agg(n), 16001, false) FROM generate_series(1, 16001) n;
|
||||||
|
|
||||||
-- ensure no error
|
-- ensure no error
|
||||||
SELECT ARRAY[1,2,3] = ARRAY[1,2,3];
|
SELECT ARRAY[1,2,3] = ARRAY[1,2,3];
|
||||||
|
|||||||
@@ -24,3 +24,4 @@ SELECT avg(v) FROM unnest(ARRAY['[1,2,3]'::vector, '[3,5,7]']) v;
|
|||||||
SELECT avg(v) FROM unnest(ARRAY['[1,2,3]'::vector, '[3,5,7]', NULL]) v;
|
SELECT avg(v) FROM unnest(ARRAY['[1,2,3]'::vector, '[3,5,7]', NULL]) v;
|
||||||
SELECT avg(v) FROM unnest(ARRAY[]::vector[]) v;
|
SELECT avg(v) FROM unnest(ARRAY[]::vector[]) v;
|
||||||
SELECT avg(v) FROM unnest(ARRAY['[1,2]'::vector, '[3]']) v;
|
SELECT avg(v) FROM unnest(ARRAY['[1,2]'::vector, '[3]']) v;
|
||||||
|
SELECT vector_avg(array_agg(n)) FROM generate_series(1, 16002) n;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
comment = 'vector data type and ivfflat access method'
|
comment = 'vector data type and ivfflat access method'
|
||||||
default_version = '0.4.1'
|
default_version = '0.4.2'
|
||||||
module_pathname = '$libdir/vector'
|
module_pathname = '$libdir/vector'
|
||||||
relocatable = true
|
relocatable = true
|
||||||
|
|||||||
Reference in New Issue
Block a user