mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-23 04:20:56 +08:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42c930231a | ||
|
|
2fe560dc58 | ||
|
|
b46beada1a | ||
|
|
0a42bc7aa5 | ||
|
|
f5df32c41d | ||
|
|
2c53c30415 | ||
|
|
b4bc010459 | ||
|
|
7b4ff9b59f | ||
|
|
cfdcbd75d1 | ||
|
|
5136983f35 | ||
|
|
4ab4b89980 | ||
|
|
85f0e3ccf6 | ||
|
|
28e797cb5a | ||
|
|
1263d753be | ||
|
|
5bc7937715 | ||
|
|
e7e899e9af | ||
|
|
2627c5ff77 | ||
|
|
34b3cfdc43 | ||
|
|
cd218aae5a | ||
|
|
ba9367f86c | ||
|
|
9c20550a41 |
103
.github/workflows/build.yml
vendored
103
.github/workflows/build.yml
vendored
@@ -8,18 +8,10 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- postgres: 18
|
||||
os: ubuntu-24.04
|
||||
- postgres: 17
|
||||
os: ubuntu-24.04
|
||||
- postgres: 16
|
||||
os: ubuntu-22.04
|
||||
- postgres: 15
|
||||
os: ubuntu-22.04
|
||||
os: ubuntu-24.04-arm
|
||||
- postgres: 14
|
||||
os: ubuntu-20.04
|
||||
- postgres: 13
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.04-arm
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ankane/setup-postgres@v1
|
||||
@@ -39,94 +31,3 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install libipc-run-perl
|
||||
- run: make prove_installcheck
|
||||
mac:
|
||||
runs-on: ${{ matrix.os }}
|
||||
if: ${{ !startsWith(github.ref_name, 'windows') }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- postgres: 16
|
||||
os: macos-14
|
||||
- postgres: 14
|
||||
os: macos-13
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ankane/setup-postgres@v1
|
||||
with:
|
||||
postgres-version: ${{ matrix.postgres }}
|
||||
- run: make
|
||||
env:
|
||||
PG_CFLAGS: -DUSE_ASSERT_CHECKING -Wall -Wextra -Werror -Wno-unused-parameter
|
||||
- run: make install
|
||||
- run: make installcheck
|
||||
- if: ${{ failure() }}
|
||||
run: cat regression.diffs
|
||||
# Homebrew Postgres does not enable TAP tests, so need to download
|
||||
- run: |
|
||||
brew install cpanm
|
||||
cpanm --notest IPC::Run
|
||||
wget -q https://github.com/postgres/postgres/archive/refs/tags/$TAG.tar.gz
|
||||
tar xf $TAG.tar.gz
|
||||
mv postgres-$TAG postgres
|
||||
env:
|
||||
TAG: ${{ matrix.postgres == 16 && 'REL_16_2' || 'REL_14_11' }}
|
||||
- run: make prove_installcheck PROVE_FLAGS="-I ./postgres/src/test/perl -I ./test/perl"
|
||||
env:
|
||||
PERL5LIB: /Users/runner/perl5/lib/perl5
|
||||
- run: make clean && $(brew --prefix llvm@15)/bin/scan-build --status-bugs make
|
||||
env:
|
||||
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
|
||||
- if: ${{ failure() }}
|
||||
run: cat regression.diffs
|
||||
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: -DUSE_ASSERT_CHECKING -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare
|
||||
- if: ${{ failure() }}
|
||||
run: cat pgvector/regression.diffs
|
||||
valgrind:
|
||||
if: ${{ !startsWith(github.ref_name, 'mac') && !startsWith(github.ref_name, 'windows') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ankane/setup-postgres-valgrind@v1
|
||||
with:
|
||||
postgres-version: 16
|
||||
check-ub: yes
|
||||
- run: make OPTFLAGS=""
|
||||
- run: sudo --preserve-env=PG_CONFIG make install
|
||||
- run: make installcheck
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 0.8.0 (unreleased)
|
||||
## 0.8.0 (2024-10-30)
|
||||
|
||||
- Added support for iterative index scans
|
||||
- Added casts for arrays to `sparsevec`
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
||||
Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
|
||||
|
||||
Portions Copyright (c) 1994, The Regents of the University of California
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "vector",
|
||||
"abstract": "Open-source vector similarity search for Postgres",
|
||||
"description": "Supports L2 distance, inner product, and cosine distance",
|
||||
"version": "0.7.4",
|
||||
"version": "0.8.0",
|
||||
"maintainer": [
|
||||
"Andrew Kane <andrew@ankane.org>"
|
||||
],
|
||||
@@ -12,7 +12,7 @@
|
||||
"prereqs": {
|
||||
"runtime": {
|
||||
"requires": {
|
||||
"PostgreSQL": "12.0.0"
|
||||
"PostgreSQL": "13.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -20,7 +20,7 @@
|
||||
"vector": {
|
||||
"file": "sql/vector.sql",
|
||||
"docfile": "README.md",
|
||||
"version": "0.7.4",
|
||||
"version": "0.8.0",
|
||||
"abstract": "Open-source vector similarity search for Postgres"
|
||||
}
|
||||
},
|
||||
|
||||
2
Makefile
2
Makefile
@@ -1,5 +1,5 @@
|
||||
EXTENSION = vector
|
||||
EXTVERSION = 0.7.4
|
||||
EXTVERSION = 0.8.0
|
||||
|
||||
MODULE_big = vector
|
||||
DATA = $(wildcard sql/*--*--*.sql)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
EXTENSION = vector
|
||||
EXTVERSION = 0.7.4
|
||||
EXTVERSION = 0.8.0
|
||||
|
||||
DATA_built = sql\$(EXTENSION)--$(EXTVERSION).sql
|
||||
OBJS = src\bitutils.obj src\bitvec.obj src\halfutils.obj src\halfvec.obj 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\sparsevec.obj src\vector.obj
|
||||
|
||||
27
README.md
27
README.md
@@ -17,11 +17,11 @@ Plus [ACID](https://en.wikipedia.org/wiki/ACID) compliance, point-in-time recove
|
||||
|
||||
### Linux and Mac
|
||||
|
||||
Compile and install the extension (supports Postgres 12+)
|
||||
Compile and install the extension (supports Postgres 13+)
|
||||
|
||||
```sh
|
||||
cd /tmp
|
||||
git clone --branch v0.7.4 https://github.com/pgvector/pgvector.git
|
||||
git clone --branch v0.8.0 https://github.com/pgvector/pgvector.git
|
||||
cd pgvector
|
||||
make
|
||||
make install # may need sudo
|
||||
@@ -46,13 +46,13 @@ Then use `nmake` to build:
|
||||
```cmd
|
||||
set "PGROOT=C:\Program Files\PostgreSQL\16"
|
||||
cd %TEMP%
|
||||
git clone --branch v0.7.4 https://github.com/pgvector/pgvector.git
|
||||
git clone --branch v0.8.0 https://github.com/pgvector/pgvector.git
|
||||
cd pgvector
|
||||
nmake /F Makefile.win
|
||||
nmake /F Makefile.win install
|
||||
```
|
||||
|
||||
Note: Postgres 17 is not supported yet due to an upstream issue
|
||||
Note: Postgres 17 is not supported with MSVC yet due to an [upstream issue](https://www.postgresql.org/message-id/flat/CAOdR5yF0krWrxycA04rgUKCgKugRvGWzzGLAhDZ9bzNv8g0Lag%40mail.gmail.com)
|
||||
|
||||
See the [installation notes](#installation-notes---windows) if you run into issues
|
||||
|
||||
@@ -324,7 +324,7 @@ For a large number of workers, you may also need to increase `max_parallel_worke
|
||||
|
||||
### Indexing Progress
|
||||
|
||||
Check [indexing progress](https://www.postgresql.org/docs/current/progress-reporting.html#CREATE-INDEX-PROGRESS-REPORTING) with Postgres 12+
|
||||
Check [indexing progress](https://www.postgresql.org/docs/current/progress-reporting.html#CREATE-INDEX-PROGRESS-REPORTING)
|
||||
|
||||
```sql
|
||||
SELECT phase, round(100.0 * blocks_done / nullif(blocks_total, 0), 1) AS "%" FROM pg_stat_progress_create_index;
|
||||
@@ -410,7 +410,7 @@ For a large number of workers, you may also need to increase `max_parallel_worke
|
||||
|
||||
### Indexing Progress
|
||||
|
||||
Check [indexing progress](https://www.postgresql.org/docs/current/progress-reporting.html#CREATE-INDEX-PROGRESS-REPORTING) with Postgres 12+
|
||||
Check [indexing progress](https://www.postgresql.org/docs/current/progress-reporting.html#CREATE-INDEX-PROGRESS-REPORTING)
|
||||
|
||||
```sql
|
||||
SELECT phase, round(100.0 * tuples_done / nullif(tuples_total, 0), 1) AS "%" FROM pg_stat_progress_create_index;
|
||||
@@ -477,7 +477,7 @@ CREATE TABLE items (embedding vector(3), category_id int) PARTITION BY LIST(cate
|
||||
|
||||
## Iterative Index Scans
|
||||
|
||||
*Unreleased*
|
||||
*Added in 0.8.0*
|
||||
|
||||
With approximate indexes, queries with filtering can return less results since filtering is applied *after* the index is scanned. Starting with 0.8.0, you can enable iterative index scans, which will automatically scan more of the index until enough results are found (or it reaches `hnsw.max_scan_tuples` or `ivfflat.max_probes`).
|
||||
|
||||
@@ -801,8 +801,12 @@ C | [pgvector-c](https://github.com/pgvector/pgvector-c)
|
||||
C++ | [pgvector-cpp](https://github.com/pgvector/pgvector-cpp)
|
||||
C#, F#, Visual Basic | [pgvector-dotnet](https://github.com/pgvector/pgvector-dotnet)
|
||||
Crystal | [pgvector-crystal](https://github.com/pgvector/pgvector-crystal)
|
||||
D | [pgvector-d](https://github.com/pgvector/pgvector-d)
|
||||
Dart | [pgvector-dart](https://github.com/pgvector/pgvector-dart)
|
||||
Elixir | [pgvector-elixir](https://github.com/pgvector/pgvector-elixir)
|
||||
Erlang | [pgvector-erlang](https://github.com/pgvector/pgvector-erlang)
|
||||
Fortran | [pgvector-fortran](https://github.com/pgvector/pgvector-fortran)
|
||||
Gleam | [pgvector-gleam](https://github.com/pgvector/pgvector-gleam)
|
||||
Go | [pgvector-go](https://github.com/pgvector/pgvector-go)
|
||||
Haskell | [pgvector-haskell](https://github.com/pgvector/pgvector-haskell)
|
||||
Java, Kotlin, Groovy, Scala | [pgvector-java](https://github.com/pgvector/pgvector-java)
|
||||
@@ -816,6 +820,7 @@ Perl | [pgvector-perl](https://github.com/pgvector/pgvector-perl)
|
||||
PHP | [pgvector-php](https://github.com/pgvector/pgvector-php)
|
||||
Python | [pgvector-python](https://github.com/pgvector/pgvector-python)
|
||||
R | [pgvector-r](https://github.com/pgvector/pgvector-r)
|
||||
Raku | [pgvector-raku](https://github.com/pgvector/pgvector-raku)
|
||||
Ruby | [pgvector-ruby](https://github.com/pgvector/pgvector-ruby), [Neighbor](https://github.com/ankane/neighbor)
|
||||
Rust | [pgvector-rust](https://github.com/pgvector/pgvector-rust)
|
||||
Swift | [pgvector-swift](https://github.com/pgvector/pgvector-swift)
|
||||
@@ -937,7 +942,7 @@ ALTER TABLE items ALTER COLUMN embedding SET STORAGE PLAIN;
|
||||
|
||||
#### Why are there less results for a query after adding an HNSW index?
|
||||
|
||||
Results are limited by the size of the dynamic candidate list (`hnsw.ef_search`). There may be even less results due to dead tuples or filtering conditions in the query. We recommend setting `hnsw.ef_search` to at least twice the `LIMIT` of the query. If you need more than 500 results, use an IVFFlat index instead.
|
||||
Results are limited by the size of the dynamic candidate list (`hnsw.ef_search`), which is 40 by default. There may be even less results due to dead tuples or filtering conditions in the query. Enabling [iterative index scans](#iterative-index-scans) can help address this.
|
||||
|
||||
Also, note that `NULL` vectors are not indexed (as well as zero vectors for cosine distance).
|
||||
|
||||
@@ -949,7 +954,7 @@ The index was likely created with too little data for the number of lists. Drop
|
||||
DROP INDEX index_name;
|
||||
```
|
||||
|
||||
Results can also be limited by the number of probes (`ivfflat.probes`).
|
||||
Results can also be limited by the number of probes (`ivfflat.probes`). Enabling [iterative index scans](#iterative-index-scans) can address this.
|
||||
|
||||
Also, note that `NULL` vectors are not indexed (as well as zero vectors for cosine distance).
|
||||
|
||||
@@ -1153,7 +1158,7 @@ This adds pgvector to the [Postgres image](https://hub.docker.com/_/postgres) (r
|
||||
You can also build the image manually:
|
||||
|
||||
```sh
|
||||
git clone --branch v0.7.4 https://github.com/pgvector/pgvector.git
|
||||
git clone --branch v0.8.0 https://github.com/pgvector/pgvector.git
|
||||
cd pgvector
|
||||
docker build --pull --build-arg PG_MAJOR=17 -t myuser/pgvector .
|
||||
```
|
||||
@@ -1203,7 +1208,7 @@ Note: Replace `17` with your Postgres server version
|
||||
Install the FreeBSD package with:
|
||||
|
||||
```sh
|
||||
pkg install postgresql15-pgvector
|
||||
pkg install postgresql16-pgvector
|
||||
```
|
||||
|
||||
or the port with:
|
||||
|
||||
@@ -126,7 +126,7 @@ typedef struct HnswNeighborArray HnswNeighborArray;
|
||||
|
||||
#define HnswPtrDeclare(type, relptrtype, ptrtype) \
|
||||
relptr_declare(type, relptrtype); \
|
||||
typedef union { type *ptr; relptrtype relptr; } ptrtype;
|
||||
typedef union { type *ptr; relptrtype relptr; } ptrtype
|
||||
|
||||
/* Pointers that can be absolute or relative */
|
||||
/* Use char for DatumPtr so works with Pointer */
|
||||
|
||||
@@ -722,8 +722,6 @@ CountElement(HnswElement skipElement, HnswElement e)
|
||||
static void
|
||||
HnswLoadUnvisitedFromMemory(char *base, HnswElement element, HnswUnvisited * unvisited, int *unvisitedLength, visited_hash * v, int lc, HnswNeighborArray * localNeighborhood, Size neighborhoodSize)
|
||||
{
|
||||
uint32 hashes[HNSW_MAX_M * 2];
|
||||
|
||||
/* Get the neighborhood at layer lc */
|
||||
HnswNeighborArray *neighborhood = HnswGetNeighbors(base, element, lc);
|
||||
|
||||
@@ -735,33 +733,14 @@ HnswLoadUnvisitedFromMemory(char *base, HnswElement element, HnswUnvisited * unv
|
||||
*unvisitedLength = 0;
|
||||
|
||||
for (int i = 0; i < localNeighborhood->length; i++)
|
||||
hashes[i] = HnswPtrAccess(base, localNeighborhood->items[i].element)->hash;
|
||||
|
||||
if (base != NULL)
|
||||
{
|
||||
for (int i = 0; i < localNeighborhood->length; i++)
|
||||
{
|
||||
HnswCandidate *hc = &localNeighborhood->items[i];
|
||||
bool found;
|
||||
HnswCandidate *hc = &localNeighborhood->items[i];
|
||||
bool found;
|
||||
|
||||
offsethash_insert_hash(v->offsets, HnswPtrOffset(hc->element), hashes[i], &found);
|
||||
AddToVisited(base, v, hc->element, true, &found);
|
||||
|
||||
if (!found)
|
||||
unvisited[(*unvisitedLength)++].element = HnswPtrAccess(base, hc->element);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < localNeighborhood->length; i++)
|
||||
{
|
||||
HnswCandidate *hc = &localNeighborhood->items[i];
|
||||
bool found;
|
||||
|
||||
pointerhash_insert_hash(v->pointers, (uintptr_t) HnswPtrPointer(hc->element), hashes[i], &found);
|
||||
|
||||
if (!found)
|
||||
unvisited[(*unvisitedLength)++].element = HnswPtrAccess(base, hc->element);
|
||||
}
|
||||
if (!found)
|
||||
unvisited[(*unvisitedLength)++].element = HnswPtrAccess(base, hc->element);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1414,7 +1393,7 @@ hnsw_halfvec_support(PG_FUNCTION_ARGS)
|
||||
};
|
||||
|
||||
PG_RETURN_POINTER(&typeInfo);
|
||||
};
|
||||
}
|
||||
|
||||
FUNCTION_PREFIX PG_FUNCTION_INFO_V1(hnsw_bit_support);
|
||||
Datum
|
||||
@@ -1427,7 +1406,7 @@ hnsw_bit_support(PG_FUNCTION_ARGS)
|
||||
};
|
||||
|
||||
PG_RETURN_POINTER(&typeInfo);
|
||||
};
|
||||
}
|
||||
|
||||
FUNCTION_PREFIX PG_FUNCTION_INFO_V1(hnsw_sparsevec_support);
|
||||
Datum
|
||||
@@ -1440,4 +1419,4 @@ hnsw_sparsevec_support(PG_FUNCTION_ARGS)
|
||||
};
|
||||
|
||||
PG_RETURN_POINTER(&typeInfo);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ InitBuildState(IvfflatBuildState * buildstate, Relation heap, Relation index, In
|
||||
buildstate->sortdesc = CreateTemplateTupleDesc(3);
|
||||
TupleDescInitEntry(buildstate->sortdesc, (AttrNumber) 1, "list", INT4OID, -1, 0);
|
||||
TupleDescInitEntry(buildstate->sortdesc, (AttrNumber) 2, "tid", TIDOID, -1, 0);
|
||||
TupleDescInitEntry(buildstate->sortdesc, (AttrNumber) 3, "vector", buildstate->tupdesc->attrs[0].atttypid, -1, 0);
|
||||
TupleDescInitEntry(buildstate->sortdesc, (AttrNumber) 3, "vector", TupleDescAttr(buildstate->tupdesc, 0)->atttypid, -1, 0);
|
||||
|
||||
buildstate->slot = MakeSingleTupleTableSlot(buildstate->sortdesc, &TTSOpsVirtual);
|
||||
|
||||
|
||||
@@ -355,7 +355,7 @@ ivfflat_halfvec_support(PG_FUNCTION_ARGS)
|
||||
};
|
||||
|
||||
PG_RETURN_POINTER(&typeInfo);
|
||||
};
|
||||
}
|
||||
|
||||
FUNCTION_PREFIX PG_FUNCTION_INFO_V1(ivfflat_bit_support);
|
||||
Datum
|
||||
@@ -370,4 +370,4 @@ ivfflat_bit_support(PG_FUNCTION_ARGS)
|
||||
};
|
||||
|
||||
PG_RETURN_POINTER(&typeInfo);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "catalog/pg_type.h"
|
||||
#include "common/shortest_dec.h"
|
||||
#include "common/string.h"
|
||||
#include "fmgr.h"
|
||||
#include "halfutils.h"
|
||||
@@ -12,17 +13,10 @@
|
||||
#include "sparsevec.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/float.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "vector.h"
|
||||
|
||||
#if PG_VERSION_NUM >= 120000
|
||||
#include "common/shortest_dec.h"
|
||||
#include "utils/float.h"
|
||||
#else
|
||||
#include <float.h>
|
||||
#include "utils/builtins.h"
|
||||
#endif
|
||||
|
||||
typedef struct SparseInputElement
|
||||
{
|
||||
int32 index;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
comment = 'vector data type and ivfflat and hnsw access methods'
|
||||
default_version = '0.7.4'
|
||||
default_version = '0.8.0'
|
||||
module_pathname = '$libdir/vector'
|
||||
relocatable = true
|
||||
|
||||
Reference in New Issue
Block a user