mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-26 13:52:42 +08:00
Compare commits
3 Commits
ci6
...
hnsw-vacuu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f75886bb2 | ||
|
|
ebf7de0c16 | ||
|
|
142a32af96 |
63
.github/workflows/build.yml
vendored
63
.github/workflows/build.yml
vendored
@@ -29,7 +29,9 @@ jobs:
|
|||||||
- run: make
|
- run: make
|
||||||
env:
|
env:
|
||||||
PG_CFLAGS: -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare
|
PG_CFLAGS: -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare
|
||||||
- run: sudo make install
|
- run: |
|
||||||
|
export PG_CONFIG=`which pg_config`
|
||||||
|
sudo --preserve-env=PG_CONFIG make install
|
||||||
- run: make installcheck
|
- run: make installcheck
|
||||||
- if: ${{ failure() }}
|
- if: ${{ failure() }}
|
||||||
run: cat regression.diffs
|
run: cat regression.diffs
|
||||||
@@ -37,3 +39,62 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install libipc-run-perl
|
sudo apt-get install libipc-run-perl
|
||||||
- run: make prove_installcheck
|
- run: make prove_installcheck
|
||||||
|
mac:
|
||||||
|
runs-on: macos-latest
|
||||||
|
if: ${{ !startsWith(github.ref_name, 'windows') }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: ankane/setup-postgres@v1
|
||||||
|
with:
|
||||||
|
postgres-version: 14
|
||||||
|
- run: make
|
||||||
|
env:
|
||||||
|
PG_CFLAGS: -Wall -Wextra -Werror -Wno-unused-parameter
|
||||||
|
- run: make install
|
||||||
|
- run: make installcheck
|
||||||
|
- if: ${{ failure() }}
|
||||||
|
run: cat regression.diffs
|
||||||
|
- run: |
|
||||||
|
brew install cpanm
|
||||||
|
cpanm --notest IPC::Run
|
||||||
|
wget -q https://github.com/postgres/postgres/archive/refs/tags/REL_14_10.tar.gz
|
||||||
|
tar xf REL_14_10.tar.gz
|
||||||
|
- run: make prove_installcheck PROVE_FLAGS="-I ./postgres-REL_14_10/src/test/perl" PERL5LIB="/Users/runner/perl5/lib/perl5"
|
||||||
|
- run: make clean && /usr/local/opt/llvm@15/bin/scan-build --status-bugs make PG_CFLAGS="-DUSE_ASSERT_CHECKING"
|
||||||
|
windows:
|
||||||
|
runs-on: windows-latest
|
||||||
|
if: ${{ !startsWith(github.ref_name, 'mac') }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: ankane/setup-postgres@v1
|
||||||
|
with:
|
||||||
|
postgres-version: 14
|
||||||
|
- run: |
|
||||||
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" && ^
|
||||||
|
nmake /NOLOGO /F Makefile.win && ^
|
||||||
|
nmake /NOLOGO /F Makefile.win install && ^
|
||||||
|
nmake /NOLOGO /F Makefile.win installcheck && ^
|
||||||
|
nmake /NOLOGO /F Makefile.win clean && ^
|
||||||
|
nmake /NOLOGO /F Makefile.win uninstall
|
||||||
|
shell: cmd
|
||||||
|
i386:
|
||||||
|
if: ${{ !startsWith(github.ref_name, 'mac') && !startsWith(github.ref_name, 'windows') }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: debian:12
|
||||||
|
options: --platform linux/386
|
||||||
|
steps:
|
||||||
|
- run: apt-get update && apt-get install -y build-essential git libipc-run-perl postgresql-15 postgresql-server-dev-15 sudo
|
||||||
|
- run: service postgresql start
|
||||||
|
- run: |
|
||||||
|
git clone https://github.com/${{ github.repository }}.git pgvector
|
||||||
|
cd pgvector
|
||||||
|
git fetch origin ${{ github.ref }}
|
||||||
|
git reset --hard FETCH_HEAD
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
chown -R postgres .
|
||||||
|
sudo -u postgres make installcheck
|
||||||
|
sudo -u postgres make prove_installcheck
|
||||||
|
env:
|
||||||
|
PG_CFLAGS: -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare
|
||||||
|
|||||||
12
CHANGELOG.md
12
CHANGELOG.md
@@ -1,15 +1,11 @@
|
|||||||
## 0.6.1 (unreleased)
|
## 0.6.0 (unreleased)
|
||||||
|
|
||||||
- Fixed error with `ANALYZE` and vectors with different dimensions
|
If upgrading with Postgres 12 or Docker, see [these notes](https://github.com/pgvector/pgvector#060-unreleased).
|
||||||
|
|
||||||
## 0.6.0 (2024-01-29)
|
|
||||||
|
|
||||||
If upgrading with Postgres 12 or Docker, see [these notes](https://github.com/pgvector/pgvector#060).
|
|
||||||
|
|
||||||
- Added support for parallel index builds for HNSW
|
|
||||||
- Added validation for GUC parameters
|
|
||||||
- Changed storage for vector from `extended` to `external`
|
- Changed storage for vector from `extended` to `external`
|
||||||
- Improved performance of HNSW
|
- Improved performance of HNSW
|
||||||
|
- Added support for parallel index builds for HNSW
|
||||||
|
- Added validation for GUC parameters
|
||||||
- Reduced memory usage for HNSW index builds
|
- Reduced memory usage for HNSW index builds
|
||||||
- Reduced WAL generation for HNSW index builds
|
- Reduced WAL generation for HNSW index builds
|
||||||
- Fixed error with logical replication
|
- Fixed error with logical replication
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
ARG PG_MAJOR=16
|
ARG PG_MAJOR=15
|
||||||
FROM postgres:$PG_MAJOR
|
FROM postgres:$PG_MAJOR
|
||||||
ARG PG_MAJOR
|
ARG PG_MAJOR
|
||||||
|
|
||||||
|
|||||||
@@ -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.6.0",
|
"version": "0.5.1",
|
||||||
"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.6.0",
|
"version": "0.5.1",
|
||||||
"abstract": "Open-source vector similarity search for Postgres"
|
"abstract": "Open-source vector similarity search for Postgres"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -1,5 +1,5 @@
|
|||||||
EXTENSION = vector
|
EXTENSION = vector
|
||||||
EXTVERSION = 0.6.0
|
EXTVERSION = 0.5.1
|
||||||
|
|
||||||
MODULE_big = vector
|
MODULE_big = vector
|
||||||
DATA = $(wildcard sql/*--*.sql)
|
DATA = $(wildcard sql/*--*.sql)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
EXTENSION = vector
|
EXTENSION = vector
|
||||||
EXTVERSION = 0.6.0
|
EXTVERSION = 0.5.1
|
||||||
|
|
||||||
OBJS = src\hnsw.obj src\hnswbuild.obj src\hnswinsert.obj src\hnswscan.obj src\hnswutils.obj src\hnswvacuum.obj 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\hnsw.obj src\hnswbuild.obj src\hnswinsert.obj src\hnswscan.obj src\hnswutils.obj src\hnswvacuum.obj src\ivfbuild.obj src\ivfflat.obj src\ivfinsert.obj src\ivfkmeans.obj src\ivfscan.obj src\ivfutils.obj src\ivfvacuum.obj src\vector.obj
|
||||||
HEADERS = src\vector.h
|
HEADERS = src\vector.h
|
||||||
|
|||||||
46
README.md
46
README.md
@@ -16,11 +16,11 @@ Plus [ACID](https://en.wikipedia.org/wiki/ACID) compliance, point-in-time recove
|
|||||||
|
|
||||||
### Linux and Mac
|
### Linux and Mac
|
||||||
|
|
||||||
Compile and install the extension (supports Postgres 12+)
|
Compile and install the extension (supports Postgres 11+)
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd /tmp
|
cd /tmp
|
||||||
git clone --branch v0.6.0 https://github.com/pgvector/pgvector.git
|
git clone --branch v0.5.1 https://github.com/pgvector/pgvector.git
|
||||||
cd pgvector
|
cd pgvector
|
||||||
make
|
make
|
||||||
make install # may need sudo
|
make install # may need sudo
|
||||||
@@ -28,7 +28,7 @@ make install # may need sudo
|
|||||||
|
|
||||||
See the [installation notes](#installation-notes) if you run into issues
|
See the [installation notes](#installation-notes) if you run into issues
|
||||||
|
|
||||||
You can also install it with [Docker](#docker), [Homebrew](#homebrew), [PGXN](#pgxn), [APT](#apt), [Yum](#yum), [pkg](#pkg), or [conda-forge](#conda-forge), and it comes preinstalled with [Postgres.app](#postgresapp) and many [hosted providers](#hosted-postgres). There are also instructions for [GitHub Actions](https://github.com/pgvector/setup-pgvector).
|
You can also install it with [Docker](#docker), [Homebrew](#homebrew), [PGXN](#pgxn), [APT](#apt), [Yum](#yum), or [conda-forge](#conda-forge), and it comes preinstalled with [Postgres.app](#postgresapp) and many [hosted providers](#hosted-postgres). There are also instructions for [GitHub Actions](https://github.com/pgvector/setup-pgvector).
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ Then use `nmake` to build:
|
|||||||
|
|
||||||
```cmd
|
```cmd
|
||||||
set "PGROOT=C:\Program Files\PostgreSQL\16"
|
set "PGROOT=C:\Program Files\PostgreSQL\16"
|
||||||
git clone --branch v0.6.0 https://github.com/pgvector/pgvector.git
|
git clone --branch v0.5.1 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
|
||||||
@@ -264,7 +264,7 @@ HINT: Increase maintenance_work_mem to speed up builds.
|
|||||||
|
|
||||||
Note: Do not set `maintenance_work_mem` so high that it exhausts the memory on the server
|
Note: Do not set `maintenance_work_mem` so high that it exhausts the memory on the server
|
||||||
|
|
||||||
Starting with 0.6.0, you can also speed up index creation by increasing the number of parallel workers (2 by default)
|
Starting with 0.6.0 [unreleased], you can also speed up index creation by increasing the number of parallel workers (2 by default)
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SET max_parallel_maintenance_workers = 7; -- plus leader
|
SET max_parallel_maintenance_workers = 7; -- plus leader
|
||||||
@@ -430,15 +430,6 @@ To speed up queries with an IVFFlat index, increase the number of inverted lists
|
|||||||
CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 1000);
|
CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 1000);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Vacuuming
|
|
||||||
|
|
||||||
Vacuuming can take a while for HNSW indexes. Speed it up by reindexing first.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
REINDEX INDEX CONCURRENTLY index_name;
|
|
||||||
VACUUM table_name;
|
|
||||||
```
|
|
||||||
|
|
||||||
## Languages
|
## Languages
|
||||||
|
|
||||||
Use pgvector from any language with a Postgres client. You can even generate and store vectors in one language and query them in another.
|
Use pgvector from any language with a Postgres client. You can even generate and store vectors in one language and query them in another.
|
||||||
@@ -660,20 +651,20 @@ If compilation fails and the output includes `warning: no such sysroot directory
|
|||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
|
|
||||||
Get the [Docker image](https://hub.docker.com/r/pgvector/pgvector) with:
|
Get the [Docker image](https://hub.docker.com/r/ankane/pgvector) with:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
docker pull pgvector/pgvector:pg16
|
docker pull ankane/pgvector
|
||||||
```
|
```
|
||||||
|
|
||||||
This adds pgvector to the [Postgres image](https://hub.docker.com/_/postgres) (replace `16` with your Postgres server version, and run it the same way).
|
This adds pgvector to the [Postgres image](https://hub.docker.com/_/postgres) (run it the same way).
|
||||||
|
|
||||||
You can also build the image manually:
|
You can also build the image manually:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone --branch v0.6.0 https://github.com/pgvector/pgvector.git
|
git clone --branch v0.5.1 https://github.com/pgvector/pgvector.git
|
||||||
cd pgvector
|
cd pgvector
|
||||||
docker build --build-arg PG_MAJOR=16 -t myuser/pgvector .
|
docker build --build-arg PG_MAJOR=15 -t myuser/pgvector .
|
||||||
```
|
```
|
||||||
|
|
||||||
### Homebrew
|
### Homebrew
|
||||||
@@ -716,21 +707,6 @@ sudo dnf install pgvector_16
|
|||||||
|
|
||||||
Note: Replace `16` with your Postgres server version
|
Note: Replace `16` with your Postgres server version
|
||||||
|
|
||||||
### pkg
|
|
||||||
|
|
||||||
Install the FreeBSD package with:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
pkg install postgresql15-pg_vector
|
|
||||||
```
|
|
||||||
|
|
||||||
or the port with:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cd /usr/ports/databases/pg_vector
|
|
||||||
make install
|
|
||||||
```
|
|
||||||
|
|
||||||
### conda-forge
|
### conda-forge
|
||||||
|
|
||||||
With Conda Postgres, install from [conda-forge](https://anaconda.org/conda-forge/pgvector) with:
|
With Conda Postgres, install from [conda-forge](https://anaconda.org/conda-forge/pgvector) with:
|
||||||
@@ -765,7 +741,7 @@ SELECT extversion FROM pg_extension WHERE extname = 'vector';
|
|||||||
|
|
||||||
## Upgrade Notes
|
## Upgrade Notes
|
||||||
|
|
||||||
### 0.6.0
|
### 0.6.0 [unreleased]
|
||||||
|
|
||||||
#### Postgres 12
|
#### Postgres 12
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,6 @@
|
|||||||
#define PROGRESS_HNSW_PHASE_LOAD 2
|
#define PROGRESS_HNSW_PHASE_LOAD 2
|
||||||
|
|
||||||
#define HNSW_MAX_SIZE (BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - MAXALIGN(sizeof(HnswPageOpaqueData)) - sizeof(ItemIdData))
|
#define HNSW_MAX_SIZE (BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - MAXALIGN(sizeof(HnswPageOpaqueData)) - sizeof(ItemIdData))
|
||||||
#define HNSW_TUPLE_ALLOC_SIZE BLCKSZ
|
|
||||||
|
|
||||||
#define HNSW_ELEMENT_TUPLE_SIZE(size) MAXALIGN(offsetof(HnswElementTupleData, data) + (size))
|
#define HNSW_ELEMENT_TUPLE_SIZE(size) MAXALIGN(offsetof(HnswElementTupleData, data) + (size))
|
||||||
#define HNSW_NEIGHBOR_TUPLE_SIZE(level, m) MAXALIGN(offsetof(HnswNeighborTupleData, indextids) + ((level) + 2) * (m) * sizeof(ItemPointerData))
|
#define HNSW_NEIGHBOR_TUPLE_SIZE(level, m) MAXALIGN(offsetof(HnswNeighborTupleData, indextids) + ((level) + 2) * (m) * sizeof(ItemPointerData))
|
||||||
@@ -355,7 +354,6 @@ typedef struct HnswVacuumState
|
|||||||
/* Variables */
|
/* Variables */
|
||||||
struct tidhash_hash *deleted;
|
struct tidhash_hash *deleted;
|
||||||
BufferAccessStrategy bas;
|
BufferAccessStrategy bas;
|
||||||
HnswNeighborTuple ntup;
|
|
||||||
HnswElementData highestPoint;
|
HnswElementData highestPoint;
|
||||||
|
|
||||||
/* Memory */
|
/* Memory */
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ CreateGraphPages(HnswBuildState * buildstate)
|
|||||||
{
|
{
|
||||||
Relation index = buildstate->index;
|
Relation index = buildstate->index;
|
||||||
ForkNumber forkNum = buildstate->forkNum;
|
ForkNumber forkNum = buildstate->forkNum;
|
||||||
|
Size etupAllocSize;
|
||||||
Size maxSize;
|
Size maxSize;
|
||||||
HnswElementTuple etup;
|
HnswElementTuple etup;
|
||||||
HnswNeighborTuple ntup;
|
HnswNeighborTuple ntup;
|
||||||
@@ -159,11 +160,12 @@ CreateGraphPages(HnswBuildState * buildstate)
|
|||||||
char *base = buildstate->hnswarea;
|
char *base = buildstate->hnswarea;
|
||||||
|
|
||||||
/* Calculate sizes */
|
/* Calculate sizes */
|
||||||
|
etupAllocSize = BLCKSZ;
|
||||||
maxSize = HNSW_MAX_SIZE;
|
maxSize = HNSW_MAX_SIZE;
|
||||||
|
|
||||||
/* Allocate once */
|
/* Allocate once */
|
||||||
etup = palloc0(HNSW_TUPLE_ALLOC_SIZE);
|
etup = palloc0(etupAllocSize);
|
||||||
ntup = palloc0(HNSW_TUPLE_ALLOC_SIZE);
|
ntup = palloc0(BLCKSZ);
|
||||||
|
|
||||||
/* Prepare first page */
|
/* Prepare first page */
|
||||||
buf = HnswNewBuffer(index, forkNum);
|
buf = HnswNewBuffer(index, forkNum);
|
||||||
@@ -176,13 +178,13 @@ CreateGraphPages(HnswBuildState * buildstate)
|
|||||||
Size etupSize;
|
Size etupSize;
|
||||||
Size ntupSize;
|
Size ntupSize;
|
||||||
Size combinedSize;
|
Size combinedSize;
|
||||||
Pointer valuePtr = HnswPtrAccess(base, element->value);
|
void *valuePtr = HnswPtrAccess(base, element->value);
|
||||||
|
|
||||||
/* Update iterator */
|
/* Update iterator */
|
||||||
iter = element->next;
|
iter = element->next;
|
||||||
|
|
||||||
/* Zero memory for each element */
|
/* Zero memory for each element */
|
||||||
MemSet(etup, 0, HNSW_TUPLE_ALLOC_SIZE);
|
MemSet(etup, 0, etupAllocSize);
|
||||||
|
|
||||||
/* Calculate sizes */
|
/* Calculate sizes */
|
||||||
etupSize = HNSW_ELEMENT_TUPLE_SIZE(VARSIZE_ANY(valuePtr));
|
etupSize = HNSW_ELEMENT_TUPLE_SIZE(VARSIZE_ANY(valuePtr));
|
||||||
@@ -190,7 +192,7 @@ CreateGraphPages(HnswBuildState * buildstate)
|
|||||||
combinedSize = etupSize + ntupSize + sizeof(ItemIdData);
|
combinedSize = etupSize + ntupSize + sizeof(ItemIdData);
|
||||||
|
|
||||||
/* Initial size check */
|
/* Initial size check */
|
||||||
if (etupSize > HNSW_TUPLE_ALLOC_SIZE)
|
if (etupSize > etupAllocSize)
|
||||||
elog(ERROR, "index tuple too large");
|
elog(ERROR, "index tuple too large");
|
||||||
|
|
||||||
HnswSetElementTuple(base, etup, element);
|
HnswSetElementTuple(base, etup, element);
|
||||||
@@ -252,43 +254,38 @@ WriteNeighborTuples(HnswBuildState * buildstate)
|
|||||||
int m = buildstate->m;
|
int m = buildstate->m;
|
||||||
HnswElementPtr iter = buildstate->graph->head;
|
HnswElementPtr iter = buildstate->graph->head;
|
||||||
char *base = buildstate->hnswarea;
|
char *base = buildstate->hnswarea;
|
||||||
HnswNeighborTuple ntup;
|
|
||||||
|
|
||||||
/* Allocate once */
|
|
||||||
ntup = palloc0(HNSW_TUPLE_ALLOC_SIZE);
|
|
||||||
|
|
||||||
while (!HnswPtrIsNull(base, iter))
|
while (!HnswPtrIsNull(base, iter))
|
||||||
{
|
{
|
||||||
HnswElement element = HnswPtrAccess(base, iter);
|
HnswElement e = HnswPtrAccess(base, iter);
|
||||||
Buffer buf;
|
Buffer buf;
|
||||||
Page page;
|
Page page;
|
||||||
Size ntupSize = HNSW_NEIGHBOR_TUPLE_SIZE(element->level, m);
|
ItemId itemid;
|
||||||
|
HnswNeighborTuple ntup;
|
||||||
|
|
||||||
/* Update iterator */
|
/* Update iterator */
|
||||||
iter = element->next;
|
iter = e->next;
|
||||||
|
|
||||||
/* Zero memory for each element */
|
|
||||||
MemSet(ntup, 0, HNSW_TUPLE_ALLOC_SIZE);
|
|
||||||
|
|
||||||
/* Can take a while, so ensure we can interrupt */
|
/* Can take a while, so ensure we can interrupt */
|
||||||
/* Needs to be called when no buffer locks are held */
|
/* Needs to be called when no buffer locks are held */
|
||||||
CHECK_FOR_INTERRUPTS();
|
CHECK_FOR_INTERRUPTS();
|
||||||
|
|
||||||
buf = ReadBufferExtended(index, forkNum, element->neighborPage, RBM_NORMAL, NULL);
|
buf = ReadBufferExtended(index, forkNum, e->neighborPage, RBM_NORMAL, NULL);
|
||||||
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
|
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
|
||||||
page = BufferGetPage(buf);
|
page = BufferGetPage(buf);
|
||||||
|
itemid = PageGetItemId(page, e->neighborOffno);
|
||||||
|
ntup = (HnswNeighborTuple) PageGetItem(page, itemid);
|
||||||
|
|
||||||
HnswSetNeighborTuple(base, ntup, element, m);
|
/* Check expected size */
|
||||||
|
Assert(ItemIdGetLength(itemid) == HNSW_NEIGHBOR_TUPLE_SIZE(e->level, m));
|
||||||
|
|
||||||
if (!PageIndexTupleOverwrite(page, element->neighborOffno, (Item) ntup, ntupSize))
|
/* Update page in-place */
|
||||||
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
HnswSetNeighborTuple(base, ntup, e, m);
|
||||||
|
|
||||||
/* Commit */
|
/* Commit */
|
||||||
MarkBufferDirty(buf);
|
MarkBufferDirty(buf);
|
||||||
UnlockReleaseBuffer(buf);
|
UnlockReleaseBuffer(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
pfree(ntup);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -355,7 +355,9 @@ HnswUpdateNeighborsOnDisk(Relation index, FmgrInfo *procinfo, Oid collation, Hns
|
|||||||
Buffer buf;
|
Buffer buf;
|
||||||
Page page;
|
Page page;
|
||||||
GenericXLogState *state;
|
GenericXLogState *state;
|
||||||
|
ItemId itemid;
|
||||||
HnswNeighborTuple ntup;
|
HnswNeighborTuple ntup;
|
||||||
|
Size ntupSize;
|
||||||
int idx = -1;
|
int idx = -1;
|
||||||
int startIdx;
|
int startIdx;
|
||||||
HnswElement neighborElement = HnswPtrAccess(base, hc->element);
|
HnswElement neighborElement = HnswPtrAccess(base, hc->element);
|
||||||
@@ -394,7 +396,9 @@ HnswUpdateNeighborsOnDisk(Relation index, FmgrInfo *procinfo, Oid collation, Hns
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get tuple */
|
/* Get tuple */
|
||||||
ntup = (HnswNeighborTuple) PageGetItem(page, PageGetItemId(page, offno));
|
itemid = PageGetItemId(page, offno);
|
||||||
|
ntup = (HnswNeighborTuple) PageGetItem(page, itemid);
|
||||||
|
ntupSize = ItemIdGetLength(itemid);
|
||||||
|
|
||||||
/* Calculate index for update */
|
/* Calculate index for update */
|
||||||
startIdx = (neighborElement->level - lc) * m;
|
startIdx = (neighborElement->level - lc) * m;
|
||||||
@@ -423,9 +427,13 @@ HnswUpdateNeighborsOnDisk(Relation index, FmgrInfo *procinfo, Oid collation, Hns
|
|||||||
{
|
{
|
||||||
ItemPointer indextid = &ntup->indextids[idx];
|
ItemPointer indextid = &ntup->indextids[idx];
|
||||||
|
|
||||||
/* Update neighbor on the buffer */
|
/* Update neighbor */
|
||||||
ItemPointerSet(indextid, e->blkno, e->offno);
|
ItemPointerSet(indextid, e->blkno, e->offno);
|
||||||
|
|
||||||
|
/* Overwrite tuple */
|
||||||
|
if (!PageIndexTupleOverwrite(page, offno, (Item) ntup, ntupSize))
|
||||||
|
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
||||||
|
|
||||||
/* Commit */
|
/* Commit */
|
||||||
if (building)
|
if (building)
|
||||||
MarkBufferDirty(buf);
|
MarkBufferDirty(buf);
|
||||||
@@ -449,7 +457,9 @@ AddDuplicateOnDisk(Relation index, HnswElement element, HnswElement dup, bool bu
|
|||||||
Buffer buf;
|
Buffer buf;
|
||||||
Page page;
|
Page page;
|
||||||
GenericXLogState *state;
|
GenericXLogState *state;
|
||||||
|
ItemId itemid;
|
||||||
HnswElementTuple etup;
|
HnswElementTuple etup;
|
||||||
|
Size etupSize;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Read page */
|
/* Read page */
|
||||||
@@ -467,7 +477,9 @@ AddDuplicateOnDisk(Relation index, HnswElement element, HnswElement dup, bool bu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Find space */
|
/* Find space */
|
||||||
etup = (HnswElementTuple) PageGetItem(page, PageGetItemId(page, dup->offno));
|
itemid = PageGetItemId(page, dup->offno);
|
||||||
|
etup = (HnswElementTuple) PageGetItem(page, itemid);
|
||||||
|
etupSize = ItemIdGetLength(itemid);
|
||||||
for (i = 0; i < HNSW_HEAPTIDS; i++)
|
for (i = 0; i < HNSW_HEAPTIDS; i++)
|
||||||
{
|
{
|
||||||
if (!ItemPointerIsValid(&etup->heaptids[i]))
|
if (!ItemPointerIsValid(&etup->heaptids[i]))
|
||||||
@@ -483,9 +495,13 @@ AddDuplicateOnDisk(Relation index, HnswElement element, HnswElement dup, bool bu
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add heap TID, modifying the tuple on the page directly */
|
/* Add heap TID */
|
||||||
etup->heaptids[i] = element->heaptids[0];
|
etup->heaptids[i] = element->heaptids[0];
|
||||||
|
|
||||||
|
/* Overwrite tuple */
|
||||||
|
if (!PageIndexTupleOverwrite(page, dup->offno, (Item) etup, etupSize))
|
||||||
|
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
||||||
|
|
||||||
/* Commit */
|
/* Commit */
|
||||||
if (building)
|
if (building)
|
||||||
MarkBufferDirty(buf);
|
MarkBufferDirty(buf);
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ RemoveHeapTids(HnswVacuumState * vacuumstate)
|
|||||||
/* Iterate over nodes */
|
/* Iterate over nodes */
|
||||||
for (offno = FirstOffsetNumber; offno <= maxoffno; offno = OffsetNumberNext(offno))
|
for (offno = FirstOffsetNumber; offno <= maxoffno; offno = OffsetNumberNext(offno))
|
||||||
{
|
{
|
||||||
HnswElementTuple etup = (HnswElementTuple) PageGetItem(page, PageGetItemId(page, offno));
|
ItemId itemid = PageGetItemId(page, offno);
|
||||||
|
HnswElementTuple etup = (HnswElementTuple) PageGetItem(page, itemid);
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
bool itemUpdated = false;
|
bool itemUpdated = false;
|
||||||
|
|
||||||
@@ -91,10 +92,15 @@ RemoveHeapTids(HnswVacuumState * vacuumstate)
|
|||||||
|
|
||||||
if (itemUpdated)
|
if (itemUpdated)
|
||||||
{
|
{
|
||||||
|
Size etupSize = ItemIdGetLength(itemid);
|
||||||
|
|
||||||
/* Mark rest as invalid */
|
/* Mark rest as invalid */
|
||||||
for (int i = idx; i < HNSW_HEAPTIDS; i++)
|
for (int i = idx; i < HNSW_HEAPTIDS; i++)
|
||||||
ItemPointerSetInvalid(&etup->heaptids[i]);
|
ItemPointerSetInvalid(&etup->heaptids[i]);
|
||||||
|
|
||||||
|
if (!PageIndexTupleOverwrite(page, offno, (Item) etup, etupSize))
|
||||||
|
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
||||||
|
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,8 +198,8 @@ RepairGraphElement(HnswVacuumState * vacuumstate, HnswElement element, HnswEleme
|
|||||||
FmgrInfo *procinfo = vacuumstate->procinfo;
|
FmgrInfo *procinfo = vacuumstate->procinfo;
|
||||||
Oid collation = vacuumstate->collation;
|
Oid collation = vacuumstate->collation;
|
||||||
BufferAccessStrategy bas = vacuumstate->bas;
|
BufferAccessStrategy bas = vacuumstate->bas;
|
||||||
HnswNeighborTuple ntup = vacuumstate->ntup;
|
ItemId itemid;
|
||||||
Size ntupSize = HNSW_NEIGHBOR_TUPLE_SIZE(element->level, m);
|
HnswNeighborTuple ntup;
|
||||||
char *base = NULL;
|
char *base = NULL;
|
||||||
|
|
||||||
/* Skip if element is entry point */
|
/* Skip if element is entry point */
|
||||||
@@ -207,23 +213,23 @@ RepairGraphElement(HnswVacuumState * vacuumstate, HnswElement element, HnswEleme
|
|||||||
/* Find neighbors for element, skipping itself */
|
/* Find neighbors for element, skipping itself */
|
||||||
HnswFindElementNeighbors(base, element, entryPoint, index, procinfo, collation, m, efConstruction, true);
|
HnswFindElementNeighbors(base, element, entryPoint, index, procinfo, collation, m, efConstruction, true);
|
||||||
|
|
||||||
/* Zero memory for each element */
|
|
||||||
MemSet(ntup, 0, HNSW_TUPLE_ALLOC_SIZE);
|
|
||||||
|
|
||||||
/* Update neighbor tuple */
|
|
||||||
/* Do this before getting page to minimize locking */
|
|
||||||
HnswSetNeighborTuple(base, ntup, element, m);
|
|
||||||
|
|
||||||
/* Get neighbor page */
|
/* Get neighbor page */
|
||||||
buf = ReadBufferExtended(index, MAIN_FORKNUM, element->neighborPage, RBM_NORMAL, bas);
|
buf = ReadBufferExtended(index, MAIN_FORKNUM, element->neighborPage, RBM_NORMAL, bas);
|
||||||
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
|
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
|
||||||
state = GenericXLogStart(index);
|
state = GenericXLogStart(index);
|
||||||
page = GenericXLogRegisterBuffer(state, buf, 0);
|
page = GenericXLogRegisterBuffer(state, buf, 0);
|
||||||
|
|
||||||
/* Overwrite tuple */
|
/* Get neighbor tuple */
|
||||||
if (!PageIndexTupleOverwrite(page, element->neighborOffno, (Item) ntup, ntupSize))
|
itemid = PageGetItemId(page, element->neighborOffno);
|
||||||
|
ntup = (HnswNeighborTuple) PageGetItem(page, itemid);
|
||||||
|
|
||||||
|
/* Check expected size */
|
||||||
|
if (ItemIdGetLength(itemid) != HNSW_NEIGHBOR_TUPLE_SIZE(element->level, m))
|
||||||
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
||||||
|
|
||||||
|
/* Update page in-place */
|
||||||
|
HnswSetNeighborTuple(base, ntup, element, m);
|
||||||
|
|
||||||
/* Commit */
|
/* Commit */
|
||||||
GenericXLogFinish(state);
|
GenericXLogFinish(state);
|
||||||
UnlockReleaseBuffer(buf);
|
UnlockReleaseBuffer(buf);
|
||||||
@@ -476,8 +482,11 @@ MarkDeleted(HnswVacuumState * vacuumstate)
|
|||||||
/* Update element and neighbors together */
|
/* Update element and neighbors together */
|
||||||
for (offno = FirstOffsetNumber; offno <= maxoffno; offno = OffsetNumberNext(offno))
|
for (offno = FirstOffsetNumber; offno <= maxoffno; offno = OffsetNumberNext(offno))
|
||||||
{
|
{
|
||||||
HnswElementTuple etup = (HnswElementTuple) PageGetItem(page, PageGetItemId(page, offno));
|
ItemId itemid = PageGetItemId(page, offno);
|
||||||
|
HnswElementTuple etup = (HnswElementTuple) PageGetItem(page, itemid);
|
||||||
HnswNeighborTuple ntup;
|
HnswNeighborTuple ntup;
|
||||||
|
Size etupSize;
|
||||||
|
Size ntupSize;
|
||||||
Buffer nbuf;
|
Buffer nbuf;
|
||||||
Page npage;
|
Page npage;
|
||||||
BlockNumber neighborPage;
|
BlockNumber neighborPage;
|
||||||
@@ -501,6 +510,10 @@ MarkDeleted(HnswVacuumState * vacuumstate)
|
|||||||
if (ItemPointerIsValid(&etup->heaptids[0]))
|
if (ItemPointerIsValid(&etup->heaptids[0]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Calculate sizes */
|
||||||
|
etupSize = ItemIdGetLength(itemid);
|
||||||
|
ntupSize = HNSW_NEIGHBOR_TUPLE_SIZE(etup->level, vacuumstate->m);
|
||||||
|
|
||||||
/* Get neighbor page */
|
/* Get neighbor page */
|
||||||
neighborPage = ItemPointerGetBlockNumber(&etup->neighbortid);
|
neighborPage = ItemPointerGetBlockNumber(&etup->neighbortid);
|
||||||
neighborOffno = ItemPointerGetOffsetNumber(&etup->neighbortid);
|
neighborOffno = ItemPointerGetOffsetNumber(&etup->neighbortid);
|
||||||
@@ -527,10 +540,13 @@ MarkDeleted(HnswVacuumState * vacuumstate)
|
|||||||
for (int i = 0; i < ntup->count; i++)
|
for (int i = 0; i < ntup->count; i++)
|
||||||
ItemPointerSetInvalid(&ntup->indextids[i]);
|
ItemPointerSetInvalid(&ntup->indextids[i]);
|
||||||
|
|
||||||
/*
|
/* Overwrite element tuple */
|
||||||
* We modified the tuples in place, no need to call
|
if (!PageIndexTupleOverwrite(page, offno, (Item) etup, etupSize))
|
||||||
* PageIndexTupleOverwrite
|
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
||||||
*/
|
|
||||||
|
/* Overwrite neighbor tuple */
|
||||||
|
if (!PageIndexTupleOverwrite(npage, neighborOffno, (Item) ntup, ntupSize))
|
||||||
|
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
||||||
|
|
||||||
/* Commit */
|
/* Commit */
|
||||||
GenericXLogFinish(state);
|
GenericXLogFinish(state);
|
||||||
@@ -575,7 +591,6 @@ InitVacuumState(HnswVacuumState * vacuumstate, IndexVacuumInfo *info, IndexBulkD
|
|||||||
vacuumstate->bas = GetAccessStrategy(BAS_BULKREAD);
|
vacuumstate->bas = GetAccessStrategy(BAS_BULKREAD);
|
||||||
vacuumstate->procinfo = index_getprocinfo(index, 1, HNSW_DISTANCE_PROC);
|
vacuumstate->procinfo = index_getprocinfo(index, 1, HNSW_DISTANCE_PROC);
|
||||||
vacuumstate->collation = index->rd_indcollation[0];
|
vacuumstate->collation = index->rd_indcollation[0];
|
||||||
vacuumstate->ntup = palloc0(HNSW_TUPLE_ALLOC_SIZE);
|
|
||||||
vacuumstate->tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
|
vacuumstate->tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
|
||||||
"Hnsw vacuum temporary context",
|
"Hnsw vacuum temporary context",
|
||||||
ALLOCSET_DEFAULT_SIZES);
|
ALLOCSET_DEFAULT_SIZES);
|
||||||
@@ -595,7 +610,6 @@ FreeVacuumState(HnswVacuumState * vacuumstate)
|
|||||||
{
|
{
|
||||||
tidhash_destroy(vacuumstate->deleted);
|
tidhash_destroy(vacuumstate->deleted);
|
||||||
FreeAccessStrategy(vacuumstate->bas);
|
FreeAccessStrategy(vacuumstate->bas);
|
||||||
pfree(vacuumstate->ntup);
|
|
||||||
MemoryContextDelete(vacuumstate->tmpCtx);
|
MemoryContextDelete(vacuumstate->tmpCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
30
src/vector.c
30
src/vector.c
@@ -866,10 +866,9 @@ vector_mul(PG_FUNCTION_ARGS)
|
|||||||
int
|
int
|
||||||
vector_cmp_internal(Vector * a, Vector * b)
|
vector_cmp_internal(Vector * a, Vector * b)
|
||||||
{
|
{
|
||||||
int dim = Min(a->dim, b->dim);
|
CheckDims(a, b);
|
||||||
|
|
||||||
/* Check values before dimensions to be consistent with Postgres arrays */
|
for (int i = 0; i < a->dim; i++)
|
||||||
for (int i = 0; i < dim; i++)
|
|
||||||
{
|
{
|
||||||
if (a->x[i] < b->x[i])
|
if (a->x[i] < b->x[i])
|
||||||
return -1;
|
return -1;
|
||||||
@@ -877,13 +876,6 @@ vector_cmp_internal(Vector * a, Vector * b)
|
|||||||
if (a->x[i] > b->x[i])
|
if (a->x[i] > b->x[i])
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a->dim < b->dim)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (a->dim > b->dim)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -897,9 +889,6 @@ vector_lt(PG_FUNCTION_ARGS)
|
|||||||
Vector *a = PG_GETARG_VECTOR_P(0);
|
Vector *a = PG_GETARG_VECTOR_P(0);
|
||||||
Vector *b = PG_GETARG_VECTOR_P(1);
|
Vector *b = PG_GETARG_VECTOR_P(1);
|
||||||
|
|
||||||
/* TODO Remove in 0.7.0 */
|
|
||||||
CheckDims(a, b);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(vector_cmp_internal(a, b) < 0);
|
PG_RETURN_BOOL(vector_cmp_internal(a, b) < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -913,9 +902,6 @@ vector_le(PG_FUNCTION_ARGS)
|
|||||||
Vector *a = PG_GETARG_VECTOR_P(0);
|
Vector *a = PG_GETARG_VECTOR_P(0);
|
||||||
Vector *b = PG_GETARG_VECTOR_P(1);
|
Vector *b = PG_GETARG_VECTOR_P(1);
|
||||||
|
|
||||||
/* TODO Remove in 0.7.0 */
|
|
||||||
CheckDims(a, b);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(vector_cmp_internal(a, b) <= 0);
|
PG_RETURN_BOOL(vector_cmp_internal(a, b) <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -929,9 +915,6 @@ vector_eq(PG_FUNCTION_ARGS)
|
|||||||
Vector *a = PG_GETARG_VECTOR_P(0);
|
Vector *a = PG_GETARG_VECTOR_P(0);
|
||||||
Vector *b = PG_GETARG_VECTOR_P(1);
|
Vector *b = PG_GETARG_VECTOR_P(1);
|
||||||
|
|
||||||
/* TODO Remove in 0.7.0 */
|
|
||||||
CheckDims(a, b);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(vector_cmp_internal(a, b) == 0);
|
PG_RETURN_BOOL(vector_cmp_internal(a, b) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -945,9 +928,6 @@ vector_ne(PG_FUNCTION_ARGS)
|
|||||||
Vector *a = PG_GETARG_VECTOR_P(0);
|
Vector *a = PG_GETARG_VECTOR_P(0);
|
||||||
Vector *b = PG_GETARG_VECTOR_P(1);
|
Vector *b = PG_GETARG_VECTOR_P(1);
|
||||||
|
|
||||||
/* TODO Remove in 0.7.0 */
|
|
||||||
CheckDims(a, b);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(vector_cmp_internal(a, b) != 0);
|
PG_RETURN_BOOL(vector_cmp_internal(a, b) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -961,9 +941,6 @@ vector_ge(PG_FUNCTION_ARGS)
|
|||||||
Vector *a = PG_GETARG_VECTOR_P(0);
|
Vector *a = PG_GETARG_VECTOR_P(0);
|
||||||
Vector *b = PG_GETARG_VECTOR_P(1);
|
Vector *b = PG_GETARG_VECTOR_P(1);
|
||||||
|
|
||||||
/* TODO Remove in 0.7.0 */
|
|
||||||
CheckDims(a, b);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(vector_cmp_internal(a, b) >= 0);
|
PG_RETURN_BOOL(vector_cmp_internal(a, b) >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -977,9 +954,6 @@ vector_gt(PG_FUNCTION_ARGS)
|
|||||||
Vector *a = PG_GETARG_VECTOR_P(0);
|
Vector *a = PG_GETARG_VECTOR_P(0);
|
||||||
Vector *b = PG_GETARG_VECTOR_P(1);
|
Vector *b = PG_GETARG_VECTOR_P(1);
|
||||||
|
|
||||||
/* TODO Remove in 0.7.0 */
|
|
||||||
CheckDims(a, b);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(vector_cmp_internal(a, b) > 0);
|
PG_RETURN_BOOL(vector_cmp_internal(a, b) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,56 +24,6 @@ SELECT '[1e37]'::vector * '[1e37]';
|
|||||||
ERROR: value out of range: overflow
|
ERROR: value out of range: overflow
|
||||||
SELECT '[1e-37]'::vector * '[1e-37]';
|
SELECT '[1e-37]'::vector * '[1e-37]';
|
||||||
ERROR: value out of range: underflow
|
ERROR: value out of range: underflow
|
||||||
SELECT '[1,2,3]'::vector = '[1,2,3]';
|
|
||||||
?column?
|
|
||||||
----------
|
|
||||||
t
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
SELECT '[1,2,3]'::vector = '[1,2]';
|
|
||||||
ERROR: different vector dimensions 3 and 2
|
|
||||||
SELECT vector_cmp('[1,2,3]', '[1,2,3]');
|
|
||||||
vector_cmp
|
|
||||||
------------
|
|
||||||
0
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
SELECT vector_cmp('[1,2,3]', '[0,0,0]');
|
|
||||||
vector_cmp
|
|
||||||
------------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
SELECT vector_cmp('[0,0,0]', '[1,2,3]');
|
|
||||||
vector_cmp
|
|
||||||
------------
|
|
||||||
-1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
SELECT vector_cmp('[1,2]', '[1,2,3]');
|
|
||||||
vector_cmp
|
|
||||||
------------
|
|
||||||
-1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
SELECT vector_cmp('[1,2,3]', '[1,2]');
|
|
||||||
vector_cmp
|
|
||||||
------------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
SELECT vector_cmp('[1,2]', '[2,3,4]');
|
|
||||||
vector_cmp
|
|
||||||
------------
|
|
||||||
-1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
SELECT vector_cmp('[2,3]', '[1,2,3]');
|
|
||||||
vector_cmp
|
|
||||||
------------
|
|
||||||
1
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
SELECT vector_dims('[1,2,3]');
|
SELECT vector_dims('[1,2,3]');
|
||||||
vector_dims
|
vector_dims
|
||||||
-------------
|
-------------
|
||||||
|
|||||||
@@ -6,17 +6,6 @@ SELECT '[1,2,3]'::vector * '[4,5,6]';
|
|||||||
SELECT '[1e37]'::vector * '[1e37]';
|
SELECT '[1e37]'::vector * '[1e37]';
|
||||||
SELECT '[1e-37]'::vector * '[1e-37]';
|
SELECT '[1e-37]'::vector * '[1e-37]';
|
||||||
|
|
||||||
SELECT '[1,2,3]'::vector = '[1,2,3]';
|
|
||||||
SELECT '[1,2,3]'::vector = '[1,2]';
|
|
||||||
|
|
||||||
SELECT vector_cmp('[1,2,3]', '[1,2,3]');
|
|
||||||
SELECT vector_cmp('[1,2,3]', '[0,0,0]');
|
|
||||||
SELECT vector_cmp('[0,0,0]', '[1,2,3]');
|
|
||||||
SELECT vector_cmp('[1,2]', '[1,2,3]');
|
|
||||||
SELECT vector_cmp('[1,2,3]', '[1,2]');
|
|
||||||
SELECT vector_cmp('[1,2]', '[2,3,4]');
|
|
||||||
SELECT vector_cmp('[2,3]', '[1,2,3]');
|
|
||||||
|
|
||||||
SELECT vector_dims('[1,2,3]');
|
SELECT vector_dims('[1,2,3]');
|
||||||
|
|
||||||
SELECT round(vector_norm('[1,1]')::numeric, 5);
|
SELECT round(vector_norm('[1,1]')::numeric, 5);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
comment = 'vector data type and ivfflat and hnsw access methods'
|
comment = 'vector data type and ivfflat and hnsw access methods'
|
||||||
default_version = '0.6.0'
|
default_version = '0.5.1'
|
||||||
module_pathname = '$libdir/vector'
|
module_pathname = '$libdir/vector'
|
||||||
relocatable = true
|
relocatable = true
|
||||||
|
|||||||
Reference in New Issue
Block a user