mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-22 20:15:46 +08:00
Compare commits
45 Commits
half-dispa
...
valgrind-s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b0443afdf | ||
|
|
b609c343b4 | ||
|
|
bbfb3f200a | ||
|
|
99d367edc0 | ||
|
|
991743786a | ||
|
|
60ceaea4f2 | ||
|
|
9cd789fe06 | ||
|
|
0da6213a60 | ||
|
|
d1b83991af | ||
|
|
6c247a38d3 | ||
|
|
6639cde19d | ||
|
|
bd409f0c6a | ||
|
|
1994fd003a | ||
|
|
bd62561a19 | ||
|
|
f14c21748b | ||
|
|
2b77005610 | ||
|
|
e884b3aa69 | ||
|
|
ab71c12a28 | ||
|
|
1804c63e27 | ||
|
|
4e6aa2f0c1 | ||
|
|
40e86251c3 | ||
|
|
0c9ae4b187 | ||
|
|
d83af48e70 | ||
|
|
b2f7dad8a7 | ||
|
|
881fbc15ef | ||
|
|
f9941c2992 | ||
|
|
f9c071a761 | ||
|
|
9f4b770db3 | ||
|
|
70b299a7ff | ||
|
|
d46d014234 | ||
|
|
655adc535a | ||
|
|
47f0a5e9ac | ||
|
|
af9d50481d | ||
|
|
6dad8460a6 | ||
|
|
ed4837cc4f | ||
|
|
3df5655b30 | ||
|
|
e4c4ac9648 | ||
|
|
fb77671d05 | ||
|
|
fd4fbd238c | ||
|
|
4e093f95be | ||
|
|
fb3c964ac2 | ||
|
|
0b938f8328 | ||
|
|
6153e173f3 | ||
|
|
eb48b9eec4 | ||
|
|
fb6af03361 |
118
.github/workflows/build.yml
vendored
118
.github/workflows/build.yml
vendored
@@ -1,122 +1,6 @@
|
|||||||
name: build
|
name: build
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
jobs:
|
jobs:
|
||||||
ubuntu:
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
if: ${{ !startsWith(github.ref_name, 'mac') && !startsWith(github.ref_name, 'windows') }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- postgres: 17
|
|
||||||
os: ubuntu-22.04
|
|
||||||
- postgres: 16
|
|
||||||
os: ubuntu-22.04
|
|
||||||
- postgres: 15
|
|
||||||
os: ubuntu-22.04
|
|
||||||
- postgres: 14
|
|
||||||
os: ubuntu-22.04
|
|
||||||
- postgres: 13
|
|
||||||
os: ubuntu-20.04
|
|
||||||
- postgres: 12
|
|
||||||
os: ubuntu-20.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: ankane/setup-postgres@v1
|
|
||||||
with:
|
|
||||||
postgres-version: ${{ matrix.postgres }}
|
|
||||||
dev-files: true
|
|
||||||
- run: make
|
|
||||||
env:
|
|
||||||
PG_CFLAGS: -DUSE_ASSERT_CHECKING -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare
|
|
||||||
- run: |
|
|
||||||
export PG_CONFIG=`which pg_config`
|
|
||||||
sudo --preserve-env=PG_CONFIG make install
|
|
||||||
- run: make installcheck
|
|
||||||
- if: ${{ failure() }}
|
|
||||||
run: cat regression.diffs
|
|
||||||
- run: |
|
|
||||||
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-12
|
|
||||||
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" && ^
|
|
||||||
cd %TEMP% && ^
|
|
||||||
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: -DUSE_ASSERT_CHECKING -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare
|
|
||||||
- if: ${{ failure() }}
|
|
||||||
run: cat pgvector/regression.diffs
|
|
||||||
valgrind:
|
valgrind:
|
||||||
if: ${{ !startsWith(github.ref_name, 'mac') && !startsWith(github.ref_name, 'windows') }}
|
if: ${{ !startsWith(github.ref_name, 'mac') && !startsWith(github.ref_name, 'windows') }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -128,4 +12,4 @@ jobs:
|
|||||||
check-ub: yes
|
check-ub: yes
|
||||||
- run: make OPTFLAGS=""
|
- run: make OPTFLAGS=""
|
||||||
- run: sudo --preserve-env=PG_CONFIG make install
|
- run: sudo --preserve-env=PG_CONFIG make install
|
||||||
- run: make installcheck
|
- run: make prove_installcheck PROVE_TESTS=test/t/031_hnsw_sparsevec_vacuum_recall.pl
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
- Added `halfvec` type
|
- Added `halfvec` type
|
||||||
- Added `sparsevec` type
|
- Added `sparsevec` type
|
||||||
- Added support for indexing `bit` type
|
- Added support for indexing `bit` type
|
||||||
|
- Added support for indexing L1 distance with HNSW
|
||||||
- Added `binary_quantize` function
|
- Added `binary_quantize` function
|
||||||
- Added `hamming_distance` function
|
- Added `hamming_distance` function
|
||||||
- Added `jaccard_distance` function
|
- Added `jaccard_distance` function
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -3,7 +3,7 @@ EXTVERSION = 0.6.2
|
|||||||
|
|
||||||
MODULE_big = vector
|
MODULE_big = vector
|
||||||
DATA = $(wildcard sql/*--*.sql)
|
DATA = $(wildcard sql/*--*.sql)
|
||||||
OBJS = src/bitvector.o src/halfutils.o src/halfvec.o src/hnsw.o src/hnswbuild.o src/hnswinsert.o src/hnswscan.o src/hnswutils.o src/hnswvacuum.o src/ivfbuild.o src/ivfflat.o src/ivfinsert.o src/ivfkmeans.o src/ivfscan.o src/ivfutils.o src/ivfvacuum.o src/sparsevec.o src/vector.o
|
OBJS = src/bitutils.o src/bitvec.o src/halfutils.o src/halfvec.o src/hnsw.o src/hnswbuild.o src/hnswinsert.o src/hnswscan.o src/hnswutils.o src/hnswvacuum.o src/ivfbuild.o src/ivfflat.o src/ivfinsert.o src/ivfkmeans.o src/ivfscan.o src/ivfutils.o src/ivfvacuum.o src/sparsevec.o src/vector.o
|
||||||
HEADERS = src/halfvec.h src/sparsevec.h src/vector.h
|
HEADERS = src/halfvec.h src/sparsevec.h src/vector.h
|
||||||
|
|
||||||
TESTS = $(wildcard test/sql/*.sql)
|
TESTS = $(wildcard test/sql/*.sql)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
EXTENSION = vector
|
EXTENSION = vector
|
||||||
EXTVERSION = 0.6.2
|
EXTVERSION = 0.6.2
|
||||||
|
|
||||||
OBJS = src\bitvector.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
|
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
|
||||||
HEADERS = src\halfvec.h src\sparsevec.h src\vector.h
|
HEADERS = src\halfvec.h src\sparsevec.h src\vector.h
|
||||||
|
|
||||||
REGRESS = bit_functions btree_halfvec btree_sparsevec btree_vector cast copy halfvec_functions halfvec_input hnsw_bit_hamming hnsw_bit_jaccard hnsw_halfvec_cosine hnsw_halfvec_ip hnsw_halfvec_l2 hnsw_options hnsw_sparsevec_cosine hnsw_sparsevec_ip hnsw_sparsevec_l2 hnsw_unlogged hnsw_vector_cosine hnsw_vector_ip hnsw_vector_l2 ivfflat_halfvec_cosine ivfflat_halfvec_ip ivfflat_halfvec_l2 ivfflat_options ivfflat_unlogged ivfflat_vector_cosine ivfflat_vector_ip ivfflat_vector_l2 sparsevec_functions sparsevec_input vector_functions vector_input
|
REGRESS = bit_functions btree_halfvec btree_sparsevec btree_vector cast copy halfvec_functions halfvec_input hnsw_bit_hamming hnsw_bit_jaccard hnsw_halfvec_cosine hnsw_halfvec_ip hnsw_halfvec_l2 hnsw_options hnsw_sparsevec_cosine hnsw_sparsevec_ip hnsw_sparsevec_l2 hnsw_unlogged hnsw_vector_cosine hnsw_vector_ip hnsw_vector_l2 ivfflat_halfvec_cosine ivfflat_halfvec_ip ivfflat_halfvec_l2 ivfflat_options ivfflat_unlogged ivfflat_vector_cosine ivfflat_vector_ip ivfflat_vector_l2 sparsevec_functions sparsevec_input vector_functions vector_input
|
||||||
|
|||||||
20
README.md
20
README.md
@@ -81,7 +81,7 @@ Get the nearest neighbors by L2 distance
|
|||||||
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
|
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
|
||||||
```
|
```
|
||||||
|
|
||||||
Also supports inner product (`<#>`) and cosine distance (`<=>`)
|
Also supports inner product (`<#>`), cosine distance (`<=>`), and L1 distance (`<+>`, unreleased)
|
||||||
|
|
||||||
Note: `<#>` returns the negative inner product since Postgres only supports `ASC` order index scans on operators
|
Note: `<#>` returns the negative inner product since Postgres only supports `ASC` order index scans on operators
|
||||||
|
|
||||||
@@ -143,6 +143,7 @@ Supported distance functions are:
|
|||||||
- `<->` - L2 distance
|
- `<->` - L2 distance
|
||||||
- `<#>` - (negative) inner product
|
- `<#>` - (negative) inner product
|
||||||
- `<=>` - cosine distance
|
- `<=>` - cosine distance
|
||||||
|
- `<+>` - L1 distance (unreleased)
|
||||||
|
|
||||||
Get the nearest neighbors to a row
|
Get the nearest neighbors to a row
|
||||||
|
|
||||||
@@ -227,6 +228,12 @@ Cosine distance
|
|||||||
CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);
|
CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
L1 distance - unreleased
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE INDEX ON items USING hnsw (embedding vector_l1_ops);
|
||||||
|
```
|
||||||
|
|
||||||
Hamming distance - unreleased
|
Hamming distance - unreleased
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
@@ -349,6 +356,12 @@ Cosine distance
|
|||||||
CREATE INDEX ON items USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
|
CREATE INDEX ON items USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Hamming distance - unreleased
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE INDEX ON items USING ivfflat (embedding bit_hamming_ops) WITH (lists = 100);
|
||||||
|
```
|
||||||
|
|
||||||
Supported types are:
|
Supported types are:
|
||||||
|
|
||||||
- `vector` - up to 2,000 dimensions
|
- `vector` - up to 2,000 dimensions
|
||||||
@@ -535,7 +548,7 @@ SELECT id, content FROM items, plainto_tsquery('hello search') query
|
|||||||
|
|
||||||
You can use [Reciprocal Rank Fusion](https://github.com/pgvector/pgvector-python/blob/master/examples/hybrid_search_rrf.py) or a [cross-encoder](https://github.com/pgvector/pgvector-python/blob/master/examples/hybrid_search.py) to combine results.
|
You can use [Reciprocal Rank Fusion](https://github.com/pgvector/pgvector-python/blob/master/examples/hybrid_search_rrf.py) or a [cross-encoder](https://github.com/pgvector/pgvector-python/blob/master/examples/hybrid_search.py) to combine results.
|
||||||
|
|
||||||
## Subvector Indexing
|
## Indexing Subvectors
|
||||||
|
|
||||||
*Unreleased*
|
*Unreleased*
|
||||||
|
|
||||||
@@ -855,6 +868,7 @@ Operator | Description | Added
|
|||||||
<-> | Euclidean distance |
|
<-> | Euclidean distance |
|
||||||
<#> | negative inner product |
|
<#> | negative inner product |
|
||||||
<=> | cosine distance |
|
<=> | cosine distance |
|
||||||
|
<+> | taxicab distance | unreleased
|
||||||
|
|
||||||
### Vector Functions
|
### Vector Functions
|
||||||
|
|
||||||
@@ -892,6 +906,7 @@ Operator | Description | Added
|
|||||||
<-> | Euclidean distance | unreleased
|
<-> | Euclidean distance | unreleased
|
||||||
<#> | negative inner product | unreleased
|
<#> | negative inner product | unreleased
|
||||||
<=> | cosine distance | unreleased
|
<=> | cosine distance | unreleased
|
||||||
|
<+> | taxicab distance | unreleased
|
||||||
|
|
||||||
### Halfvec Functions
|
### Halfvec Functions
|
||||||
|
|
||||||
@@ -943,6 +958,7 @@ Operator | Description | Added
|
|||||||
<-> | Euclidean distance | unreleased
|
<-> | Euclidean distance | unreleased
|
||||||
<#> | negative inner product | unreleased
|
<#> | negative inner product | unreleased
|
||||||
<=> | cosine distance | unreleased
|
<=> | cosine distance | unreleased
|
||||||
|
<+> | taxicab distance | unreleased
|
||||||
|
|
||||||
### Sparsevec Functions
|
### Sparsevec Functions
|
||||||
|
|
||||||
|
|||||||
@@ -13,16 +13,32 @@ CREATE FUNCTION subvector(vector, int, int) RETURNS vector
|
|||||||
CREATE FUNCTION vector_concat(vector, vector) RETURNS vector
|
CREATE FUNCTION vector_concat(vector, vector) RETURNS vector
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE OPERATOR <+> (
|
||||||
|
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = l1_distance,
|
||||||
|
COMMUTATOR = '<+>'
|
||||||
|
);
|
||||||
|
|
||||||
CREATE OPERATOR || (
|
CREATE OPERATOR || (
|
||||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_concat
|
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_concat
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE OPERATOR CLASS vector_l1_ops
|
||||||
|
FOR TYPE vector USING hnsw AS
|
||||||
|
OPERATOR 1 <+> (vector, vector) FOR ORDER BY float_ops,
|
||||||
|
FUNCTION 1 l1_distance(vector, vector);
|
||||||
|
|
||||||
CREATE FUNCTION hamming_distance(bit, bit) RETURNS float8
|
CREATE FUNCTION hamming_distance(bit, bit) RETURNS float8
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
CREATE FUNCTION jaccard_distance(bit, bit) RETURNS float8
|
CREATE FUNCTION jaccard_distance(bit, bit) RETURNS float8
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE FUNCTION bit_ivfflat_support(internal) RETURNS internal
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE FUNCTION bit_hnsw_support(internal) RETURNS internal
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
CREATE OPERATOR <~> (
|
CREATE OPERATOR <~> (
|
||||||
LEFTARG = bit, RIGHTARG = bit, PROCEDURE = hamming_distance,
|
LEFTARG = bit, RIGHTARG = bit, PROCEDURE = hamming_distance,
|
||||||
COMMUTATOR = '<~>'
|
COMMUTATOR = '<~>'
|
||||||
@@ -37,23 +53,20 @@ CREATE OPERATOR CLASS bit_hamming_ops
|
|||||||
FOR TYPE bit USING ivfflat AS
|
FOR TYPE bit USING ivfflat AS
|
||||||
OPERATOR 1 <~> (bit, bit) FOR ORDER BY float_ops,
|
OPERATOR 1 <~> (bit, bit) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 hamming_distance(bit, bit),
|
FUNCTION 1 hamming_distance(bit, bit),
|
||||||
FUNCTION 3 hamming_distance(bit, bit);
|
FUNCTION 3 hamming_distance(bit, bit),
|
||||||
|
FUNCTION 6 bit_ivfflat_support(internal);
|
||||||
CREATE OPERATOR CLASS bit_jaccard_ops
|
|
||||||
FOR TYPE bit USING ivfflat AS
|
|
||||||
OPERATOR 1 <%> (bit, bit) FOR ORDER BY float_ops,
|
|
||||||
FUNCTION 1 jaccard_distance(bit, bit),
|
|
||||||
FUNCTION 3 jaccard_distance(bit, bit);
|
|
||||||
|
|
||||||
CREATE OPERATOR CLASS bit_hamming_ops
|
CREATE OPERATOR CLASS bit_hamming_ops
|
||||||
FOR TYPE bit USING hnsw AS
|
FOR TYPE bit USING hnsw AS
|
||||||
OPERATOR 1 <~> (bit, bit) FOR ORDER BY float_ops,
|
OPERATOR 1 <~> (bit, bit) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 hamming_distance(bit, bit);
|
FUNCTION 1 hamming_distance(bit, bit),
|
||||||
|
FUNCTION 4 bit_hnsw_support(internal);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS bit_jaccard_ops
|
CREATE OPERATOR CLASS bit_jaccard_ops
|
||||||
FOR TYPE bit USING hnsw AS
|
FOR TYPE bit USING hnsw AS
|
||||||
OPERATOR 1 <%> (bit, bit) FOR ORDER BY float_ops,
|
OPERATOR 1 <%> (bit, bit) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 jaccard_distance(bit, bit);
|
FUNCTION 1 jaccard_distance(bit, bit),
|
||||||
|
FUNCTION 4 bit_hnsw_support(internal);
|
||||||
|
|
||||||
CREATE TYPE halfvec;
|
CREATE TYPE halfvec;
|
||||||
|
|
||||||
@@ -156,6 +169,12 @@ CREATE FUNCTION halfvec_accum(double precision[], halfvec) RETURNS double precis
|
|||||||
CREATE FUNCTION halfvec_avg(double precision[]) RETURNS halfvec
|
CREATE FUNCTION halfvec_avg(double precision[]) RETURNS halfvec
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE FUNCTION halfvec_ivfflat_support(internal) RETURNS internal
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE FUNCTION halfvec_hnsw_support(internal) RETURNS internal
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
CREATE AGGREGATE avg(halfvec) (
|
CREATE AGGREGATE avg(halfvec) (
|
||||||
SFUNC = halfvec_accum,
|
SFUNC = halfvec_accum,
|
||||||
STYPE = double precision[],
|
STYPE = double precision[],
|
||||||
@@ -235,6 +254,11 @@ CREATE OPERATOR <=> (
|
|||||||
COMMUTATOR = '<=>'
|
COMMUTATOR = '<=>'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE OPERATOR <+> (
|
||||||
|
LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = l1_distance,
|
||||||
|
COMMUTATOR = '<+>'
|
||||||
|
);
|
||||||
|
|
||||||
CREATE OPERATOR + (
|
CREATE OPERATOR + (
|
||||||
LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_add,
|
LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_add,
|
||||||
COMMUTATOR = +
|
COMMUTATOR = +
|
||||||
@@ -302,14 +326,17 @@ CREATE OPERATOR CLASS halfvec_l2_ops
|
|||||||
FOR TYPE halfvec USING ivfflat AS
|
FOR TYPE halfvec USING ivfflat AS
|
||||||
OPERATOR 1 <-> (halfvec, halfvec) FOR ORDER BY float_ops,
|
OPERATOR 1 <-> (halfvec, halfvec) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 halfvec_l2_squared_distance(halfvec, halfvec),
|
FUNCTION 1 halfvec_l2_squared_distance(halfvec, halfvec),
|
||||||
FUNCTION 3 l2_distance(halfvec, halfvec);
|
FUNCTION 3 l2_distance(halfvec, halfvec),
|
||||||
|
FUNCTION 6 halfvec_ivfflat_support(internal);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS halfvec_ip_ops
|
CREATE OPERATOR CLASS halfvec_ip_ops
|
||||||
FOR TYPE halfvec USING ivfflat AS
|
FOR TYPE halfvec USING ivfflat AS
|
||||||
OPERATOR 1 <#> (halfvec, halfvec) FOR ORDER BY float_ops,
|
OPERATOR 1 <#> (halfvec, halfvec) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
|
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
|
||||||
FUNCTION 3 halfvec_spherical_distance(halfvec, halfvec),
|
FUNCTION 3 halfvec_spherical_distance(halfvec, halfvec),
|
||||||
FUNCTION 4 l2_norm(halfvec);
|
FUNCTION 4 l2_norm(halfvec),
|
||||||
|
FUNCTION 5 l2_normalize(halfvec),
|
||||||
|
FUNCTION 6 halfvec_ivfflat_support(internal);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS halfvec_cosine_ops
|
CREATE OPERATOR CLASS halfvec_cosine_ops
|
||||||
FOR TYPE halfvec USING ivfflat AS
|
FOR TYPE halfvec USING ivfflat AS
|
||||||
@@ -317,23 +344,35 @@ CREATE OPERATOR CLASS halfvec_cosine_ops
|
|||||||
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
|
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
|
||||||
FUNCTION 2 l2_norm(halfvec),
|
FUNCTION 2 l2_norm(halfvec),
|
||||||
FUNCTION 3 halfvec_spherical_distance(halfvec, halfvec),
|
FUNCTION 3 halfvec_spherical_distance(halfvec, halfvec),
|
||||||
FUNCTION 4 l2_norm(halfvec);
|
FUNCTION 4 l2_norm(halfvec),
|
||||||
|
FUNCTION 5 l2_normalize(halfvec),
|
||||||
|
FUNCTION 6 halfvec_ivfflat_support(internal);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS halfvec_l2_ops
|
CREATE OPERATOR CLASS halfvec_l2_ops
|
||||||
FOR TYPE halfvec USING hnsw AS
|
FOR TYPE halfvec USING hnsw AS
|
||||||
OPERATOR 1 <-> (halfvec, halfvec) FOR ORDER BY float_ops,
|
OPERATOR 1 <-> (halfvec, halfvec) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 halfvec_l2_squared_distance(halfvec, halfvec);
|
FUNCTION 1 halfvec_l2_squared_distance(halfvec, halfvec),
|
||||||
|
FUNCTION 4 halfvec_hnsw_support(internal);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS halfvec_ip_ops
|
CREATE OPERATOR CLASS halfvec_ip_ops
|
||||||
FOR TYPE halfvec USING hnsw AS
|
FOR TYPE halfvec USING hnsw AS
|
||||||
OPERATOR 1 <#> (halfvec, halfvec) FOR ORDER BY float_ops,
|
OPERATOR 1 <#> (halfvec, halfvec) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec);
|
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
|
||||||
|
FUNCTION 4 halfvec_hnsw_support(internal);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS halfvec_cosine_ops
|
CREATE OPERATOR CLASS halfvec_cosine_ops
|
||||||
FOR TYPE halfvec USING hnsw AS
|
FOR TYPE halfvec USING hnsw AS
|
||||||
OPERATOR 1 <=> (halfvec, halfvec) FOR ORDER BY float_ops,
|
OPERATOR 1 <=> (halfvec, halfvec) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
|
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
|
||||||
FUNCTION 2 l2_norm(halfvec);
|
FUNCTION 2 l2_norm(halfvec),
|
||||||
|
FUNCTION 3 l2_normalize(halfvec),
|
||||||
|
FUNCTION 4 halfvec_hnsw_support(internal);
|
||||||
|
|
||||||
|
CREATE OPERATOR CLASS halfvec_l1_ops
|
||||||
|
FOR TYPE halfvec USING hnsw AS
|
||||||
|
OPERATOR 1 <+> (halfvec, halfvec) FOR ORDER BY float_ops,
|
||||||
|
FUNCTION 1 l1_distance(halfvec, halfvec),
|
||||||
|
FUNCTION 4 halfvec_hnsw_support(internal);
|
||||||
|
|
||||||
CREATE TYPE sparsevec;
|
CREATE TYPE sparsevec;
|
||||||
|
|
||||||
@@ -415,6 +454,15 @@ CREATE FUNCTION vector_to_sparsevec(vector, integer, boolean) RETURNS sparsevec
|
|||||||
CREATE FUNCTION sparsevec_to_vector(sparsevec, integer, boolean) RETURNS vector
|
CREATE FUNCTION sparsevec_to_vector(sparsevec, integer, boolean) RETURNS vector
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE FUNCTION halfvec_to_sparsevec(halfvec, integer, boolean) RETURNS sparsevec
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE FUNCTION sparsevec_to_halfvec(sparsevec, integer, boolean) RETURNS halfvec
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE FUNCTION sparsevec_hnsw_support(internal) RETURNS internal
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
CREATE CAST (sparsevec AS sparsevec)
|
CREATE CAST (sparsevec AS sparsevec)
|
||||||
WITH FUNCTION sparsevec(sparsevec, integer, boolean) AS IMPLICIT;
|
WITH FUNCTION sparsevec(sparsevec, integer, boolean) AS IMPLICIT;
|
||||||
|
|
||||||
@@ -424,6 +472,12 @@ CREATE CAST (sparsevec AS vector)
|
|||||||
CREATE CAST (vector AS sparsevec)
|
CREATE CAST (vector AS sparsevec)
|
||||||
WITH FUNCTION vector_to_sparsevec(vector, integer, boolean) AS IMPLICIT;
|
WITH FUNCTION vector_to_sparsevec(vector, integer, boolean) AS IMPLICIT;
|
||||||
|
|
||||||
|
CREATE CAST (sparsevec AS halfvec)
|
||||||
|
WITH FUNCTION sparsevec_to_halfvec(sparsevec, integer, boolean) AS ASSIGNMENT;
|
||||||
|
|
||||||
|
CREATE CAST (halfvec AS sparsevec)
|
||||||
|
WITH FUNCTION halfvec_to_sparsevec(halfvec, integer, boolean) AS IMPLICIT;
|
||||||
|
|
||||||
CREATE OPERATOR <-> (
|
CREATE OPERATOR <-> (
|
||||||
LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = l2_distance,
|
LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = l2_distance,
|
||||||
COMMUTATOR = '<->'
|
COMMUTATOR = '<->'
|
||||||
@@ -439,6 +493,11 @@ CREATE OPERATOR <=> (
|
|||||||
COMMUTATOR = '<=>'
|
COMMUTATOR = '<=>'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE OPERATOR <+> (
|
||||||
|
LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = l1_distance,
|
||||||
|
COMMUTATOR = '<+>'
|
||||||
|
);
|
||||||
|
|
||||||
CREATE OPERATOR < (
|
CREATE OPERATOR < (
|
||||||
LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = sparsevec_lt,
|
LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = sparsevec_lt,
|
||||||
COMMUTATOR = > , NEGATOR = >= ,
|
COMMUTATOR = > , NEGATOR = >= ,
|
||||||
@@ -487,15 +546,25 @@ CREATE OPERATOR CLASS sparsevec_ops
|
|||||||
CREATE OPERATOR CLASS sparsevec_l2_ops
|
CREATE OPERATOR CLASS sparsevec_l2_ops
|
||||||
FOR TYPE sparsevec USING hnsw AS
|
FOR TYPE sparsevec USING hnsw AS
|
||||||
OPERATOR 1 <-> (sparsevec, sparsevec) FOR ORDER BY float_ops,
|
OPERATOR 1 <-> (sparsevec, sparsevec) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 sparsevec_l2_squared_distance(sparsevec, sparsevec);
|
FUNCTION 1 sparsevec_l2_squared_distance(sparsevec, sparsevec),
|
||||||
|
FUNCTION 4 sparsevec_hnsw_support(internal);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS sparsevec_ip_ops
|
CREATE OPERATOR CLASS sparsevec_ip_ops
|
||||||
FOR TYPE sparsevec USING hnsw AS
|
FOR TYPE sparsevec USING hnsw AS
|
||||||
OPERATOR 1 <#> (sparsevec, sparsevec) FOR ORDER BY float_ops,
|
OPERATOR 1 <#> (sparsevec, sparsevec) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 sparsevec_negative_inner_product(sparsevec, sparsevec);
|
FUNCTION 1 sparsevec_negative_inner_product(sparsevec, sparsevec),
|
||||||
|
FUNCTION 4 sparsevec_hnsw_support(internal);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS sparsevec_cosine_ops
|
CREATE OPERATOR CLASS sparsevec_cosine_ops
|
||||||
FOR TYPE sparsevec USING hnsw AS
|
FOR TYPE sparsevec USING hnsw AS
|
||||||
OPERATOR 1 <=> (sparsevec, sparsevec) FOR ORDER BY float_ops,
|
OPERATOR 1 <=> (sparsevec, sparsevec) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 sparsevec_negative_inner_product(sparsevec, sparsevec),
|
FUNCTION 1 sparsevec_negative_inner_product(sparsevec, sparsevec),
|
||||||
FUNCTION 2 l2_norm(sparsevec);
|
FUNCTION 2 l2_norm(sparsevec),
|
||||||
|
FUNCTION 3 l2_normalize(sparsevec),
|
||||||
|
FUNCTION 4 sparsevec_hnsw_support(internal);
|
||||||
|
|
||||||
|
CREATE OPERATOR CLASS sparsevec_l1_ops
|
||||||
|
FOR TYPE sparsevec USING hnsw AS
|
||||||
|
OPERATOR 1 <+> (sparsevec, sparsevec) FOR ORDER BY float_ops,
|
||||||
|
FUNCTION 1 l1_distance(sparsevec, sparsevec),
|
||||||
|
FUNCTION 4 sparsevec_hnsw_support(internal);
|
||||||
|
|||||||
107
sql/vector.sql
107
sql/vector.sql
@@ -186,6 +186,11 @@ CREATE OPERATOR <=> (
|
|||||||
COMMUTATOR = '<=>'
|
COMMUTATOR = '<=>'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE OPERATOR <+> (
|
||||||
|
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = l1_distance,
|
||||||
|
COMMUTATOR = '<+>'
|
||||||
|
);
|
||||||
|
|
||||||
CREATE OPERATOR + (
|
CREATE OPERATOR + (
|
||||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_add,
|
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_add,
|
||||||
COMMUTATOR = +
|
COMMUTATOR = +
|
||||||
@@ -304,6 +309,11 @@ CREATE OPERATOR CLASS vector_cosine_ops
|
|||||||
FUNCTION 1 vector_negative_inner_product(vector, vector),
|
FUNCTION 1 vector_negative_inner_product(vector, vector),
|
||||||
FUNCTION 2 vector_norm(vector);
|
FUNCTION 2 vector_norm(vector);
|
||||||
|
|
||||||
|
CREATE OPERATOR CLASS vector_l1_ops
|
||||||
|
FOR TYPE vector USING hnsw AS
|
||||||
|
OPERATOR 1 <+> (vector, vector) FOR ORDER BY float_ops,
|
||||||
|
FUNCTION 1 l1_distance(vector, vector);
|
||||||
|
|
||||||
-- bit functions
|
-- bit functions
|
||||||
|
|
||||||
CREATE FUNCTION hamming_distance(bit, bit) RETURNS float8
|
CREATE FUNCTION hamming_distance(bit, bit) RETURNS float8
|
||||||
@@ -312,6 +322,14 @@ CREATE FUNCTION hamming_distance(bit, bit) RETURNS float8
|
|||||||
CREATE FUNCTION jaccard_distance(bit, bit) RETURNS float8
|
CREATE FUNCTION jaccard_distance(bit, bit) RETURNS float8
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
-- bit private functions
|
||||||
|
|
||||||
|
CREATE FUNCTION bit_ivfflat_support(internal) RETURNS internal
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE FUNCTION bit_hnsw_support(internal) RETURNS internal
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
-- bit operators
|
-- bit operators
|
||||||
|
|
||||||
CREATE OPERATOR <~> (
|
CREATE OPERATOR <~> (
|
||||||
@@ -330,23 +348,20 @@ CREATE OPERATOR CLASS bit_hamming_ops
|
|||||||
FOR TYPE bit USING ivfflat AS
|
FOR TYPE bit USING ivfflat AS
|
||||||
OPERATOR 1 <~> (bit, bit) FOR ORDER BY float_ops,
|
OPERATOR 1 <~> (bit, bit) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 hamming_distance(bit, bit),
|
FUNCTION 1 hamming_distance(bit, bit),
|
||||||
FUNCTION 3 hamming_distance(bit, bit);
|
FUNCTION 3 hamming_distance(bit, bit),
|
||||||
|
FUNCTION 6 bit_ivfflat_support(internal);
|
||||||
CREATE OPERATOR CLASS bit_jaccard_ops
|
|
||||||
FOR TYPE bit USING ivfflat AS
|
|
||||||
OPERATOR 1 <%> (bit, bit) FOR ORDER BY float_ops,
|
|
||||||
FUNCTION 1 jaccard_distance(bit, bit),
|
|
||||||
FUNCTION 3 jaccard_distance(bit, bit);
|
|
||||||
|
|
||||||
CREATE OPERATOR CLASS bit_hamming_ops
|
CREATE OPERATOR CLASS bit_hamming_ops
|
||||||
FOR TYPE bit USING hnsw AS
|
FOR TYPE bit USING hnsw AS
|
||||||
OPERATOR 1 <~> (bit, bit) FOR ORDER BY float_ops,
|
OPERATOR 1 <~> (bit, bit) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 hamming_distance(bit, bit);
|
FUNCTION 1 hamming_distance(bit, bit),
|
||||||
|
FUNCTION 4 bit_hnsw_support(internal);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS bit_jaccard_ops
|
CREATE OPERATOR CLASS bit_jaccard_ops
|
||||||
FOR TYPE bit USING hnsw AS
|
FOR TYPE bit USING hnsw AS
|
||||||
OPERATOR 1 <%> (bit, bit) FOR ORDER BY float_ops,
|
OPERATOR 1 <%> (bit, bit) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 jaccard_distance(bit, bit);
|
FUNCTION 1 jaccard_distance(bit, bit),
|
||||||
|
FUNCTION 4 bit_hnsw_support(internal);
|
||||||
|
|
||||||
-- halfvec type
|
-- halfvec type
|
||||||
|
|
||||||
@@ -455,6 +470,12 @@ CREATE FUNCTION halfvec_accum(double precision[], halfvec) RETURNS double precis
|
|||||||
CREATE FUNCTION halfvec_avg(double precision[]) RETURNS halfvec
|
CREATE FUNCTION halfvec_avg(double precision[]) RETURNS halfvec
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE FUNCTION halfvec_ivfflat_support(internal) RETURNS internal
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE FUNCTION halfvec_hnsw_support(internal) RETURNS internal
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
-- halfvec aggregates
|
-- halfvec aggregates
|
||||||
|
|
||||||
CREATE AGGREGATE avg(halfvec) (
|
CREATE AGGREGATE avg(halfvec) (
|
||||||
@@ -542,6 +563,11 @@ CREATE OPERATOR <=> (
|
|||||||
COMMUTATOR = '<=>'
|
COMMUTATOR = '<=>'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE OPERATOR <+> (
|
||||||
|
LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = l1_distance,
|
||||||
|
COMMUTATOR = '<+>'
|
||||||
|
);
|
||||||
|
|
||||||
CREATE OPERATOR + (
|
CREATE OPERATOR + (
|
||||||
LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_add,
|
LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_add,
|
||||||
COMMUTATOR = +
|
COMMUTATOR = +
|
||||||
@@ -611,14 +637,17 @@ CREATE OPERATOR CLASS halfvec_l2_ops
|
|||||||
FOR TYPE halfvec USING ivfflat AS
|
FOR TYPE halfvec USING ivfflat AS
|
||||||
OPERATOR 1 <-> (halfvec, halfvec) FOR ORDER BY float_ops,
|
OPERATOR 1 <-> (halfvec, halfvec) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 halfvec_l2_squared_distance(halfvec, halfvec),
|
FUNCTION 1 halfvec_l2_squared_distance(halfvec, halfvec),
|
||||||
FUNCTION 3 l2_distance(halfvec, halfvec);
|
FUNCTION 3 l2_distance(halfvec, halfvec),
|
||||||
|
FUNCTION 6 halfvec_ivfflat_support(internal);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS halfvec_ip_ops
|
CREATE OPERATOR CLASS halfvec_ip_ops
|
||||||
FOR TYPE halfvec USING ivfflat AS
|
FOR TYPE halfvec USING ivfflat AS
|
||||||
OPERATOR 1 <#> (halfvec, halfvec) FOR ORDER BY float_ops,
|
OPERATOR 1 <#> (halfvec, halfvec) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
|
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
|
||||||
FUNCTION 3 halfvec_spherical_distance(halfvec, halfvec),
|
FUNCTION 3 halfvec_spherical_distance(halfvec, halfvec),
|
||||||
FUNCTION 4 l2_norm(halfvec);
|
FUNCTION 4 l2_norm(halfvec),
|
||||||
|
FUNCTION 5 l2_normalize(halfvec),
|
||||||
|
FUNCTION 6 halfvec_ivfflat_support(internal);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS halfvec_cosine_ops
|
CREATE OPERATOR CLASS halfvec_cosine_ops
|
||||||
FOR TYPE halfvec USING ivfflat AS
|
FOR TYPE halfvec USING ivfflat AS
|
||||||
@@ -626,23 +655,35 @@ CREATE OPERATOR CLASS halfvec_cosine_ops
|
|||||||
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
|
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
|
||||||
FUNCTION 2 l2_norm(halfvec),
|
FUNCTION 2 l2_norm(halfvec),
|
||||||
FUNCTION 3 halfvec_spherical_distance(halfvec, halfvec),
|
FUNCTION 3 halfvec_spherical_distance(halfvec, halfvec),
|
||||||
FUNCTION 4 l2_norm(halfvec);
|
FUNCTION 4 l2_norm(halfvec),
|
||||||
|
FUNCTION 5 l2_normalize(halfvec),
|
||||||
|
FUNCTION 6 halfvec_ivfflat_support(internal);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS halfvec_l2_ops
|
CREATE OPERATOR CLASS halfvec_l2_ops
|
||||||
FOR TYPE halfvec USING hnsw AS
|
FOR TYPE halfvec USING hnsw AS
|
||||||
OPERATOR 1 <-> (halfvec, halfvec) FOR ORDER BY float_ops,
|
OPERATOR 1 <-> (halfvec, halfvec) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 halfvec_l2_squared_distance(halfvec, halfvec);
|
FUNCTION 1 halfvec_l2_squared_distance(halfvec, halfvec),
|
||||||
|
FUNCTION 4 halfvec_hnsw_support(internal);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS halfvec_ip_ops
|
CREATE OPERATOR CLASS halfvec_ip_ops
|
||||||
FOR TYPE halfvec USING hnsw AS
|
FOR TYPE halfvec USING hnsw AS
|
||||||
OPERATOR 1 <#> (halfvec, halfvec) FOR ORDER BY float_ops,
|
OPERATOR 1 <#> (halfvec, halfvec) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec);
|
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
|
||||||
|
FUNCTION 4 halfvec_hnsw_support(internal);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS halfvec_cosine_ops
|
CREATE OPERATOR CLASS halfvec_cosine_ops
|
||||||
FOR TYPE halfvec USING hnsw AS
|
FOR TYPE halfvec USING hnsw AS
|
||||||
OPERATOR 1 <=> (halfvec, halfvec) FOR ORDER BY float_ops,
|
OPERATOR 1 <=> (halfvec, halfvec) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
|
FUNCTION 1 halfvec_negative_inner_product(halfvec, halfvec),
|
||||||
FUNCTION 2 l2_norm(halfvec);
|
FUNCTION 2 l2_norm(halfvec),
|
||||||
|
FUNCTION 3 l2_normalize(halfvec),
|
||||||
|
FUNCTION 4 halfvec_hnsw_support(internal);
|
||||||
|
|
||||||
|
CREATE OPERATOR CLASS halfvec_l1_ops
|
||||||
|
FOR TYPE halfvec USING hnsw AS
|
||||||
|
OPERATOR 1 <+> (halfvec, halfvec) FOR ORDER BY float_ops,
|
||||||
|
FUNCTION 1 l1_distance(halfvec, halfvec),
|
||||||
|
FUNCTION 4 halfvec_hnsw_support(internal);
|
||||||
|
|
||||||
--- sparsevec type
|
--- sparsevec type
|
||||||
|
|
||||||
@@ -732,6 +773,15 @@ CREATE FUNCTION vector_to_sparsevec(vector, integer, boolean) RETURNS sparsevec
|
|||||||
CREATE FUNCTION sparsevec_to_vector(sparsevec, integer, boolean) RETURNS vector
|
CREATE FUNCTION sparsevec_to_vector(sparsevec, integer, boolean) RETURNS vector
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE FUNCTION halfvec_to_sparsevec(halfvec, integer, boolean) RETURNS sparsevec
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE FUNCTION sparsevec_to_halfvec(sparsevec, integer, boolean) RETURNS halfvec
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE FUNCTION sparsevec_hnsw_support(internal) RETURNS internal
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||||
|
|
||||||
-- sparsevec casts
|
-- sparsevec casts
|
||||||
|
|
||||||
CREATE CAST (sparsevec AS sparsevec)
|
CREATE CAST (sparsevec AS sparsevec)
|
||||||
@@ -743,6 +793,12 @@ CREATE CAST (sparsevec AS vector)
|
|||||||
CREATE CAST (vector AS sparsevec)
|
CREATE CAST (vector AS sparsevec)
|
||||||
WITH FUNCTION vector_to_sparsevec(vector, integer, boolean) AS IMPLICIT;
|
WITH FUNCTION vector_to_sparsevec(vector, integer, boolean) AS IMPLICIT;
|
||||||
|
|
||||||
|
CREATE CAST (sparsevec AS halfvec)
|
||||||
|
WITH FUNCTION sparsevec_to_halfvec(sparsevec, integer, boolean) AS ASSIGNMENT;
|
||||||
|
|
||||||
|
CREATE CAST (halfvec AS sparsevec)
|
||||||
|
WITH FUNCTION halfvec_to_sparsevec(halfvec, integer, boolean) AS IMPLICIT;
|
||||||
|
|
||||||
-- sparsevec operators
|
-- sparsevec operators
|
||||||
|
|
||||||
CREATE OPERATOR <-> (
|
CREATE OPERATOR <-> (
|
||||||
@@ -760,6 +816,11 @@ CREATE OPERATOR <=> (
|
|||||||
COMMUTATOR = '<=>'
|
COMMUTATOR = '<=>'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE OPERATOR <+> (
|
||||||
|
LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = l1_distance,
|
||||||
|
COMMUTATOR = '<+>'
|
||||||
|
);
|
||||||
|
|
||||||
CREATE OPERATOR < (
|
CREATE OPERATOR < (
|
||||||
LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = sparsevec_lt,
|
LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = sparsevec_lt,
|
||||||
COMMUTATOR = > , NEGATOR = >= ,
|
COMMUTATOR = > , NEGATOR = >= ,
|
||||||
@@ -810,15 +871,25 @@ CREATE OPERATOR CLASS sparsevec_ops
|
|||||||
CREATE OPERATOR CLASS sparsevec_l2_ops
|
CREATE OPERATOR CLASS sparsevec_l2_ops
|
||||||
FOR TYPE sparsevec USING hnsw AS
|
FOR TYPE sparsevec USING hnsw AS
|
||||||
OPERATOR 1 <-> (sparsevec, sparsevec) FOR ORDER BY float_ops,
|
OPERATOR 1 <-> (sparsevec, sparsevec) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 sparsevec_l2_squared_distance(sparsevec, sparsevec);
|
FUNCTION 1 sparsevec_l2_squared_distance(sparsevec, sparsevec),
|
||||||
|
FUNCTION 4 sparsevec_hnsw_support(internal);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS sparsevec_ip_ops
|
CREATE OPERATOR CLASS sparsevec_ip_ops
|
||||||
FOR TYPE sparsevec USING hnsw AS
|
FOR TYPE sparsevec USING hnsw AS
|
||||||
OPERATOR 1 <#> (sparsevec, sparsevec) FOR ORDER BY float_ops,
|
OPERATOR 1 <#> (sparsevec, sparsevec) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 sparsevec_negative_inner_product(sparsevec, sparsevec);
|
FUNCTION 1 sparsevec_negative_inner_product(sparsevec, sparsevec),
|
||||||
|
FUNCTION 4 sparsevec_hnsw_support(internal);
|
||||||
|
|
||||||
CREATE OPERATOR CLASS sparsevec_cosine_ops
|
CREATE OPERATOR CLASS sparsevec_cosine_ops
|
||||||
FOR TYPE sparsevec USING hnsw AS
|
FOR TYPE sparsevec USING hnsw AS
|
||||||
OPERATOR 1 <=> (sparsevec, sparsevec) FOR ORDER BY float_ops,
|
OPERATOR 1 <=> (sparsevec, sparsevec) FOR ORDER BY float_ops,
|
||||||
FUNCTION 1 sparsevec_negative_inner_product(sparsevec, sparsevec),
|
FUNCTION 1 sparsevec_negative_inner_product(sparsevec, sparsevec),
|
||||||
FUNCTION 2 l2_norm(sparsevec);
|
FUNCTION 2 l2_norm(sparsevec),
|
||||||
|
FUNCTION 3 l2_normalize(sparsevec),
|
||||||
|
FUNCTION 4 sparsevec_hnsw_support(internal);
|
||||||
|
|
||||||
|
CREATE OPERATOR CLASS sparsevec_l1_ops
|
||||||
|
FOR TYPE sparsevec USING hnsw AS
|
||||||
|
OPERATOR 1 <+> (sparsevec, sparsevec) FOR ORDER BY float_ops,
|
||||||
|
FUNCTION 1 l1_distance(sparsevec, sparsevec),
|
||||||
|
FUNCTION 4 sparsevec_hnsw_support(internal);
|
||||||
|
|||||||
217
src/bitutils.c
Normal file
217
src/bitutils.c
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "bitutils.h"
|
||||||
|
#include "port/pg_bitutils.h"
|
||||||
|
|
||||||
|
#ifdef BIT_DISPATCH
|
||||||
|
#include <immintrin.h>
|
||||||
|
|
||||||
|
#if defined(HAVE__GET_CPUID)
|
||||||
|
#include <cpuid.h>
|
||||||
|
#else
|
||||||
|
#include <intrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define TARGET_AVX512_POPCOUNT
|
||||||
|
#else
|
||||||
|
#define TARGET_AVX512_POPCOUNT __attribute__((target("avx512f,avx512vpopcntdq")))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Disable for LLVM due to crash with bitcode generation */
|
||||||
|
#if defined(USE_TARGET_CLONES) && !defined(__POPCNT__) && !defined(__llvm__)
|
||||||
|
#define BIT_TARGET_CLONES __attribute__((target_clones("default", "popcnt")))
|
||||||
|
#else
|
||||||
|
#define BIT_TARGET_CLONES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Use built-ins when possible for inlining */
|
||||||
|
#if defined(HAVE__BUILTIN_POPCOUNT) && defined(HAVE_LONG_INT_64)
|
||||||
|
#define popcount64(x) __builtin_popcountl(x)
|
||||||
|
#elif defined(HAVE__BUILTIN_POPCOUNT) && defined(HAVE_LONG_LONG_INT_64)
|
||||||
|
#define popcount64(x) __builtin_popcountll(x)
|
||||||
|
#elif !defined(_MSC_VER)
|
||||||
|
/* Fails to resolve with MSVC */
|
||||||
|
#define popcount64(x) pg_popcount64(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint64 (*BitHammingDistance) (uint32 bytes, unsigned char *ax, unsigned char *bx, uint64 distance);
|
||||||
|
double (*BitJaccardDistance) (uint32 bytes, unsigned char *ax, unsigned char *bx, uint64 ab, uint64 aa, uint64 bb);
|
||||||
|
|
||||||
|
BIT_TARGET_CLONES static uint64
|
||||||
|
BitHammingDistanceDefault(uint32 bytes, unsigned char *ax, unsigned char *bx, uint64 distance)
|
||||||
|
{
|
||||||
|
#ifdef popcount64
|
||||||
|
for (; bytes >= sizeof(uint64); bytes -= sizeof(uint64))
|
||||||
|
{
|
||||||
|
uint64 axs;
|
||||||
|
uint64 bxs;
|
||||||
|
|
||||||
|
/* Ensure aligned */
|
||||||
|
memcpy(&axs, ax, sizeof(uint64));
|
||||||
|
memcpy(&bxs, bx, sizeof(uint64));
|
||||||
|
|
||||||
|
distance += popcount64(axs ^ bxs);
|
||||||
|
|
||||||
|
ax += sizeof(uint64);
|
||||||
|
bx += sizeof(uint64);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < bytes; i++)
|
||||||
|
distance += pg_number_of_ones[ax[i] ^ bx[i]];
|
||||||
|
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BIT_DISPATCH
|
||||||
|
TARGET_AVX512_POPCOUNT static uint64
|
||||||
|
BitHammingDistanceAvx512Popcount(uint32 bytes, unsigned char *ax, unsigned char *bx, uint64 distance)
|
||||||
|
{
|
||||||
|
__m512i dist = _mm512_setzero_si512();
|
||||||
|
|
||||||
|
for (; bytes >= sizeof(__m512i); bytes -= sizeof(__m512i))
|
||||||
|
{
|
||||||
|
__m512i axs = _mm512_loadu_si512((const __m512i *) ax);
|
||||||
|
__m512i bxs = _mm512_loadu_si512((const __m512i *) bx);
|
||||||
|
|
||||||
|
dist = _mm512_add_epi64(dist, _mm512_popcnt_epi64(_mm512_xor_si512(axs, bxs)));
|
||||||
|
|
||||||
|
ax += sizeof(__m512i);
|
||||||
|
bx += sizeof(__m512i);
|
||||||
|
}
|
||||||
|
|
||||||
|
distance += _mm512_reduce_add_epi64(dist);
|
||||||
|
|
||||||
|
return BitHammingDistanceDefault(bytes, ax, bx, distance);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BIT_TARGET_CLONES static double
|
||||||
|
BitJaccardDistanceDefault(uint32 bytes, unsigned char *ax, unsigned char *bx, uint64 ab, uint64 aa, uint64 bb)
|
||||||
|
{
|
||||||
|
#ifdef popcount64
|
||||||
|
for (; bytes >= sizeof(uint64); bytes -= sizeof(uint64))
|
||||||
|
{
|
||||||
|
uint64 axs;
|
||||||
|
uint64 bxs;
|
||||||
|
|
||||||
|
/* Ensure aligned */
|
||||||
|
memcpy(&axs, ax, sizeof(uint64));
|
||||||
|
memcpy(&bxs, bx, sizeof(uint64));
|
||||||
|
|
||||||
|
ab += popcount64(axs & bxs);
|
||||||
|
aa += popcount64(axs);
|
||||||
|
bb += popcount64(bxs);
|
||||||
|
|
||||||
|
ax += sizeof(uint64);
|
||||||
|
bx += sizeof(uint64);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < bytes; i++)
|
||||||
|
{
|
||||||
|
ab += pg_number_of_ones[ax[i] & bx[i]];
|
||||||
|
aa += pg_number_of_ones[ax[i]];
|
||||||
|
bb += pg_number_of_ones[bx[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ab == 0)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 1 - (ab / ((double) (aa + bb - ab)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BIT_DISPATCH
|
||||||
|
TARGET_AVX512_POPCOUNT static double
|
||||||
|
BitJaccardDistanceAvx512Popcount(uint32 bytes, unsigned char *ax, unsigned char *bx, uint64 ab, uint64 aa, uint64 bb)
|
||||||
|
{
|
||||||
|
__m512i abx = _mm512_setzero_si512();
|
||||||
|
__m512i aax = _mm512_setzero_si512();
|
||||||
|
__m512i bbx = _mm512_setzero_si512();
|
||||||
|
|
||||||
|
for (; bytes >= sizeof(__m512i); bytes -= sizeof(__m512i))
|
||||||
|
{
|
||||||
|
__m512i axs = _mm512_loadu_si512((const __m512i *) ax);
|
||||||
|
__m512i bxs = _mm512_loadu_si512((const __m512i *) bx);
|
||||||
|
|
||||||
|
abx = _mm512_add_epi64(abx, _mm512_popcnt_epi64(_mm512_and_si512(axs, bxs)));
|
||||||
|
aax = _mm512_add_epi64(aax, _mm512_popcnt_epi64(axs));
|
||||||
|
bbx = _mm512_add_epi64(bbx, _mm512_popcnt_epi64(bxs));
|
||||||
|
|
||||||
|
ax += sizeof(__m512i);
|
||||||
|
bx += sizeof(__m512i);
|
||||||
|
}
|
||||||
|
|
||||||
|
ab += _mm512_reduce_add_epi64(abx);
|
||||||
|
aa += _mm512_reduce_add_epi64(aax);
|
||||||
|
bb += _mm512_reduce_add_epi64(bbx);
|
||||||
|
|
||||||
|
return BitJaccardDistanceDefault(bytes, ax, bx, ab, aa, bb);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BIT_DISPATCH
|
||||||
|
#define CPU_FEATURE_OSXSAVE (1 << 27) /* F1 ECX */
|
||||||
|
#define CPU_FEATURE_AVX512F (1 << 16) /* F7,0 EBX */
|
||||||
|
#define CPU_FEATURE_AVX512VPOPCNTDQ (1 << 14) /* F7,0 ECX */
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define TARGET_XSAVE
|
||||||
|
#else
|
||||||
|
#define TARGET_XSAVE __attribute__((target("xsave")))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TARGET_XSAVE static bool
|
||||||
|
SupportsAvx512Popcount()
|
||||||
|
{
|
||||||
|
unsigned int exx[4] = {0, 0, 0, 0};
|
||||||
|
|
||||||
|
#if defined(HAVE__GET_CPUID)
|
||||||
|
__get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
|
||||||
|
#else
|
||||||
|
__cpuid(exx, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check OS supports XSAVE */
|
||||||
|
if ((exx[2] & CPU_FEATURE_OSXSAVE) != CPU_FEATURE_OSXSAVE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Check XMM, YMM, and ZMM registers are enabled */
|
||||||
|
if ((_xgetbv(0) & 0xe6) != 0xe6)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#if defined(HAVE__GET_CPUID)
|
||||||
|
__get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
|
||||||
|
#else
|
||||||
|
__cpuidex(exx, 7, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check AVX512F */
|
||||||
|
if ((exx[1] & CPU_FEATURE_AVX512F) != CPU_FEATURE_AVX512F)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Check AVX512VPOPCNTDQ */
|
||||||
|
return (exx[2] & CPU_FEATURE_AVX512VPOPCNTDQ) == CPU_FEATURE_AVX512VPOPCNTDQ;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
BitvecInit(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Could skip pointer when single function, but no difference in
|
||||||
|
* performance
|
||||||
|
*/
|
||||||
|
BitHammingDistance = BitHammingDistanceDefault;
|
||||||
|
BitJaccardDistance = BitJaccardDistanceDefault;
|
||||||
|
|
||||||
|
#ifdef BIT_DISPATCH
|
||||||
|
if (SupportsAvx512Popcount())
|
||||||
|
{
|
||||||
|
BitHammingDistance = BitHammingDistanceAvx512Popcount;
|
||||||
|
BitJaccardDistance = BitJaccardDistanceAvx512Popcount;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
31
src/bitutils.h
Normal file
31
src/bitutils.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#ifndef BITUTILS_H
|
||||||
|
#define BITUTILS_H
|
||||||
|
|
||||||
|
/* We use two types of dispatching: intrinsics and target_clones */
|
||||||
|
/* TODO Move to better place */
|
||||||
|
#ifndef DISABLE_DISPATCH
|
||||||
|
/* Only enable for more recent compilers to keep build process simple */
|
||||||
|
#if defined(__x86_64__) && defined(__GNUC__) && __GNUC__ >= 8
|
||||||
|
#define USE_DISPATCH
|
||||||
|
#elif defined(__x86_64__) && defined(__clang_major__) && __clang_major__ >= 7
|
||||||
|
#define USE_DISPATCH
|
||||||
|
#elif defined(_M_AMD64) && defined(_MSC_VER) && _MSC_VER >= 1920
|
||||||
|
#define USE_DISPATCH
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* target_clones requires glibc */
|
||||||
|
#if defined(USE_DISPATCH) && defined(__gnu_linux__)
|
||||||
|
#define USE_TARGET_CLONES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_DISPATCH)
|
||||||
|
#define BIT_DISPATCH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern uint64 (*BitHammingDistance) (uint32 bytes, unsigned char *ax, unsigned char *bx, uint64 distance);
|
||||||
|
extern double (*BitJaccardDistance) (uint32 bytes, unsigned char *ax, unsigned char *bx, uint64 ab, uint64 aa, uint64 bb);
|
||||||
|
|
||||||
|
void BitvecInit(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "bitvector.h"
|
#include "bitutils.h"
|
||||||
#include "port/pg_bitutils.h"
|
#include "bitvec.h"
|
||||||
#include "utils/varbit.h"
|
#include "utils/varbit.h"
|
||||||
|
|
||||||
#if PG_VERSION_NUM >= 160000
|
#if PG_VERSION_NUM >= 160000
|
||||||
@@ -46,17 +46,10 @@ hamming_distance(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
VarBit *a = PG_GETARG_VARBIT_P(0);
|
VarBit *a = PG_GETARG_VARBIT_P(0);
|
||||||
VarBit *b = PG_GETARG_VARBIT_P(1);
|
VarBit *b = PG_GETARG_VARBIT_P(1);
|
||||||
unsigned char *ax = VARBITS(a);
|
|
||||||
unsigned char *bx = VARBITS(b);
|
|
||||||
uint64 distance = 0;
|
|
||||||
|
|
||||||
CheckDims(a, b);
|
CheckDims(a, b);
|
||||||
|
|
||||||
/* TODO Improve performance */
|
PG_RETURN_FLOAT8((double) BitHammingDistance(VARBITBYTES(a), VARBITS(a), VARBITS(b), 0));
|
||||||
for (uint32 i = 0; i < VARBITBYTES(a); i++)
|
|
||||||
distance += pg_number_of_ones[ax[i] ^ bx[i]];
|
|
||||||
|
|
||||||
PG_RETURN_FLOAT8((double) distance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -68,23 +61,8 @@ jaccard_distance(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
VarBit *a = PG_GETARG_VARBIT_P(0);
|
VarBit *a = PG_GETARG_VARBIT_P(0);
|
||||||
VarBit *b = PG_GETARG_VARBIT_P(1);
|
VarBit *b = PG_GETARG_VARBIT_P(1);
|
||||||
unsigned char *ax = VARBITS(a);
|
|
||||||
unsigned char *bx = VARBITS(b);
|
|
||||||
uint64 ab = 0;
|
|
||||||
uint64 aa;
|
|
||||||
uint64 bb;
|
|
||||||
|
|
||||||
CheckDims(a, b);
|
CheckDims(a, b);
|
||||||
|
|
||||||
/* TODO Improve performance */
|
PG_RETURN_FLOAT8(BitJaccardDistance(VARBITBYTES(a), VARBITS(a), VARBITS(b), 0, 0, 0));
|
||||||
for (uint32 i = 0; i < VARBITBYTES(a); i++)
|
|
||||||
ab += pg_number_of_ones[ax[i] & bx[i]];
|
|
||||||
|
|
||||||
if (ab == 0)
|
|
||||||
PG_RETURN_FLOAT8(1);
|
|
||||||
|
|
||||||
aa = pg_popcount((char *) ax, VARBITBYTES(a));
|
|
||||||
bb = pg_popcount((char *) bx, VARBITBYTES(b));
|
|
||||||
|
|
||||||
PG_RETURN_FLOAT8(1 - (ab / ((double) (aa + bb - ab))));
|
|
||||||
}
|
}
|
||||||
@@ -8,21 +8,21 @@
|
|||||||
|
|
||||||
#if defined(HAVE__GET_CPUID)
|
#if defined(HAVE__GET_CPUID)
|
||||||
#include <cpuid.h>
|
#include <cpuid.h>
|
||||||
#elif defined(HAVE__CPUID)
|
#else
|
||||||
#include <intrin.h>
|
#include <intrin.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define TARGET_F16C_FMA
|
#define TARGET_F16C
|
||||||
#else
|
#else
|
||||||
#define TARGET_F16C_FMA __attribute__((target("f16c,fma")))
|
#define TARGET_F16C __attribute__((target("avx,f16c,fma")))
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
float (*HalfvecL2SquaredDistance) (int dim, half * ax, half * bx);
|
float (*HalfvecL2SquaredDistance) (int dim, half * ax, half * bx);
|
||||||
float (*HalfvecInnerProduct) (int dim, half * ax, half * bx);
|
float (*HalfvecInnerProduct) (int dim, half * ax, half * bx);
|
||||||
double (*HalfvecCosineSimilarity) (int dim, half * ax, half * bx);
|
double (*HalfvecCosineSimilarity) (int dim, half * ax, half * bx);
|
||||||
|
float (*HalfvecL1Distance) (int dim, half * ax, half * bx);
|
||||||
|
|
||||||
static float
|
static float
|
||||||
HalfvecL2SquaredDistanceDefault(int dim, half * ax, half * bx)
|
HalfvecL2SquaredDistanceDefault(int dim, half * ax, half * bx)
|
||||||
@@ -41,8 +41,8 @@ HalfvecL2SquaredDistanceDefault(int dim, half * ax, half * bx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HALFVEC_DISPATCH
|
#ifdef HALFVEC_DISPATCH
|
||||||
TARGET_F16C_FMA static float
|
TARGET_F16C static float
|
||||||
HalfvecL2SquaredDistanceF16cFma(int dim, half * ax, half * bx)
|
HalfvecL2SquaredDistanceF16c(int dim, half * ax, half * bx)
|
||||||
{
|
{
|
||||||
float distance;
|
float distance;
|
||||||
int i;
|
int i;
|
||||||
@@ -89,8 +89,8 @@ HalfvecInnerProductDefault(int dim, half * ax, half * bx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HALFVEC_DISPATCH
|
#ifdef HALFVEC_DISPATCH
|
||||||
TARGET_F16C_FMA static float
|
TARGET_F16C static float
|
||||||
HalfvecInnerProductF16cFma(int dim, half * ax, half * bx)
|
HalfvecInnerProductF16c(int dim, half * ax, half * bx)
|
||||||
{
|
{
|
||||||
float distance;
|
float distance;
|
||||||
int i;
|
int i;
|
||||||
@@ -142,8 +142,8 @@ HalfvecCosineSimilarityDefault(int dim, half * ax, half * bx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HALFVEC_DISPATCH
|
#ifdef HALFVEC_DISPATCH
|
||||||
TARGET_F16C_FMA static double
|
TARGET_F16C static double
|
||||||
HalfvecCosineSimilarityF16cFma(int dim, half * ax, half * bx)
|
HalfvecCosineSimilarityF16c(int dim, half * ax, half * bx)
|
||||||
{
|
{
|
||||||
float similarity;
|
float similarity;
|
||||||
float norma;
|
float norma;
|
||||||
@@ -192,6 +192,51 @@ HalfvecCosineSimilarityF16cFma(int dim, half * ax, half * bx)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static float
|
||||||
|
HalfvecL1DistanceDefault(int dim, half * ax, half * bx)
|
||||||
|
{
|
||||||
|
float distance = 0.0;
|
||||||
|
|
||||||
|
/* Auto-vectorized */
|
||||||
|
for (int i = 0; i < dim; i++)
|
||||||
|
distance += fabsf(HalfToFloat4(ax[i]) - HalfToFloat4(bx[i]));
|
||||||
|
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HALFVEC_DISPATCH
|
||||||
|
/* Does not require FMA, but keep logic simple */
|
||||||
|
TARGET_F16C static float
|
||||||
|
HalfvecL1DistanceF16c(int dim, half * ax, half * bx)
|
||||||
|
{
|
||||||
|
float distance;
|
||||||
|
int i;
|
||||||
|
float s[8];
|
||||||
|
int count = (dim / 8) * 8;
|
||||||
|
__m256 dist = _mm256_setzero_ps();
|
||||||
|
__m256 sign = _mm256_set1_ps(-0.0);
|
||||||
|
|
||||||
|
for (i = 0; i < count; i += 8)
|
||||||
|
{
|
||||||
|
__m128i axi = _mm_loadu_si128((__m128i *) (ax + i));
|
||||||
|
__m128i bxi = _mm_loadu_si128((__m128i *) (bx + i));
|
||||||
|
__m256 axs = _mm256_cvtph_ps(axi);
|
||||||
|
__m256 bxs = _mm256_cvtph_ps(bxi);
|
||||||
|
|
||||||
|
dist = _mm256_add_ps(dist, _mm256_andnot_ps(sign, _mm256_sub_ps(axs, bxs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
_mm256_storeu_ps(s, dist);
|
||||||
|
|
||||||
|
distance = s[0] + s[1] + s[2] + s[3] + s[4] + s[5] + s[6] + s[7];
|
||||||
|
|
||||||
|
for (; i < dim; i++)
|
||||||
|
distance += fabsf(HalfToFloat4(ax[i]) - HalfToFloat4(bx[i]));
|
||||||
|
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HALFVEC_DISPATCH
|
#ifdef HALFVEC_DISPATCH
|
||||||
#define CPU_FEATURE_FMA (1 << 12)
|
#define CPU_FEATURE_FMA (1 << 12)
|
||||||
#define CPU_FEATURE_OSXSAVE (1 << 27)
|
#define CPU_FEATURE_OSXSAVE (1 << 27)
|
||||||
@@ -211,16 +256,19 @@ SupportsCpuFeature(unsigned int feature)
|
|||||||
|
|
||||||
#if defined(HAVE__GET_CPUID)
|
#if defined(HAVE__GET_CPUID)
|
||||||
__get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
|
__get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
|
||||||
#elif defined(HAVE__CPUID)
|
#else
|
||||||
__cpuid(exx, 1);
|
__cpuid(exx, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Check OS supports XSAVE */
|
||||||
if ((exx[2] & CPU_FEATURE_OSXSAVE) != CPU_FEATURE_OSXSAVE)
|
if ((exx[2] & CPU_FEATURE_OSXSAVE) != CPU_FEATURE_OSXSAVE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
/* Check XMM and YMM registers are enabled */
|
||||||
if ((_xgetbv(0) & 6) != 6)
|
if ((_xgetbv(0) & 6) != 6)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
/* Now check features */
|
||||||
return (exx[2] & feature) == feature;
|
return (exx[2] & feature) == feature;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -235,13 +283,16 @@ HalfvecInit(void)
|
|||||||
HalfvecL2SquaredDistance = HalfvecL2SquaredDistanceDefault;
|
HalfvecL2SquaredDistance = HalfvecL2SquaredDistanceDefault;
|
||||||
HalfvecInnerProduct = HalfvecInnerProductDefault;
|
HalfvecInnerProduct = HalfvecInnerProductDefault;
|
||||||
HalfvecCosineSimilarity = HalfvecCosineSimilarityDefault;
|
HalfvecCosineSimilarity = HalfvecCosineSimilarityDefault;
|
||||||
|
HalfvecL1Distance = HalfvecL1DistanceDefault;
|
||||||
|
|
||||||
#ifdef HALFVEC_DISPATCH
|
#ifdef HALFVEC_DISPATCH
|
||||||
if (SupportsCpuFeature(CPU_FEATURE_AVX | CPU_FEATURE_FMA | CPU_FEATURE_F16C))
|
if (SupportsCpuFeature(CPU_FEATURE_AVX | CPU_FEATURE_F16C | CPU_FEATURE_FMA))
|
||||||
{
|
{
|
||||||
HalfvecL2SquaredDistance = HalfvecL2SquaredDistanceF16cFma;
|
HalfvecL2SquaredDistance = HalfvecL2SquaredDistanceF16c;
|
||||||
HalfvecInnerProduct = HalfvecInnerProductF16cFma;
|
HalfvecInnerProduct = HalfvecInnerProductF16c;
|
||||||
HalfvecCosineSimilarity = HalfvecCosineSimilarityF16cFma;
|
HalfvecCosineSimilarity = HalfvecCosineSimilarityF16c;
|
||||||
|
/* Does not require FMA, but keep logic simple */
|
||||||
|
HalfvecL1Distance = HalfvecL1DistanceF16c;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
extern float (*HalfvecL2SquaredDistance) (int dim, half * ax, half * bx);
|
extern float (*HalfvecL2SquaredDistance) (int dim, half * ax, half * bx);
|
||||||
extern float (*HalfvecInnerProduct) (int dim, half * ax, half * bx);
|
extern float (*HalfvecInnerProduct) (int dim, half * ax, half * bx);
|
||||||
extern double (*HalfvecCosineSimilarity) (int dim, half * ax, half * bx);
|
extern double (*HalfvecCosineSimilarity) (int dim, half * ax, half * bx);
|
||||||
|
extern float (*HalfvecL1Distance) (int dim, half * ax, half * bx);
|
||||||
|
|
||||||
void HalfvecInit(void);
|
void HalfvecInit(void);
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "bitvector.h"
|
#include "bitvec.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "common/shortest_dec.h"
|
#include "common/shortest_dec.h"
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "lib/stringinfo.h"
|
#include "lib/stringinfo.h"
|
||||||
#include "libpq/pqformat.h"
|
#include "libpq/pqformat.h"
|
||||||
#include "port.h" /* for strtof() */
|
#include "port.h" /* for strtof() */
|
||||||
|
#include "sparsevec.h"
|
||||||
#include "utils/array.h"
|
#include "utils/array.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/float.h"
|
#include "utils/float.h"
|
||||||
@@ -682,17 +683,10 @@ halfvec_l1_distance(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
HalfVector *a = PG_GETARG_HALFVEC_P(0);
|
HalfVector *a = PG_GETARG_HALFVEC_P(0);
|
||||||
HalfVector *b = PG_GETARG_HALFVEC_P(1);
|
HalfVector *b = PG_GETARG_HALFVEC_P(1);
|
||||||
half *ax = a->x;
|
|
||||||
half *bx = b->x;
|
|
||||||
float distance = 0.0;
|
|
||||||
|
|
||||||
CheckDims(a, b);
|
CheckDims(a, b);
|
||||||
|
|
||||||
/* Auto-vectorized */
|
PG_RETURN_FLOAT8((double) HalfvecL1Distance(a->dim, a->x, b->x));
|
||||||
for (int i = 0; i < a->dim; i++)
|
|
||||||
distance += fabsf(HalfToFloat4(ax[i]) - HalfToFloat4(bx[i]));
|
|
||||||
|
|
||||||
PG_RETURN_FLOAT8((double) distance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1174,3 +1168,26 @@ halfvec_avg(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
PG_RETURN_POINTER(result);
|
PG_RETURN_POINTER(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert sparse vector to half vector
|
||||||
|
*/
|
||||||
|
PGDLLEXPORT PG_FUNCTION_INFO_V1(sparsevec_to_halfvec);
|
||||||
|
Datum
|
||||||
|
sparsevec_to_halfvec(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
SparseVector *svec = PG_GETARG_SPARSEVEC_P(0);
|
||||||
|
int32 typmod = PG_GETARG_INT32(1);
|
||||||
|
HalfVector *result;
|
||||||
|
int dim = svec->dim;
|
||||||
|
float *values = SPARSEVEC_VALUES(svec);
|
||||||
|
|
||||||
|
CheckDim(dim);
|
||||||
|
CheckExpectedDim(typmod, dim);
|
||||||
|
|
||||||
|
result = InitHalfVector(dim);
|
||||||
|
for (int i = 0; i < svec->nnz; i++)
|
||||||
|
result->x[svec->indices[i] - 1] = Float4ToHalf(values[i]);
|
||||||
|
|
||||||
|
PG_RETURN_POINTER(result);
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,10 +5,11 @@
|
|||||||
|
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
|
#include "bitutils.h"
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
|
|
||||||
#if defined(__x86_64__) || defined(_M_AMD64)
|
#if defined(USE_DISPATCH)
|
||||||
#define HALFVEC_DISPATCH
|
#define HALFVEC_DISPATCH
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -44,6 +45,5 @@ typedef struct HalfVector
|
|||||||
|
|
||||||
HalfVector *InitHalfVector(int dim);
|
HalfVector *InitHalfVector(int dim);
|
||||||
int halfvec_cmp_internal(HalfVector * a, HalfVector * b);
|
int halfvec_cmp_internal(HalfVector * a, HalfVector * b);
|
||||||
PGDLLEXPORT Datum halfvec_l2_normalize(PG_FUNCTION_ARGS);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ hnswhandler(PG_FUNCTION_ARGS)
|
|||||||
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
|
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
|
||||||
|
|
||||||
amroutine->amstrategies = 0;
|
amroutine->amstrategies = 0;
|
||||||
amroutine->amsupport = 2;
|
amroutine->amsupport = 4;
|
||||||
#if PG_VERSION_NUM >= 130000
|
#if PG_VERSION_NUM >= 130000
|
||||||
amroutine->amoptsprocnum = 0;
|
amroutine->amoptsprocnum = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
/* 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_TYPE_SUPPORT_PROC 4
|
||||||
|
|
||||||
#define HNSW_VERSION 1
|
#define HNSW_VERSION 1
|
||||||
#define HNSW_MAGIC_NUMBER 0xA953A953
|
#define HNSW_MAGIC_NUMBER 0xA953A953
|
||||||
@@ -61,7 +63,8 @@ typedef enum HnswType
|
|||||||
HNSW_TYPE_VECTOR,
|
HNSW_TYPE_VECTOR,
|
||||||
HNSW_TYPE_HALFVEC,
|
HNSW_TYPE_HALFVEC,
|
||||||
HNSW_TYPE_BIT,
|
HNSW_TYPE_BIT,
|
||||||
HNSW_TYPE_SPARSEVEC
|
HNSW_TYPE_SPARSEVEC,
|
||||||
|
HNSW_TYPE_UNSUPPORTED
|
||||||
} HnswType;
|
} HnswType;
|
||||||
|
|
||||||
/* Build phases */
|
/* Build phases */
|
||||||
@@ -265,6 +268,7 @@ typedef struct HnswBuildState
|
|||||||
/* Support functions */
|
/* Support functions */
|
||||||
FmgrInfo *procinfo;
|
FmgrInfo *procinfo;
|
||||||
FmgrInfo *normprocinfo;
|
FmgrInfo *normprocinfo;
|
||||||
|
FmgrInfo *normalizeprocinfo;
|
||||||
Oid collation;
|
Oid collation;
|
||||||
|
|
||||||
/* Variables */
|
/* Variables */
|
||||||
@@ -341,6 +345,7 @@ typedef struct HnswScanOpaqueData
|
|||||||
/* Support functions */
|
/* Support functions */
|
||||||
FmgrInfo *procinfo;
|
FmgrInfo *procinfo;
|
||||||
FmgrInfo *normprocinfo;
|
FmgrInfo *normprocinfo;
|
||||||
|
FmgrInfo *normalizeprocinfo;
|
||||||
Oid collation;
|
Oid collation;
|
||||||
} HnswScanOpaqueData;
|
} HnswScanOpaqueData;
|
||||||
|
|
||||||
@@ -377,7 +382,7 @@ int HnswGetM(Relation index);
|
|||||||
int HnswGetEfConstruction(Relation index);
|
int HnswGetEfConstruction(Relation index);
|
||||||
FmgrInfo *HnswOptionalProcInfo(Relation index, uint16 procnum);
|
FmgrInfo *HnswOptionalProcInfo(Relation index, uint16 procnum);
|
||||||
HnswType HnswGetType(Relation index);
|
HnswType HnswGetType(Relation index);
|
||||||
Datum HnswNormValue(Datum value, HnswType type);
|
Datum HnswNormValue(FmgrInfo *procinfo, Oid collation, Datum value);
|
||||||
bool HnswCheckNorm(FmgrInfo *procinfo, Oid collation, Datum value);
|
bool HnswCheckNorm(FmgrInfo *procinfo, Oid collation, Datum value);
|
||||||
void HnswCheckValue(Datum value, HnswType type);
|
void HnswCheckValue(Datum value, HnswType type);
|
||||||
Buffer HnswNewBuffer(Relation index, ForkNumber forkNum);
|
Buffer HnswNewBuffer(Relation index, ForkNumber forkNum);
|
||||||
|
|||||||
@@ -496,7 +496,7 @@ InsertTuple(Relation index, Datum *values, bool *isnull, ItemPointer heaptid, Hn
|
|||||||
if (!HnswCheckNorm(buildstate->normprocinfo, buildstate->collation, value))
|
if (!HnswCheckNorm(buildstate->normprocinfo, buildstate->collation, value))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
value = HnswNormValue(value, buildstate->type);
|
value = HnswNormValue(buildstate->normalizeprocinfo, buildstate->collation, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get datum size */
|
/* Get datum size */
|
||||||
@@ -725,6 +725,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];
|
||||||
|
|
||||||
InitGraph(&buildstate->graphData, NULL, maintenance_work_mem * 1024L);
|
InitGraph(&buildstate->graphData, NULL, maintenance_work_mem * 1024L);
|
||||||
|
|||||||
@@ -614,13 +614,12 @@ HnswInsertTuple(Relation index, Datum *values, bool *isnull, ItemPointer heap_ti
|
|||||||
Datum value;
|
Datum value;
|
||||||
FmgrInfo *normprocinfo;
|
FmgrInfo *normprocinfo;
|
||||||
Oid collation = index->rd_indcollation[0];
|
Oid collation = index->rd_indcollation[0];
|
||||||
HnswType type = HnswGetType(index);
|
|
||||||
|
|
||||||
/* Detoast once for all calls */
|
/* Detoast once for all calls */
|
||||||
value = PointerGetDatum(PG_DETOAST_DATUM(values[0]));
|
value = PointerGetDatum(PG_DETOAST_DATUM(values[0]));
|
||||||
|
|
||||||
/* Check value */
|
/* Check value */
|
||||||
HnswCheckValue(value, type);
|
HnswCheckValue(value, HnswGetType(index));
|
||||||
|
|
||||||
/* Normalize if needed */
|
/* Normalize if needed */
|
||||||
normprocinfo = HnswOptionalProcInfo(index, HNSW_NORM_PROC);
|
normprocinfo = HnswOptionalProcInfo(index, HNSW_NORM_PROC);
|
||||||
@@ -629,7 +628,7 @@ HnswInsertTuple(Relation index, Datum *values, bool *isnull, ItemPointer heap_ti
|
|||||||
if (!HnswCheckNorm(normprocinfo, collation, value))
|
if (!HnswCheckNorm(normprocinfo, collation, value))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
value = HnswNormValue(value, type);
|
value = HnswNormValue(HnswOptionalProcInfo(index, HNSW_NORMALIZE_PROC), collation, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
HnswInsertTupleOnDisk(index, value, values, isnull, heap_tid, false);
|
HnswInsertTupleOnDisk(index, value, values, isnull, heap_tid, false);
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ GetScanValue(IndexScanDesc scan)
|
|||||||
|
|
||||||
/* Fine if normalization fails */
|
/* Fine if normalization fails */
|
||||||
if (so->normprocinfo != NULL)
|
if (so->normprocinfo != NULL)
|
||||||
value = HnswNormValue(value, HnswGetType(scan->indexRelation));
|
value = HnswNormValue(so->normalizeprocinfo, so->collation, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@@ -87,6 +87,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;
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "catalog/pg_type_d.h"
|
#include "catalog/pg_type_d.h"
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
#include "halfutils.h"
|
|
||||||
#include "halfvec.h"
|
|
||||||
#include "hnsw.h"
|
#include "hnsw.h"
|
||||||
#include "lib/pairingheap.h"
|
#include "lib/pairingheap.h"
|
||||||
#include "sparsevec.h"
|
#include "sparsevec.h"
|
||||||
@@ -15,8 +13,6 @@
|
|||||||
#include "utils/datum.h"
|
#include "utils/datum.h"
|
||||||
#include "utils/memdebug.h"
|
#include "utils/memdebug.h"
|
||||||
#include "utils/rel.h"
|
#include "utils/rel.h"
|
||||||
#include "utils/syscache.h"
|
|
||||||
#include "vector.h"
|
|
||||||
|
|
||||||
#if PG_VERSION_NUM >= 130000
|
#if PG_VERSION_NUM >= 130000
|
||||||
#include "common/hashfn.h"
|
#include "common/hashfn.h"
|
||||||
@@ -162,32 +158,17 @@ HnswOptionalProcInfo(Relation index, uint16 procnum)
|
|||||||
HnswType
|
HnswType
|
||||||
HnswGetType(Relation index)
|
HnswGetType(Relation index)
|
||||||
{
|
{
|
||||||
|
FmgrInfo *procinfo = HnswOptionalProcInfo(index, HNSW_TYPE_SUPPORT_PROC);
|
||||||
Oid typid = TupleDescAttr(index->rd_att, 0)->atttypid;
|
Oid typid = TupleDescAttr(index->rd_att, 0)->atttypid;
|
||||||
HeapTuple tuple;
|
|
||||||
Form_pg_type type;
|
|
||||||
HnswType result;
|
HnswType result;
|
||||||
|
|
||||||
if (typid == BITOID)
|
if (procinfo == NULL)
|
||||||
return HNSW_TYPE_BIT;
|
return HNSW_TYPE_VECTOR;
|
||||||
|
|
||||||
tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
|
result = (HnswType) DatumGetInt32(FunctionCall1(procinfo, ObjectIdGetDatum(typid)));
|
||||||
if (!HeapTupleIsValid(tuple))
|
|
||||||
elog(ERROR, "cache lookup failed for type %u", typid);
|
|
||||||
|
|
||||||
type = (Form_pg_type) GETSTRUCT(tuple);
|
if (result == HNSW_TYPE_UNSUPPORTED)
|
||||||
if (strcmp(NameStr(type->typname), "vector") == 0)
|
|
||||||
result = HNSW_TYPE_VECTOR;
|
|
||||||
else if (strcmp(NameStr(type->typname), "halfvec") == 0)
|
|
||||||
result = HNSW_TYPE_HALFVEC;
|
|
||||||
else if (strcmp(NameStr(type->typname), "sparsevec") == 0)
|
|
||||||
result = HNSW_TYPE_SPARSEVEC;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ReleaseSysCache(tuple);
|
|
||||||
elog(ERROR, "type not supported for hnsw index");
|
elog(ERROR, "type not supported for hnsw index");
|
||||||
}
|
|
||||||
|
|
||||||
ReleaseSysCache(tuple);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -196,17 +177,12 @@ HnswGetType(Relation index)
|
|||||||
* Normalize value
|
* Normalize value
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
HnswNormValue(Datum value, HnswType type)
|
HnswNormValue(FmgrInfo *procinfo, Oid collation, Datum value)
|
||||||
{
|
{
|
||||||
/* TODO Remove type-specific code */
|
if (procinfo == NULL)
|
||||||
if (type == HNSW_TYPE_VECTOR)
|
|
||||||
return DirectFunctionCall1(l2_normalize, value);
|
return DirectFunctionCall1(l2_normalize, value);
|
||||||
else if (type == HNSW_TYPE_HALFVEC)
|
|
||||||
return DirectFunctionCall1(halfvec_l2_normalize, value);
|
return FunctionCall1Coll(procinfo, collation, value);
|
||||||
else if (type == HNSW_TYPE_SPARSEVEC)
|
|
||||||
return DirectFunctionCall1(sparsevec_l2_normalize, value);
|
|
||||||
else
|
|
||||||
elog(ERROR, "Unsupported type");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1326,3 +1302,29 @@ HnswFindElementNeighbors(char *base, HnswElement element, HnswElement entryPoint
|
|||||||
ep = w;
|
ep = w;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PGDLLEXPORT PG_FUNCTION_INFO_V1(halfvec_hnsw_support);
|
||||||
|
Datum
|
||||||
|
halfvec_hnsw_support(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
PG_RETURN_INT32(HNSW_TYPE_HALFVEC);
|
||||||
|
};
|
||||||
|
|
||||||
|
PGDLLEXPORT PG_FUNCTION_INFO_V1(bit_hnsw_support);
|
||||||
|
Datum
|
||||||
|
bit_hnsw_support(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid typid = PG_GETARG_OID(0);
|
||||||
|
|
||||||
|
if (typid == BITOID)
|
||||||
|
PG_RETURN_INT32(HNSW_TYPE_BIT);
|
||||||
|
else
|
||||||
|
PG_RETURN_INT32(HNSW_TYPE_UNSUPPORTED);
|
||||||
|
};
|
||||||
|
|
||||||
|
PGDLLEXPORT PG_FUNCTION_INFO_V1(sparsevec_hnsw_support);
|
||||||
|
Datum
|
||||||
|
sparsevec_hnsw_support(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
PG_RETURN_INT32(HNSW_TYPE_SPARSEVEC);
|
||||||
|
};
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "access/tableam.h"
|
#include "access/tableam.h"
|
||||||
#include "access/parallel.h"
|
#include "access/parallel.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "bitvector.h"
|
#include "bitvec.h"
|
||||||
#include "catalog/index.h"
|
#include "catalog/index.h"
|
||||||
#include "catalog/pg_operator_d.h"
|
#include "catalog/pg_operator_d.h"
|
||||||
#include "catalog/pg_type_d.h"
|
#include "catalog/pg_type_d.h"
|
||||||
@@ -60,8 +60,10 @@ AddSample(Datum *values, IvfflatBuildState * buildstate)
|
|||||||
*/
|
*/
|
||||||
if (buildstate->kmeansnormprocinfo != NULL)
|
if (buildstate->kmeansnormprocinfo != NULL)
|
||||||
{
|
{
|
||||||
if (!IvfflatNormValue(buildstate->kmeansnormprocinfo, buildstate->collation, &value, buildstate->type))
|
if (!IvfflatCheckNorm(buildstate->kmeansnormprocinfo, buildstate->collation, value))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
value = IvfflatNormValue(buildstate->normalizeprocinfo, buildstate->collation, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (samples->length < targsamples)
|
if (samples->length < targsamples)
|
||||||
@@ -156,8 +158,10 @@ AddTupleToSort(Relation index, ItemPointer tid, Datum *values, IvfflatBuildState
|
|||||||
/* Normalize if needed */
|
/* Normalize if needed */
|
||||||
if (buildstate->normprocinfo != NULL)
|
if (buildstate->normprocinfo != NULL)
|
||||||
{
|
{
|
||||||
if (!IvfflatNormValue(buildstate->normprocinfo, buildstate->collation, &value, buildstate->type))
|
if (!IvfflatCheckNorm(buildstate->normprocinfo, buildstate->collation, value))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
value = IvfflatNormValue(buildstate->normalizeprocinfo, buildstate->collation, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the list that minimizes the distance */
|
/* Find the list that minimizes the distance */
|
||||||
@@ -379,6 +383,7 @@ 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->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 */
|
||||||
|
|||||||
@@ -188,7 +188,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
|
||||||
|
|||||||
@@ -28,6 +28,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_TYPE_SUPPORT_PROC 6
|
||||||
|
|
||||||
#define IVFFLAT_VERSION 1
|
#define IVFFLAT_VERSION 1
|
||||||
#define IVFFLAT_MAGIC_NUMBER 0x14FF1A7
|
#define IVFFLAT_MAGIC_NUMBER 0x14FF1A7
|
||||||
@@ -47,7 +49,8 @@ typedef enum IvfflatType
|
|||||||
{
|
{
|
||||||
IVFFLAT_TYPE_VECTOR,
|
IVFFLAT_TYPE_VECTOR,
|
||||||
IVFFLAT_TYPE_HALFVEC,
|
IVFFLAT_TYPE_HALFVEC,
|
||||||
IVFFLAT_TYPE_BIT
|
IVFFLAT_TYPE_BIT,
|
||||||
|
IVFFLAT_TYPE_UNSUPPORTED
|
||||||
} IvfflatType;
|
} IvfflatType;
|
||||||
|
|
||||||
/* Build phases */
|
/* Build phases */
|
||||||
@@ -175,6 +178,7 @@ typedef struct IvfflatBuildState
|
|||||||
FmgrInfo *procinfo;
|
FmgrInfo *procinfo;
|
||||||
FmgrInfo *normprocinfo;
|
FmgrInfo *normprocinfo;
|
||||||
FmgrInfo *kmeansnormprocinfo;
|
FmgrInfo *kmeansnormprocinfo;
|
||||||
|
FmgrInfo *normalizeprocinfo;
|
||||||
Oid collation;
|
Oid collation;
|
||||||
|
|
||||||
/* Variables */
|
/* Variables */
|
||||||
@@ -255,7 +259,9 @@ typedef struct IvfflatScanOpaqueData
|
|||||||
/* Support functions */
|
/* Support functions */
|
||||||
FmgrInfo *procinfo;
|
FmgrInfo *procinfo;
|
||||||
FmgrInfo *normprocinfo;
|
FmgrInfo *normprocinfo;
|
||||||
|
FmgrInfo *normalizeprocinfo;
|
||||||
Oid collation;
|
Oid collation;
|
||||||
|
Datum (*distfunc) (FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2);
|
||||||
|
|
||||||
/* Lists */
|
/* Lists */
|
||||||
pairingheap *listQueue;
|
pairingheap *listQueue;
|
||||||
@@ -275,7 +281,8 @@ void VectorArrayFree(VectorArray arr);
|
|||||||
void IvfflatKmeans(Relation index, VectorArray samples, VectorArray centers, IvfflatType type);
|
void IvfflatKmeans(Relation index, VectorArray samples, VectorArray centers, IvfflatType type);
|
||||||
FmgrInfo *IvfflatOptionalProcInfo(Relation index, uint16 procnum);
|
FmgrInfo *IvfflatOptionalProcInfo(Relation index, uint16 procnum);
|
||||||
IvfflatType IvfflatGetType(Relation index);
|
IvfflatType IvfflatGetType(Relation index);
|
||||||
bool IvfflatNormValue(FmgrInfo *procinfo, Oid collation, Datum *value, IvfflatType type);
|
Datum IvfflatNormValue(FmgrInfo *procinfo, Oid collation, Datum value);
|
||||||
|
bool IvfflatCheckNorm(FmgrInfo *procinfo, Oid collation, Datum value);
|
||||||
int IvfflatGetLists(Relation index);
|
int IvfflatGetLists(Relation index);
|
||||||
void IvfflatGetMetaPageInfo(Relation index, int *lists, int *dimensions);
|
void IvfflatGetMetaPageInfo(Relation index, int *lists, int *dimensions);
|
||||||
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);
|
||||||
|
|||||||
@@ -85,8 +85,12 @@ InsertTuple(Relation index, Datum *values, bool *isnull, ItemPointer heap_tid, R
|
|||||||
normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORM_PROC);
|
normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORM_PROC);
|
||||||
if (normprocinfo != NULL)
|
if (normprocinfo != NULL)
|
||||||
{
|
{
|
||||||
if (!IvfflatNormValue(normprocinfo, index->rd_indcollation[0], &value, IvfflatGetType(index)))
|
Oid collation = index->rd_indcollation[0];
|
||||||
|
|
||||||
|
if (!IvfflatCheckNorm(normprocinfo, collation, value))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
value = IvfflatNormValue(IvfflatOptionalProcInfo(index, IVFFLAT_NORMALIZE_PROC), collation, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the insert page - sets the page and list info */
|
/* Find the insert page - sets the page and list info */
|
||||||
|
|||||||
205
src/ivfkmeans.c
205
src/ivfkmeans.c
@@ -3,7 +3,7 @@
|
|||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "bitvector.h"
|
#include "bitvec.h"
|
||||||
#include "halfutils.h"
|
#include "halfutils.h"
|
||||||
#include "halfvec.h"
|
#include "halfvec.h"
|
||||||
#include "ivfflat.h"
|
#include "ivfflat.h"
|
||||||
@@ -89,33 +89,31 @@ InitCenters(Relation index, VectorArray samples, VectorArray centers, float *low
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Apply norm to vector
|
* Norm centers
|
||||||
*/
|
*/
|
||||||
static inline void
|
static void
|
||||||
ApplyNorm(FmgrInfo *normprocinfo, Oid collation, Datum value, IvfflatType type)
|
NormCenters(FmgrInfo *normalizeprocinfo, Oid collation, VectorArray centers)
|
||||||
{
|
{
|
||||||
double norm = DatumGetFloat8(FunctionCall1Coll(normprocinfo, collation, value));
|
MemoryContext normCtx = AllocSetContextCreate(CurrentMemoryContext,
|
||||||
|
"Ivfflat norm temporary context",
|
||||||
|
ALLOCSET_DEFAULT_SIZES);
|
||||||
|
MemoryContext oldCtx = MemoryContextSwitchTo(normCtx);
|
||||||
|
|
||||||
/* TODO Handle zero norm */
|
for (int j = 0; j < centers->length; j++)
|
||||||
if (norm > 0)
|
|
||||||
{
|
{
|
||||||
if (type == IVFFLAT_TYPE_VECTOR)
|
Datum center = PointerGetDatum(VectorArrayGet(centers, j));
|
||||||
{
|
Datum newCenter = IvfflatNormValue(normalizeprocinfo, collation, center);
|
||||||
Vector *vec = DatumGetVector(value);
|
Size size = VARSIZE_ANY(DatumGetPointer(newCenter));
|
||||||
|
|
||||||
for (int i = 0; i < vec->dim; i++)
|
if (size > centers->itemsize)
|
||||||
vec->x[i] /= norm;
|
elog(ERROR, "safety check failed");
|
||||||
}
|
|
||||||
else if (type == IVFFLAT_TYPE_HALFVEC)
|
|
||||||
{
|
|
||||||
HalfVector *vec = DatumGetHalfVector(value);
|
|
||||||
|
|
||||||
for (int i = 0; i < vec->dim; i++)
|
memcpy(DatumGetPointer(center), DatumGetPointer(newCenter), size);
|
||||||
vec->x[i] = Float4ToHalfUnchecked(HalfToFloat4(vec->x[i]) / norm);
|
MemoryContextReset(normCtx);
|
||||||
}
|
|
||||||
else
|
|
||||||
elog(ERROR, "Unsupported type");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MemoryContextSwitchTo(oldCtx);
|
||||||
|
MemoryContextDelete(normCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -145,6 +143,22 @@ CompareBitVectors(const void *a, const void *b)
|
|||||||
return DirectFunctionCall2(bitcmp, VarBitPGetDatum((VarBit *) a), VarBitPGetDatum((VarBit *) b));
|
return DirectFunctionCall2(bitcmp, VarBitPGetDatum((VarBit *) a), VarBitPGetDatum((VarBit *) b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sort vector array
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
SortVectorArray(VectorArray arr, IvfflatType type)
|
||||||
|
{
|
||||||
|
if (type == IVFFLAT_TYPE_VECTOR)
|
||||||
|
qsort(arr->items, arr->length, arr->itemsize, CompareVectors);
|
||||||
|
else if (type == IVFFLAT_TYPE_HALFVEC)
|
||||||
|
qsort(arr->items, arr->length, arr->itemsize, CompareHalfVectors);
|
||||||
|
else if (type == IVFFLAT_TYPE_BIT)
|
||||||
|
qsort(arr->items, arr->length, arr->itemsize, CompareBitVectors);
|
||||||
|
else
|
||||||
|
elog(ERROR, "Unsupported type");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Quick approach if we have little data
|
* Quick approach if we have little data
|
||||||
*/
|
*/
|
||||||
@@ -154,18 +168,12 @@ QuickCenters(Relation index, VectorArray samples, VectorArray centers, IvfflatTy
|
|||||||
int dimensions = centers->dim;
|
int dimensions = centers->dim;
|
||||||
Oid collation = index->rd_indcollation[0];
|
Oid collation = index->rd_indcollation[0];
|
||||||
FmgrInfo *normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_KMEANS_NORM_PROC);
|
FmgrInfo *normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_KMEANS_NORM_PROC);
|
||||||
|
FmgrInfo *normalizeprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORMALIZE_PROC);
|
||||||
|
|
||||||
/* Copy existing vectors while avoiding duplicates */
|
/* Copy existing vectors while avoiding duplicates */
|
||||||
if (samples->length > 0)
|
if (samples->length > 0)
|
||||||
{
|
{
|
||||||
if (type == IVFFLAT_TYPE_VECTOR)
|
SortVectorArray(samples, type);
|
||||||
qsort(samples->items, samples->length, samples->itemsize, CompareVectors);
|
|
||||||
else if (type == IVFFLAT_TYPE_HALFVEC)
|
|
||||||
qsort(samples->items, samples->length, samples->itemsize, CompareHalfVectors);
|
|
||||||
else if (type == IVFFLAT_TYPE_BIT)
|
|
||||||
qsort(samples->items, samples->length, samples->itemsize, CompareBitVectors);
|
|
||||||
else
|
|
||||||
elog(ERROR, "Unsupported type");
|
|
||||||
|
|
||||||
for (int i = 0; i < samples->length; i++)
|
for (int i = 0; i < samples->length; i++)
|
||||||
{
|
{
|
||||||
@@ -217,12 +225,12 @@ QuickCenters(Relation index, VectorArray samples, VectorArray centers, IvfflatTy
|
|||||||
else
|
else
|
||||||
elog(ERROR, "Unsupported type");
|
elog(ERROR, "Unsupported type");
|
||||||
|
|
||||||
/* Normalize if needed (only needed for random centers) */
|
|
||||||
if (normprocinfo != NULL)
|
|
||||||
ApplyNorm(normprocinfo, collation, center, type);
|
|
||||||
|
|
||||||
centers->length++;
|
centers->length++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fine if existing vectors are normalized twice */
|
||||||
|
if (normprocinfo != NULL)
|
||||||
|
NormCenters(normalizeprocinfo, collation, centers);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef IVFFLAT_MEMORY
|
#ifdef IVFFLAT_MEMORY
|
||||||
@@ -243,27 +251,14 @@ ShowMemoryUsage(MemoryContext context, Size estimatedSize)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute new centers
|
* Sum centers
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
ComputeNewCenters(VectorArray samples, VectorArray aggCenters, VectorArray newCenters, int *centerCounts, int *closestCenters, FmgrInfo *normprocinfo, Oid collation, IvfflatType type)
|
SumCenters(VectorArray samples, VectorArray aggCenters, int *closestCenters, IvfflatType type)
|
||||||
{
|
{
|
||||||
int dimensions = aggCenters->dim;
|
int dimensions = aggCenters->dim;
|
||||||
int numCenters = aggCenters->maxlen;
|
|
||||||
int numSamples = samples->length;
|
int numSamples = samples->length;
|
||||||
|
|
||||||
/* Reset sum and count */
|
|
||||||
for (int j = 0; j < numCenters; j++)
|
|
||||||
{
|
|
||||||
Vector *vec = (Vector *) VectorArrayGet(aggCenters, j);
|
|
||||||
|
|
||||||
for (int k = 0; k < dimensions; k++)
|
|
||||||
vec->x[k] = 0.0;
|
|
||||||
|
|
||||||
centerCounts[j] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Increment sum of closest center */
|
|
||||||
if (type == IVFFLAT_TYPE_VECTOR)
|
if (type == IVFFLAT_TYPE_VECTOR)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < numSamples; j++)
|
for (int j = 0; j < numSamples; j++)
|
||||||
@@ -299,6 +294,68 @@ ComputeNewCenters(VectorArray samples, VectorArray aggCenters, VectorArray newCe
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
elog(ERROR, "Unsupported type");
|
elog(ERROR, "Unsupported type");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set new centers
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
SetNewCenters(VectorArray aggCenters, VectorArray newCenters, IvfflatType type)
|
||||||
|
{
|
||||||
|
int dimensions = aggCenters->dim;
|
||||||
|
int numCenters = aggCenters->maxlen;
|
||||||
|
|
||||||
|
if (type == IVFFLAT_TYPE_HALFVEC)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < numCenters; j++)
|
||||||
|
{
|
||||||
|
Vector *aggCenter = (Vector *) VectorArrayGet(aggCenters, j);
|
||||||
|
HalfVector *newCenter = (HalfVector *) VectorArrayGet(newCenters, j);
|
||||||
|
|
||||||
|
for (int k = 0; k < dimensions; k++)
|
||||||
|
newCenter->x[k] = Float4ToHalfUnchecked(aggCenter->x[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == IVFFLAT_TYPE_BIT)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < numCenters; j++)
|
||||||
|
{
|
||||||
|
Vector *aggCenter = (Vector *) VectorArrayGet(aggCenters, j);
|
||||||
|
VarBit *newCenter = (VarBit *) VectorArrayGet(newCenters, j);
|
||||||
|
unsigned char *nx = VARBITS(newCenter);
|
||||||
|
|
||||||
|
for (uint32 k = 0; k < VARBITBYTES(newCenter); k++)
|
||||||
|
nx[k] = 0;
|
||||||
|
|
||||||
|
for (int k = 0; k < dimensions; k++)
|
||||||
|
nx[k / 8] |= (aggCenter->x[k] > 0.5) << (7 - (k % 8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute new centers
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ComputeNewCenters(VectorArray samples, VectorArray aggCenters, VectorArray newCenters, int *centerCounts, int *closestCenters, FmgrInfo *normprocinfo, FmgrInfo *normalizeprocinfo, Oid collation, IvfflatType type)
|
||||||
|
{
|
||||||
|
int dimensions = aggCenters->dim;
|
||||||
|
int numCenters = aggCenters->maxlen;
|
||||||
|
int numSamples = samples->length;
|
||||||
|
|
||||||
|
/* Reset sum and count */
|
||||||
|
for (int j = 0; j < numCenters; j++)
|
||||||
|
{
|
||||||
|
Vector *vec = (Vector *) VectorArrayGet(aggCenters, j);
|
||||||
|
|
||||||
|
for (int k = 0; k < dimensions; k++)
|
||||||
|
vec->x[k] = 0.0;
|
||||||
|
|
||||||
|
centerCounts[j] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increment sum of closest center */
|
||||||
|
SumCenters(samples, aggCenters, closestCenters, type);
|
||||||
|
|
||||||
/* Increment count of closest center */
|
/* Increment count of closest center */
|
||||||
for (int j = 0; j < numSamples; j++)
|
for (int j = 0; j < numSamples; j++)
|
||||||
@@ -331,43 +388,11 @@ ComputeNewCenters(VectorArray samples, VectorArray aggCenters, VectorArray newCe
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Set new centers if different from agg centers */
|
/* Set new centers if different from agg centers */
|
||||||
if (type == IVFFLAT_TYPE_HALFVEC)
|
SetNewCenters(aggCenters, newCenters, type);
|
||||||
{
|
|
||||||
for (int j = 0; j < numCenters; j++)
|
|
||||||
{
|
|
||||||
Vector *aggCenter = (Vector *) VectorArrayGet(aggCenters, j);
|
|
||||||
HalfVector *newCenter = (HalfVector *) VectorArrayGet(newCenters, j);
|
|
||||||
|
|
||||||
for (int k = 0; k < dimensions; k++)
|
|
||||||
newCenter->x[k] = Float4ToHalfUnchecked(aggCenter->x[k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (type == IVFFLAT_TYPE_BIT)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < numCenters; j++)
|
|
||||||
{
|
|
||||||
Vector *aggCenter = (Vector *) VectorArrayGet(aggCenters, j);
|
|
||||||
VarBit *newCenter = (VarBit *) VectorArrayGet(newCenters, j);
|
|
||||||
unsigned char *nx = VARBITS(newCenter);
|
|
||||||
|
|
||||||
for (uint32 k = 0; k < VARBITBYTES(newCenter); k++)
|
|
||||||
nx[k] = 0;
|
|
||||||
|
|
||||||
for (int k = 0; k < dimensions; k++)
|
|
||||||
nx[k / 8] |= (aggCenter->x[k] > 0.5) << (7 - (k % 8));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Normalize if needed */
|
/* Normalize if needed */
|
||||||
if (normprocinfo != NULL)
|
if (normprocinfo != NULL)
|
||||||
{
|
NormCenters(normalizeprocinfo, collation, newCenters);
|
||||||
for (int j = 0; j < numCenters; j++)
|
|
||||||
{
|
|
||||||
Datum newCenter = PointerGetDatum(VectorArrayGet(newCenters, j));
|
|
||||||
|
|
||||||
ApplyNorm(normprocinfo, collation, newCenter, type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -383,6 +408,7 @@ ElkanKmeans(Relation index, VectorArray samples, VectorArray centers, IvfflatTyp
|
|||||||
{
|
{
|
||||||
FmgrInfo *procinfo;
|
FmgrInfo *procinfo;
|
||||||
FmgrInfo *normprocinfo;
|
FmgrInfo *normprocinfo;
|
||||||
|
FmgrInfo *normalizeprocinfo;
|
||||||
Oid collation;
|
Oid collation;
|
||||||
int dimensions = centers->dim;
|
int dimensions = centers->dim;
|
||||||
int numCenters = centers->maxlen;
|
int numCenters = centers->maxlen;
|
||||||
@@ -430,6 +456,7 @@ ElkanKmeans(Relation index, VectorArray samples, VectorArray centers, IvfflatTyp
|
|||||||
/* Set support functions */
|
/* Set support functions */
|
||||||
procinfo = index_getprocinfo(index, 1, IVFFLAT_KMEANS_DISTANCE_PROC);
|
procinfo = index_getprocinfo(index, 1, IVFFLAT_KMEANS_DISTANCE_PROC);
|
||||||
normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_KMEANS_NORM_PROC);
|
normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_KMEANS_NORM_PROC);
|
||||||
|
normalizeprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORMALIZE_PROC);
|
||||||
collation = index->rd_indcollation[0];
|
collation = index->rd_indcollation[0];
|
||||||
|
|
||||||
/* Use memory context */
|
/* Use memory context */
|
||||||
@@ -449,6 +476,8 @@ ElkanKmeans(Relation index, VectorArray samples, VectorArray centers, IvfflatTyp
|
|||||||
newcdist = palloc(newcdistSize);
|
newcdist = palloc(newcdistSize);
|
||||||
|
|
||||||
aggCenters = VectorArrayInit(numCenters, dimensions, VECTOR_SIZE(dimensions));
|
aggCenters = VectorArrayInit(numCenters, dimensions, VECTOR_SIZE(dimensions));
|
||||||
|
aggCenters->length = numCenters;
|
||||||
|
|
||||||
for (int j = 0; j < numCenters; j++)
|
for (int j = 0; j < numCenters; j++)
|
||||||
{
|
{
|
||||||
Vector *vec = (Vector *) VectorArrayGet(aggCenters, j);
|
Vector *vec = (Vector *) VectorArrayGet(aggCenters, j);
|
||||||
@@ -465,6 +494,7 @@ ElkanKmeans(Relation index, VectorArray samples, VectorArray centers, IvfflatTyp
|
|||||||
else if (type == IVFFLAT_TYPE_HALFVEC)
|
else if (type == IVFFLAT_TYPE_HALFVEC)
|
||||||
{
|
{
|
||||||
newCenters = VectorArrayInit(numCenters, dimensions, centers->itemsize);
|
newCenters = VectorArrayInit(numCenters, dimensions, centers->itemsize);
|
||||||
|
newCenters->length = numCenters;
|
||||||
|
|
||||||
for (int j = 0; j < numCenters; j++)
|
for (int j = 0; j < numCenters; j++)
|
||||||
{
|
{
|
||||||
@@ -477,6 +507,7 @@ ElkanKmeans(Relation index, VectorArray samples, VectorArray centers, IvfflatTyp
|
|||||||
else if (type == IVFFLAT_TYPE_BIT)
|
else if (type == IVFFLAT_TYPE_BIT)
|
||||||
{
|
{
|
||||||
newCenters = VectorArrayInit(numCenters, dimensions, centers->itemsize);
|
newCenters = VectorArrayInit(numCenters, dimensions, centers->itemsize);
|
||||||
|
newCenters->length = numCenters;
|
||||||
|
|
||||||
for (int j = 0; j < numCenters; j++)
|
for (int j = 0; j < numCenters; j++)
|
||||||
{
|
{
|
||||||
@@ -627,7 +658,7 @@ ElkanKmeans(Relation index, VectorArray samples, VectorArray centers, IvfflatTyp
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Step 4: For each center c, let m(c) be mean of all points assigned */
|
/* Step 4: For each center c, let m(c) be mean of all points assigned */
|
||||||
ComputeNewCenters(samples, aggCenters, newCenters, centerCounts, closestCenters, normprocinfo, collation, type);
|
ComputeNewCenters(samples, aggCenters, newCenters, centerCounts, closestCenters, normprocinfo, normalizeprocinfo, collation, type);
|
||||||
|
|
||||||
/* Step 5 */
|
/* Step 5 */
|
||||||
for (int j = 0; j < numCenters; j++)
|
for (int j = 0; j < numCenters; j++)
|
||||||
@@ -710,13 +741,7 @@ CheckCenters(Relation index, VectorArray centers, IvfflatType type)
|
|||||||
if (type != IVFFLAT_TYPE_BIT)
|
if (type != IVFFLAT_TYPE_BIT)
|
||||||
{
|
{
|
||||||
/* Ensure no duplicate centers */
|
/* Ensure no duplicate centers */
|
||||||
/* Fine to sort in-place */
|
SortVectorArray(centers, type);
|
||||||
if (type == IVFFLAT_TYPE_VECTOR)
|
|
||||||
qsort(centers->items, centers->length, centers->itemsize, CompareVectors);
|
|
||||||
else if (type == IVFFLAT_TYPE_HALFVEC)
|
|
||||||
qsort(centers->items, centers->length, centers->itemsize, CompareHalfVectors);
|
|
||||||
else
|
|
||||||
elog(ERROR, "Unsupported type");
|
|
||||||
|
|
||||||
for (int i = 1; i < centers->length; i++)
|
for (int i = 1; i < centers->length; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,10 +3,8 @@
|
|||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
#include "access/relscan.h"
|
#include "access/relscan.h"
|
||||||
#include "bitvector.h"
|
|
||||||
#include "catalog/pg_operator_d.h"
|
#include "catalog/pg_operator_d.h"
|
||||||
#include "catalog/pg_type_d.h"
|
#include "catalog/pg_type_d.h"
|
||||||
#include "halfvec.h"
|
|
||||||
#include "lib/pairingheap.h"
|
#include "lib/pairingheap.h"
|
||||||
#include "ivfflat.h"
|
#include "ivfflat.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
@@ -58,7 +56,7 @@ GetScanLists(IndexScanDesc scan, Datum value)
|
|||||||
double distance;
|
double distance;
|
||||||
|
|
||||||
/* Use procinfo from the index instead of scan key for performance */
|
/* Use procinfo from the index instead of scan key for performance */
|
||||||
distance = DatumGetFloat8(FunctionCall2Coll(so->procinfo, so->collation, PointerGetDatum(&list->center), value));
|
distance = DatumGetFloat8(so->distfunc(so->procinfo, so->collation, PointerGetDatum(&list->center), value));
|
||||||
|
|
||||||
if (listCount < so->probes)
|
if (listCount < so->probes)
|
||||||
{
|
{
|
||||||
@@ -151,7 +149,7 @@ GetScanItems(IndexScanDesc scan, Datum value)
|
|||||||
* performance
|
* performance
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(slot);
|
ExecClearTuple(slot);
|
||||||
slot->tts_values[0] = FunctionCall2Coll(so->procinfo, so->collation, datum, value);
|
slot->tts_values[0] = so->distfunc(so->procinfo, so->collation, datum, value);
|
||||||
slot->tts_isnull[0] = false;
|
slot->tts_isnull[0] = false;
|
||||||
slot->tts_values[1] = PointerGetDatum(&itup->t_tid);
|
slot->tts_values[1] = PointerGetDatum(&itup->t_tid);
|
||||||
slot->tts_isnull[1] = false;
|
slot->tts_isnull[1] = false;
|
||||||
@@ -179,6 +177,15 @@ GetScanItems(IndexScanDesc scan, Datum value)
|
|||||||
tuplesort_performsort(so->sortstate);
|
tuplesort_performsort(so->sortstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Zero distance
|
||||||
|
*/
|
||||||
|
static Datum
|
||||||
|
ZeroDistance(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
|
||||||
|
{
|
||||||
|
return Float8GetDatum(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get scan value
|
* Get scan value
|
||||||
*/
|
*/
|
||||||
@@ -190,28 +197,21 @@ GetScanValue(IndexScanDesc scan)
|
|||||||
|
|
||||||
if (scan->orderByData->sk_flags & SK_ISNULL)
|
if (scan->orderByData->sk_flags & SK_ISNULL)
|
||||||
{
|
{
|
||||||
IvfflatType type = IvfflatGetType(scan->indexRelation);
|
value = PointerGetDatum(NULL);
|
||||||
|
so->distfunc = ZeroDistance;
|
||||||
if (type == IVFFLAT_TYPE_VECTOR)
|
|
||||||
value = PointerGetDatum(InitVector(so->dimensions));
|
|
||||||
else if (type == IVFFLAT_TYPE_HALFVEC)
|
|
||||||
value = PointerGetDatum(InitHalfVector(so->dimensions));
|
|
||||||
else if (type == IVFFLAT_TYPE_BIT)
|
|
||||||
value = PointerGetDatum(InitBitVector(so->dimensions));
|
|
||||||
else
|
|
||||||
elog(ERROR, "Unsupported type");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
value = scan->orderByData->sk_argument;
|
value = scan->orderByData->sk_argument;
|
||||||
|
so->distfunc = FunctionCall2Coll;
|
||||||
|
|
||||||
/* Value should not be compressed or toasted */
|
/* Value should not be compressed or toasted */
|
||||||
Assert(!VARATT_IS_COMPRESSED(DatumGetPointer(value)));
|
Assert(!VARATT_IS_COMPRESSED(DatumGetPointer(value)));
|
||||||
Assert(!VARATT_IS_EXTENDED(DatumGetPointer(value)));
|
Assert(!VARATT_IS_EXTENDED(DatumGetPointer(value)));
|
||||||
|
|
||||||
/* Fine if normalization fails */
|
/* Check normprocinfo since normalizeprocinfo not set for vector */
|
||||||
if (so->normprocinfo != NULL)
|
if (so->normprocinfo != NULL)
|
||||||
IvfflatNormValue(so->normprocinfo, so->collation, &value, IvfflatGetType(scan->indexRelation));
|
value = IvfflatNormValue(so->normalizeprocinfo, so->collation, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@@ -249,6 +249,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 */
|
||||||
|
|||||||
@@ -3,12 +3,8 @@
|
|||||||
#include "access/generic_xlog.h"
|
#include "access/generic_xlog.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
#include "halfutils.h"
|
|
||||||
#include "halfvec.h"
|
|
||||||
#include "ivfflat.h"
|
#include "ivfflat.h"
|
||||||
#include "storage/bufmgr.h"
|
#include "storage/bufmgr.h"
|
||||||
#include "vector.h"
|
|
||||||
#include "utils/syscache.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate a vector array
|
* Allocate a vector array
|
||||||
@@ -71,60 +67,40 @@ IvfflatOptionalProcInfo(Relation index, uint16 procnum)
|
|||||||
IvfflatType
|
IvfflatType
|
||||||
IvfflatGetType(Relation index)
|
IvfflatGetType(Relation index)
|
||||||
{
|
{
|
||||||
|
FmgrInfo *procinfo = IvfflatOptionalProcInfo(index, IVFFLAT_TYPE_SUPPORT_PROC);
|
||||||
Oid typid = TupleDescAttr(index->rd_att, 0)->atttypid;
|
Oid typid = TupleDescAttr(index->rd_att, 0)->atttypid;
|
||||||
HeapTuple tuple;
|
|
||||||
Form_pg_type type;
|
|
||||||
IvfflatType result;
|
IvfflatType result;
|
||||||
|
|
||||||
if (typid == BITOID)
|
if (procinfo == NULL)
|
||||||
return IVFFLAT_TYPE_BIT;
|
return IVFFLAT_TYPE_VECTOR;
|
||||||
|
|
||||||
tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
|
result = (IvfflatType) DatumGetInt32(FunctionCall1(procinfo, ObjectIdGetDatum(typid)));
|
||||||
if (!HeapTupleIsValid(tuple))
|
|
||||||
elog(ERROR, "cache lookup failed for type %u", typid);
|
|
||||||
|
|
||||||
type = (Form_pg_type) GETSTRUCT(tuple);
|
if (result == IVFFLAT_TYPE_UNSUPPORTED)
|
||||||
if (strcmp(NameStr(type->typname), "vector") == 0)
|
|
||||||
result = IVFFLAT_TYPE_VECTOR;
|
|
||||||
else if (strcmp(NameStr(type->typname), "halfvec") == 0)
|
|
||||||
result = IVFFLAT_TYPE_HALFVEC;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ReleaseSysCache(tuple);
|
|
||||||
elog(ERROR, "type not supported for ivfflat index");
|
elog(ERROR, "type not supported for ivfflat index");
|
||||||
}
|
|
||||||
|
|
||||||
ReleaseSysCache(tuple);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Divide by the norm
|
* Normalize value
|
||||||
*
|
*/
|
||||||
* Returns false if value should not be indexed
|
Datum
|
||||||
*
|
IvfflatNormValue(FmgrInfo *procinfo, Oid collation, Datum value)
|
||||||
* The caller needs to free the pointer stored in value
|
{
|
||||||
* if it's different than the original value
|
if (procinfo == NULL)
|
||||||
|
return DirectFunctionCall1(l2_normalize, value);
|
||||||
|
|
||||||
|
return FunctionCall1Coll(procinfo, collation, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if non-zero norm
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
IvfflatNormValue(FmgrInfo *procinfo, Oid collation, Datum *value, IvfflatType type)
|
IvfflatCheckNorm(FmgrInfo *procinfo, Oid collation, Datum value)
|
||||||
{
|
{
|
||||||
double norm = DatumGetFloat8(FunctionCall1Coll(procinfo, collation, *value));
|
return DatumGetFloat8(FunctionCall1Coll(procinfo, collation, value)) > 0;
|
||||||
|
|
||||||
if (norm > 0)
|
|
||||||
{
|
|
||||||
if (type == IVFFLAT_TYPE_VECTOR)
|
|
||||||
*value = DirectFunctionCall1(l2_normalize, *value);
|
|
||||||
else if (type == IVFFLAT_TYPE_HALFVEC)
|
|
||||||
*value = DirectFunctionCall1(halfvec_l2_normalize, *value);
|
|
||||||
else
|
|
||||||
elog(ERROR, "Unsupported type");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -269,3 +245,22 @@ IvfflatUpdateList(Relation index, ListInfo listInfo,
|
|||||||
UnlockReleaseBuffer(buf);
|
UnlockReleaseBuffer(buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PGDLLEXPORT PG_FUNCTION_INFO_V1(halfvec_ivfflat_support);
|
||||||
|
Datum
|
||||||
|
halfvec_ivfflat_support(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
PG_RETURN_INT32(IVFFLAT_TYPE_HALFVEC);
|
||||||
|
};
|
||||||
|
|
||||||
|
PGDLLEXPORT PG_FUNCTION_INFO_V1(bit_ivfflat_support);
|
||||||
|
Datum
|
||||||
|
bit_ivfflat_support(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid typid = PG_GETARG_OID(0);
|
||||||
|
|
||||||
|
if (typid == BITOID)
|
||||||
|
PG_RETURN_INT32(IVFFLAT_TYPE_BIT);
|
||||||
|
else
|
||||||
|
PG_RETURN_INT32(IVFFLAT_TYPE_UNSUPPORTED);
|
||||||
|
};
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
|
#include "halfutils.h"
|
||||||
|
#include "halfvec.h"
|
||||||
#include "libpq/pqformat.h"
|
#include "libpq/pqformat.h"
|
||||||
#include "sparsevec.h"
|
#include "sparsevec.h"
|
||||||
#include "utils/array.h"
|
#include "utils/array.h"
|
||||||
@@ -18,6 +20,12 @@
|
|||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef struct SparseInputElement
|
||||||
|
{
|
||||||
|
int32 index;
|
||||||
|
float value;
|
||||||
|
} SparseInputElement;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure same dimensions
|
* Ensure same dimensions
|
||||||
*/
|
*/
|
||||||
@@ -164,6 +172,21 @@ sparsevec_isspace(char ch)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare indices
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
CompareIndices(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
if (((SparseInputElement *) a)->index < ((SparseInputElement *) b)->index)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (((SparseInputElement *) a)->index > ((SparseInputElement *) b)->index)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert textual representation to internal representation
|
* Convert textual representation to internal representation
|
||||||
*/
|
*/
|
||||||
@@ -178,8 +201,7 @@ sparsevec_in(PG_FUNCTION_ARGS)
|
|||||||
char *stringEnd;
|
char *stringEnd;
|
||||||
SparseVector *result;
|
SparseVector *result;
|
||||||
float *rvalues;
|
float *rvalues;
|
||||||
int32 *indices;
|
SparseInputElement *elements;
|
||||||
float *values;
|
|
||||||
int maxNnz;
|
int maxNnz;
|
||||||
int nnz = 0;
|
int nnz = 0;
|
||||||
|
|
||||||
@@ -197,8 +219,7 @@ sparsevec_in(PG_FUNCTION_ARGS)
|
|||||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||||
errmsg("sparsevec cannot have more than %d non-zero elements", SPARSEVEC_MAX_NNZ)));
|
errmsg("sparsevec cannot have more than %d non-zero elements", SPARSEVEC_MAX_NNZ)));
|
||||||
|
|
||||||
indices = palloc(maxNnz * sizeof(int32));
|
elements = palloc(maxNnz * sizeof(SparseInputElement));
|
||||||
values = palloc(maxNnz * sizeof(float));
|
|
||||||
|
|
||||||
pt = lit;
|
pt = lit;
|
||||||
|
|
||||||
@@ -291,8 +312,8 @@ sparsevec_in(PG_FUNCTION_ARGS)
|
|||||||
/* Do not store zero values */
|
/* Do not store zero values */
|
||||||
if (value != 0)
|
if (value != 0)
|
||||||
{
|
{
|
||||||
indices[nnz] = index;
|
elements[nnz].index = index;
|
||||||
values[nnz] = value;
|
elements[nnz].value = value;
|
||||||
nnz++;
|
nnz++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,12 +374,14 @@ sparsevec_in(PG_FUNCTION_ARGS)
|
|||||||
CheckDim(dim);
|
CheckDim(dim);
|
||||||
CheckExpectedDim(typmod, dim);
|
CheckExpectedDim(typmod, dim);
|
||||||
|
|
||||||
|
qsort(elements, nnz, sizeof(SparseInputElement), CompareIndices);
|
||||||
|
|
||||||
result = InitSparseVector(dim, nnz);
|
result = InitSparseVector(dim, nnz);
|
||||||
rvalues = SPARSEVEC_VALUES(result);
|
rvalues = SPARSEVEC_VALUES(result);
|
||||||
for (int i = 0; i < nnz; i++)
|
for (int i = 0; i < nnz; i++)
|
||||||
{
|
{
|
||||||
result->indices[i] = indices[i];
|
result->indices[i] = elements[i].index;
|
||||||
rvalues[i] = values[i];
|
rvalues[i] = elements[i].value;
|
||||||
|
|
||||||
CheckIndex(result->indices, i, dim);
|
CheckIndex(result->indices, i, dim);
|
||||||
}
|
}
|
||||||
@@ -504,6 +527,10 @@ sparsevec_recv(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
values[i] = pq_getmsgfloat4(buf);
|
values[i] = pq_getmsgfloat4(buf);
|
||||||
CheckElement(values[i]);
|
CheckElement(values[i]);
|
||||||
|
if (values[i] == 0)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_DATA_EXCEPTION),
|
||||||
|
errmsg("binary representation of sparsevec cannot contain zero values")));
|
||||||
}
|
}
|
||||||
|
|
||||||
PG_RETURN_POINTER(result);
|
PG_RETURN_POINTER(result);
|
||||||
@@ -591,6 +618,49 @@ vector_to_sparsevec(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_POINTER(result);
|
PG_RETURN_POINTER(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert half vector to sparse vector
|
||||||
|
*/
|
||||||
|
PGDLLEXPORT PG_FUNCTION_INFO_V1(halfvec_to_sparsevec);
|
||||||
|
Datum
|
||||||
|
halfvec_to_sparsevec(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
HalfVector *vec = PG_GETARG_HALFVEC_P(0);
|
||||||
|
int32 typmod = PG_GETARG_INT32(1);
|
||||||
|
SparseVector *result;
|
||||||
|
int dim = vec->dim;
|
||||||
|
int nnz = 0;
|
||||||
|
float *values;
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
|
CheckDim(dim);
|
||||||
|
CheckExpectedDim(typmod, dim);
|
||||||
|
|
||||||
|
for (int i = 0; i < dim; i++)
|
||||||
|
{
|
||||||
|
if (!HalfIsZero(vec->x[i]))
|
||||||
|
nnz++;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = InitSparseVector(dim, nnz);
|
||||||
|
values = SPARSEVEC_VALUES(result);
|
||||||
|
for (int i = 0; i < dim; i++)
|
||||||
|
{
|
||||||
|
if (!HalfIsZero(vec->x[i]))
|
||||||
|
{
|
||||||
|
/* Safety check */
|
||||||
|
if (j >= result->nnz)
|
||||||
|
elog(ERROR, "safety check failed");
|
||||||
|
|
||||||
|
result->indices[j] = i + 1;
|
||||||
|
values[j] = HalfToFloat4(vec->x[i]);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PG_RETURN_POINTER(result);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the L2 squared distance between sparse vectors
|
* Get the L2 squared distance between sparse vectors
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -23,6 +23,5 @@ typedef struct SparseVector
|
|||||||
} SparseVector;
|
} SparseVector;
|
||||||
|
|
||||||
SparseVector *InitSparseVector(int dim, int nnz);
|
SparseVector *InitSparseVector(int dim, int nnz);
|
||||||
PGDLLEXPORT Datum sparsevec_l2_normalize(PG_FUNCTION_ARGS);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
27
src/vector.c
27
src/vector.c
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "bitvector.h"
|
#include "bitutils.h"
|
||||||
|
#include "bitvec.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "common/shortest_dec.h"
|
#include "common/shortest_dec.h"
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
@@ -33,18 +34,10 @@
|
|||||||
#define STATE_DIMS(x) (ARR_DIMS(x)[0] - 1)
|
#define STATE_DIMS(x) (ARR_DIMS(x)[0] - 1)
|
||||||
#define CreateStateDatums(dim) palloc(sizeof(Datum) * (dim + 1))
|
#define CreateStateDatums(dim) palloc(sizeof(Datum) * (dim + 1))
|
||||||
|
|
||||||
/* target_clones requires glibc */
|
#if defined(USE_TARGET_CLONES) && !defined(__FMA__)
|
||||||
#if defined(__gnu_linux__) && defined(__has_attribute)
|
#define VECTOR_TARGET_CLONES __attribute__((target_clones("default", "fma")))
|
||||||
/* Use separate line for portability */
|
|
||||||
#if __has_attribute(target_clones)
|
|
||||||
#define HAVE_TARGET_CLONES
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__x86_64__) && defined(HAVE_TARGET_CLONES) && !defined(__FMA__)
|
|
||||||
#define VECTOR_DISPATCH __attribute__((target_clones("default", "fma")))
|
|
||||||
#else
|
#else
|
||||||
#define VECTOR_DISPATCH
|
#define VECTOR_TARGET_CLONES
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PG_MODULE_MAGIC;
|
PG_MODULE_MAGIC;
|
||||||
@@ -56,6 +49,7 @@ PGDLLEXPORT void _PG_init(void);
|
|||||||
void
|
void
|
||||||
_PG_init(void)
|
_PG_init(void)
|
||||||
{
|
{
|
||||||
|
BitvecInit();
|
||||||
HalfvecInit();
|
HalfvecInit();
|
||||||
HnswInit();
|
HnswInit();
|
||||||
IvfflatInit();
|
IvfflatInit();
|
||||||
@@ -571,7 +565,7 @@ halfvec_to_vector(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_POINTER(result);
|
PG_RETURN_POINTER(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
VECTOR_DISPATCH static float
|
VECTOR_TARGET_CLONES static float
|
||||||
VectorL2SquaredDistance(int dim, float *ax, float *bx)
|
VectorL2SquaredDistance(int dim, float *ax, float *bx)
|
||||||
{
|
{
|
||||||
float distance = 0.0;
|
float distance = 0.0;
|
||||||
@@ -618,7 +612,7 @@ vector_l2_squared_distance(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_FLOAT8((double) VectorL2SquaredDistance(a->dim, a->x, b->x));
|
PG_RETURN_FLOAT8((double) VectorL2SquaredDistance(a->dim, a->x, b->x));
|
||||||
}
|
}
|
||||||
|
|
||||||
VECTOR_DISPATCH static float
|
VECTOR_TARGET_CLONES static float
|
||||||
VectorInnerProduct(int dim, float *ax, float *bx)
|
VectorInnerProduct(int dim, float *ax, float *bx)
|
||||||
{
|
{
|
||||||
float distance = 0.0;
|
float distance = 0.0;
|
||||||
@@ -660,7 +654,7 @@ vector_negative_inner_product(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_FLOAT8((double) -VectorInnerProduct(a->dim, a->x, b->x));
|
PG_RETURN_FLOAT8((double) -VectorInnerProduct(a->dim, a->x, b->x));
|
||||||
}
|
}
|
||||||
|
|
||||||
VECTOR_DISPATCH static double
|
VECTOR_TARGET_CLONES static double
|
||||||
VectorCosineSimilarity(int dim, float *ax, float *bx)
|
VectorCosineSimilarity(int dim, float *ax, float *bx)
|
||||||
{
|
{
|
||||||
float similarity = 0.0;
|
float similarity = 0.0;
|
||||||
@@ -735,7 +729,8 @@ vector_spherical_distance(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_FLOAT8(acos(distance) / M_PI);
|
PG_RETURN_FLOAT8(acos(distance) / M_PI);
|
||||||
}
|
}
|
||||||
|
|
||||||
static float
|
/* Does not require FMA, but keep logic simple */
|
||||||
|
VECTOR_TARGET_CLONES static float
|
||||||
VectorL1Distance(int dim, float *ax, float *bx)
|
VectorL1Distance(int dim, float *ax, float *bx)
|
||||||
{
|
{
|
||||||
float distance = 0.0;
|
float distance = 0.0;
|
||||||
|
|||||||
@@ -28,6 +28,24 @@ SELECT hamming_distance('10101010101010101010', '01010101010101010101');
|
|||||||
20
|
20
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT hamming_distance('101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', '101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101');
|
||||||
|
hamming_distance
|
||||||
|
------------------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT hamming_distance('101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', '010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010');
|
||||||
|
hamming_distance
|
||||||
|
------------------
|
||||||
|
513
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT hamming_distance('110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011', '100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001');
|
||||||
|
hamming_distance
|
||||||
|
------------------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT hamming_distance('', '');
|
SELECT hamming_distance('', '');
|
||||||
hamming_distance
|
hamming_distance
|
||||||
------------------
|
------------------
|
||||||
@@ -86,6 +104,24 @@ SELECT jaccard_distance('10101010101010101010', '01010101010101010101');
|
|||||||
1
|
1
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT jaccard_distance('101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', '101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101');
|
||||||
|
jaccard_distance
|
||||||
|
------------------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT jaccard_distance('101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', '010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010');
|
||||||
|
jaccard_distance
|
||||||
|
------------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT jaccard_distance('110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011', '100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001');
|
||||||
|
jaccard_distance
|
||||||
|
------------------
|
||||||
|
0.5
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT jaccard_distance('', '');
|
SELECT jaccard_distance('', '');
|
||||||
jaccard_distance
|
jaccard_distance
|
||||||
------------------
|
------------------
|
||||||
|
|||||||
@@ -170,6 +170,44 @@ SELECT '{2:1.5,4:3.5}/5'::sparsevec::vector(4);
|
|||||||
ERROR: expected 4 dimensions, not 5
|
ERROR: expected 4 dimensions, not 5
|
||||||
SELECT '{}/16001'::sparsevec::vector;
|
SELECT '{}/16001'::sparsevec::vector;
|
||||||
ERROR: vector cannot have more than 16000 dimensions
|
ERROR: vector cannot have more than 16000 dimensions
|
||||||
|
SELECT '[0,1.5,0,3.5,0]'::halfvec::sparsevec;
|
||||||
|
sparsevec
|
||||||
|
-----------------
|
||||||
|
{2:1.5,4:3.5}/5
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[0,1.5,0,3.5,0]'::halfvec::sparsevec(5);
|
||||||
|
sparsevec
|
||||||
|
-----------------
|
||||||
|
{2:1.5,4:3.5}/5
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[0,1.5,0,3.5,0]'::halfvec::sparsevec(4);
|
||||||
|
ERROR: expected 4 dimensions, not 5
|
||||||
|
SELECT '{2:1.5,4:3.5}/5'::sparsevec::halfvec;
|
||||||
|
halfvec
|
||||||
|
-----------------
|
||||||
|
[0,1.5,0,3.5,0]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '{2:1.5,4:3.5}/5'::sparsevec::halfvec(5);
|
||||||
|
halfvec
|
||||||
|
-----------------
|
||||||
|
[0,1.5,0,3.5,0]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '{2:1.5,4:3.5}/5'::sparsevec::halfvec(4);
|
||||||
|
ERROR: expected 4 dimensions, not 5
|
||||||
|
SELECT '{}/16001'::sparsevec::halfvec;
|
||||||
|
ERROR: halfvec cannot have more than 16000 dimensions
|
||||||
|
SELECT '{1:65520}/1'::sparsevec::halfvec;
|
||||||
|
ERROR: "65520" is out of range for type halfvec
|
||||||
|
SELECT '{1:1e-8}/1'::sparsevec::halfvec;
|
||||||
|
halfvec
|
||||||
|
---------
|
||||||
|
[0]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
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;
|
SELECT array_to_vector(array_agg(n), 16001, false) FROM generate_series(1, 16001) n;
|
||||||
|
|||||||
@@ -304,6 +304,24 @@ SELECT l1_distance('[0,0]'::halfvec, '[0,1]');
|
|||||||
|
|
||||||
SELECT l1_distance('[1,2]'::halfvec, '[3]');
|
SELECT l1_distance('[1,2]'::halfvec, '[3]');
|
||||||
ERROR: different halfvec dimensions 2 and 1
|
ERROR: different halfvec dimensions 2 and 1
|
||||||
|
SELECT l1_distance('[1,2,3,4,5,6,7,8,9]'::halfvec, '[1,2,3,4,5,6,7,8,9]');
|
||||||
|
l1_distance
|
||||||
|
-------------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l1_distance('[1,2,3,4,5,6,7,8,9]'::halfvec, '[0,3,2,5,4,7,6,9,8]');
|
||||||
|
l1_distance
|
||||||
|
-------------
|
||||||
|
9
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[0,0]'::halfvec <+> '[3,4]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
7
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT l2_normalize('[3,4]'::halfvec);
|
SELECT l2_normalize('[3,4]'::halfvec);
|
||||||
l2_normalize
|
l2_normalize
|
||||||
------------------------
|
------------------------
|
||||||
|
|||||||
21
test/expected/hnsw_halfvec_l1.out
Normal file
21
test/expected/hnsw_halfvec_l1.out
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
SET enable_seqscan = off;
|
||||||
|
CREATE TABLE t (val halfvec(3));
|
||||||
|
INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), (NULL);
|
||||||
|
CREATE INDEX ON t USING hnsw (val halfvec_l1_ops);
|
||||||
|
INSERT INTO t (val) VALUES ('[1,2,4]');
|
||||||
|
SELECT * FROM t ORDER BY val <+> '[3,3,3]';
|
||||||
|
val
|
||||||
|
---------
|
||||||
|
[1,2,3]
|
||||||
|
[1,2,4]
|
||||||
|
[1,1,1]
|
||||||
|
[0,0,0]
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <+> (SELECT NULL::halfvec)) t2;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
4
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
DROP TABLE t;
|
||||||
21
test/expected/hnsw_sparsevec_l1.out
Normal file
21
test/expected/hnsw_sparsevec_l1.out
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
SET enable_seqscan = off;
|
||||||
|
CREATE TABLE t (val sparsevec(3));
|
||||||
|
INSERT INTO t (val) VALUES ('{}/3'), ('{1:1,2:2,3:3}/3'), ('{1:1,2:1,3:1}/3'), (NULL);
|
||||||
|
CREATE INDEX ON t USING hnsw (val sparsevec_l1_ops);
|
||||||
|
INSERT INTO t (val) VALUES ('{1:1,2:2,3:4}/3');
|
||||||
|
SELECT * FROM t ORDER BY val <+> '{1:3,2:3,3:3}/3';
|
||||||
|
val
|
||||||
|
-----------------
|
||||||
|
{1:1,2:2,3:3}/3
|
||||||
|
{1:1,2:2,3:4}/3
|
||||||
|
{1:1,2:1,3:1}/3
|
||||||
|
{}/3
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <+> (SELECT NULL::sparsevec)) t2;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
4
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
DROP TABLE t;
|
||||||
21
test/expected/hnsw_vector_l1.out
Normal file
21
test/expected/hnsw_vector_l1.out
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
SET enable_seqscan = off;
|
||||||
|
CREATE TABLE t (val vector(3));
|
||||||
|
INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), (NULL);
|
||||||
|
CREATE INDEX ON t USING hnsw (val vector_l1_ops);
|
||||||
|
INSERT INTO t (val) VALUES ('[1,2,4]');
|
||||||
|
SELECT * FROM t ORDER BY val <+> '[3,3,3]';
|
||||||
|
val
|
||||||
|
---------
|
||||||
|
[1,2,3]
|
||||||
|
[1,2,4]
|
||||||
|
[1,1,1]
|
||||||
|
[0,0,0]
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <+> (SELECT NULL::vector)) t2;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
4
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
DROP TABLE t;
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
SET enable_seqscan = off;
|
|
||||||
CREATE TABLE t (val bit(4));
|
|
||||||
INSERT INTO t (val) VALUES (B'0000'), (B'1100'), (B'1111'), (NULL);
|
|
||||||
CREATE INDEX ON t USING ivfflat (val bit_jaccard_ops) WITH (lists = 1);
|
|
||||||
INSERT INTO t (val) VALUES (B'1110');
|
|
||||||
SELECT * FROM t ORDER BY val <%> B'1111';
|
|
||||||
val
|
|
||||||
------
|
|
||||||
1111
|
|
||||||
1110
|
|
||||||
1100
|
|
||||||
0000
|
|
||||||
(4 rows)
|
|
||||||
|
|
||||||
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <%> (SELECT NULL::bit)) t2;
|
|
||||||
count
|
|
||||||
-------
|
|
||||||
4
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
DROP TABLE t;
|
|
||||||
@@ -164,8 +164,18 @@ SELECT '{1:0,2:1,3:0}/3'::sparsevec;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT '{2:1,1:1}/2'::sparsevec;
|
SELECT '{2:1,1:1}/2'::sparsevec;
|
||||||
ERROR: indexes must be in ascending order
|
sparsevec
|
||||||
LINE 1: SELECT '{2:1,1:1}/2'::sparsevec;
|
-------------
|
||||||
|
{1:1,2:1}/2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '{1:1,1:1}/2'::sparsevec;
|
||||||
|
ERROR: indexes must not contain duplicates
|
||||||
|
LINE 1: SELECT '{1:1,1:1}/2'::sparsevec;
|
||||||
|
^
|
||||||
|
SELECT '{1:1,2:1,1:1}/2'::sparsevec;
|
||||||
|
ERROR: indexes must not contain duplicates
|
||||||
|
LINE 1: SELECT '{1:1,2:1,1:1}/2'::sparsevec;
|
||||||
^
|
^
|
||||||
SELECT '{}/5'::sparsevec;
|
SELECT '{}/5'::sparsevec;
|
||||||
sparsevec
|
sparsevec
|
||||||
|
|||||||
@@ -202,6 +202,12 @@ SELECT l2_distance('[3e38]'::vector, '[-3e38]');
|
|||||||
Infinity
|
Infinity
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l2_distance('[1,1,1,1,1,1,1,1,1]'::vector, '[1,1,1,1,1,1,1,4,5]');
|
||||||
|
l2_distance
|
||||||
|
-------------
|
||||||
|
5
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT '[0,0]'::vector <-> '[3,4]';
|
SELECT '[0,0]'::vector <-> '[3,4]';
|
||||||
?column?
|
?column?
|
||||||
----------
|
----------
|
||||||
@@ -222,6 +228,12 @@ SELECT inner_product('[3e38]'::vector, '[3e38]');
|
|||||||
Infinity
|
Infinity
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT inner_product('[1,1,1,1,1,1,1,1,1]'::vector, '[1,2,3,4,5,6,7,8,9]');
|
||||||
|
inner_product
|
||||||
|
---------------
|
||||||
|
45
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT '[1,2]'::vector <#> '[3,4]';
|
SELECT '[1,2]'::vector <#> '[3,4]';
|
||||||
?column?
|
?column?
|
||||||
----------
|
----------
|
||||||
@@ -278,6 +290,18 @@ SELECT cosine_distance('[3e38]'::vector, '[3e38]');
|
|||||||
NaN
|
NaN
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT cosine_distance('[1,2,3,4,5,6,7,8,9]'::vector, '[1,2,3,4,5,6,7,8,9]');
|
||||||
|
cosine_distance
|
||||||
|
-----------------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT cosine_distance('[1,2,3,4,5,6,7,8,9]'::vector, '[-1,-2,-3,-4,-5,-6,-7,-8,-9]');
|
||||||
|
cosine_distance
|
||||||
|
-----------------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT '[1,2]'::vector <=> '[2,4]';
|
SELECT '[1,2]'::vector <=> '[2,4]';
|
||||||
?column?
|
?column?
|
||||||
----------
|
----------
|
||||||
@@ -304,6 +328,24 @@ SELECT l1_distance('[3e38]'::vector, '[-3e38]');
|
|||||||
Infinity
|
Infinity
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l1_distance('[1,2,3,4,5,6,7,8,9]'::vector, '[1,2,3,4,5,6,7,8,9]');
|
||||||
|
l1_distance
|
||||||
|
-------------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l1_distance('[1,2,3,4,5,6,7,8,9]'::vector, '[0,3,2,5,4,7,6,9,8]');
|
||||||
|
l1_distance
|
||||||
|
-------------
|
||||||
|
9
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[0,0]'::vector <+> '[3,4]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
7
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT l2_normalize('[3,4]'::vector);
|
SELECT l2_normalize('[3,4]'::vector);
|
||||||
l2_normalize
|
l2_normalize
|
||||||
--------------
|
--------------
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ SELECT hamming_distance('111', '110');
|
|||||||
SELECT hamming_distance('111', '100');
|
SELECT hamming_distance('111', '100');
|
||||||
SELECT hamming_distance('111', '000');
|
SELECT hamming_distance('111', '000');
|
||||||
SELECT hamming_distance('10101010101010101010', '01010101010101010101');
|
SELECT hamming_distance('10101010101010101010', '01010101010101010101');
|
||||||
|
SELECT hamming_distance('101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', '101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101');
|
||||||
|
SELECT hamming_distance('101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', '010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010');
|
||||||
|
SELECT hamming_distance('110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011', '100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001');
|
||||||
SELECT hamming_distance('', '');
|
SELECT hamming_distance('', '');
|
||||||
SELECT hamming_distance('111', '00');
|
SELECT hamming_distance('111', '00');
|
||||||
SELECT hamming_distance('111', '000'::varbit(4));
|
SELECT hamming_distance('111', '000'::varbit(4));
|
||||||
@@ -15,6 +18,9 @@ SELECT jaccard_distance('1111', '1000');
|
|||||||
SELECT jaccard_distance('1111', '0000');
|
SELECT jaccard_distance('1111', '0000');
|
||||||
SELECT jaccard_distance('1100', '1000');
|
SELECT jaccard_distance('1100', '1000');
|
||||||
SELECT jaccard_distance('10101010101010101010', '01010101010101010101');
|
SELECT jaccard_distance('10101010101010101010', '01010101010101010101');
|
||||||
|
SELECT jaccard_distance('101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', '101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101');
|
||||||
|
SELECT jaccard_distance('101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', '010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010');
|
||||||
|
SELECT jaccard_distance('110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011', '100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001');
|
||||||
SELECT jaccard_distance('', '');
|
SELECT jaccard_distance('', '');
|
||||||
SELECT jaccard_distance('1111', '000');
|
SELECT jaccard_distance('1111', '000');
|
||||||
SELECT jaccard_distance('1111', '0000'::varbit(5));
|
SELECT jaccard_distance('1111', '0000'::varbit(5));
|
||||||
|
|||||||
@@ -47,6 +47,17 @@ SELECT '{2:1.5,4:3.5}/5'::sparsevec::vector(5);
|
|||||||
SELECT '{2:1.5,4:3.5}/5'::sparsevec::vector(4);
|
SELECT '{2:1.5,4:3.5}/5'::sparsevec::vector(4);
|
||||||
SELECT '{}/16001'::sparsevec::vector;
|
SELECT '{}/16001'::sparsevec::vector;
|
||||||
|
|
||||||
|
SELECT '[0,1.5,0,3.5,0]'::halfvec::sparsevec;
|
||||||
|
SELECT '[0,1.5,0,3.5,0]'::halfvec::sparsevec(5);
|
||||||
|
SELECT '[0,1.5,0,3.5,0]'::halfvec::sparsevec(4);
|
||||||
|
|
||||||
|
SELECT '{2:1.5,4:3.5}/5'::sparsevec::halfvec;
|
||||||
|
SELECT '{2:1.5,4:3.5}/5'::sparsevec::halfvec(5);
|
||||||
|
SELECT '{2:1.5,4:3.5}/5'::sparsevec::halfvec(4);
|
||||||
|
SELECT '{}/16001'::sparsevec::halfvec;
|
||||||
|
SELECT '{1:65520}/1'::sparsevec::halfvec;
|
||||||
|
SELECT '{1:1e-8}/1'::sparsevec::halfvec;
|
||||||
|
|
||||||
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;
|
SELECT array_to_vector(array_agg(n), 16001, false) FROM generate_series(1, 16001) n;
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ SELECT '[1,2]'::halfvec <=> '[2,4]';
|
|||||||
SELECT l1_distance('[0,0]'::halfvec, '[3,4]');
|
SELECT l1_distance('[0,0]'::halfvec, '[3,4]');
|
||||||
SELECT l1_distance('[0,0]'::halfvec, '[0,1]');
|
SELECT l1_distance('[0,0]'::halfvec, '[0,1]');
|
||||||
SELECT l1_distance('[1,2]'::halfvec, '[3]');
|
SELECT l1_distance('[1,2]'::halfvec, '[3]');
|
||||||
|
SELECT l1_distance('[1,2,3,4,5,6,7,8,9]'::halfvec, '[1,2,3,4,5,6,7,8,9]');
|
||||||
|
SELECT l1_distance('[1,2,3,4,5,6,7,8,9]'::halfvec, '[0,3,2,5,4,7,6,9,8]');
|
||||||
|
SELECT '[0,0]'::halfvec <+> '[3,4]';
|
||||||
|
|
||||||
SELECT l2_normalize('[3,4]'::halfvec);
|
SELECT l2_normalize('[3,4]'::halfvec);
|
||||||
SELECT l2_normalize('[3,0]'::halfvec);
|
SELECT l2_normalize('[3,0]'::halfvec);
|
||||||
|
|||||||
12
test/sql/hnsw_halfvec_l1.sql
Normal file
12
test/sql/hnsw_halfvec_l1.sql
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
SET enable_seqscan = off;
|
||||||
|
|
||||||
|
CREATE TABLE t (val halfvec(3));
|
||||||
|
INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), (NULL);
|
||||||
|
CREATE INDEX ON t USING hnsw (val halfvec_l1_ops);
|
||||||
|
|
||||||
|
INSERT INTO t (val) VALUES ('[1,2,4]');
|
||||||
|
|
||||||
|
SELECT * FROM t ORDER BY val <+> '[3,3,3]';
|
||||||
|
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <+> (SELECT NULL::halfvec)) t2;
|
||||||
|
|
||||||
|
DROP TABLE t;
|
||||||
12
test/sql/hnsw_sparsevec_l1.sql
Normal file
12
test/sql/hnsw_sparsevec_l1.sql
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
SET enable_seqscan = off;
|
||||||
|
|
||||||
|
CREATE TABLE t (val sparsevec(3));
|
||||||
|
INSERT INTO t (val) VALUES ('{}/3'), ('{1:1,2:2,3:3}/3'), ('{1:1,2:1,3:1}/3'), (NULL);
|
||||||
|
CREATE INDEX ON t USING hnsw (val sparsevec_l1_ops);
|
||||||
|
|
||||||
|
INSERT INTO t (val) VALUES ('{1:1,2:2,3:4}/3');
|
||||||
|
|
||||||
|
SELECT * FROM t ORDER BY val <+> '{1:3,2:3,3:3}/3';
|
||||||
|
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <+> (SELECT NULL::sparsevec)) t2;
|
||||||
|
|
||||||
|
DROP TABLE t;
|
||||||
12
test/sql/hnsw_vector_l1.sql
Normal file
12
test/sql/hnsw_vector_l1.sql
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
SET enable_seqscan = off;
|
||||||
|
|
||||||
|
CREATE TABLE t (val vector(3));
|
||||||
|
INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), (NULL);
|
||||||
|
CREATE INDEX ON t USING hnsw (val vector_l1_ops);
|
||||||
|
|
||||||
|
INSERT INTO t (val) VALUES ('[1,2,4]');
|
||||||
|
|
||||||
|
SELECT * FROM t ORDER BY val <+> '[3,3,3]';
|
||||||
|
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <+> (SELECT NULL::vector)) t2;
|
||||||
|
|
||||||
|
DROP TABLE t;
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
SET enable_seqscan = off;
|
|
||||||
|
|
||||||
CREATE TABLE t (val bit(4));
|
|
||||||
INSERT INTO t (val) VALUES (B'0000'), (B'1100'), (B'1111'), (NULL);
|
|
||||||
CREATE INDEX ON t USING ivfflat (val bit_jaccard_ops) WITH (lists = 1);
|
|
||||||
|
|
||||||
INSERT INTO t (val) VALUES (B'1110');
|
|
||||||
|
|
||||||
SELECT * FROM t ORDER BY val <%> B'1111';
|
|
||||||
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <%> (SELECT NULL::bit)) t2;
|
|
||||||
|
|
||||||
DROP TABLE t;
|
|
||||||
@@ -34,6 +34,8 @@ SELECT '{1:1a}/1'::sparsevec;
|
|||||||
SELECT '{1:1,}/1'::sparsevec;
|
SELECT '{1:1,}/1'::sparsevec;
|
||||||
SELECT '{1:0,2:1,3:0}/3'::sparsevec;
|
SELECT '{1:0,2:1,3:0}/3'::sparsevec;
|
||||||
SELECT '{2:1,1:1}/2'::sparsevec;
|
SELECT '{2:1,1:1}/2'::sparsevec;
|
||||||
|
SELECT '{1:1,1:1}/2'::sparsevec;
|
||||||
|
SELECT '{1:1,2:1,1:1}/2'::sparsevec;
|
||||||
SELECT '{}/5'::sparsevec;
|
SELECT '{}/5'::sparsevec;
|
||||||
SELECT '{}/-1'::sparsevec;
|
SELECT '{}/-1'::sparsevec;
|
||||||
SELECT '{}/100001'::sparsevec;
|
SELECT '{}/100001'::sparsevec;
|
||||||
|
|||||||
@@ -46,11 +46,13 @@ SELECT l2_distance('[0,0]'::vector, '[3,4]');
|
|||||||
SELECT l2_distance('[0,0]'::vector, '[0,1]');
|
SELECT l2_distance('[0,0]'::vector, '[0,1]');
|
||||||
SELECT l2_distance('[1,2]'::vector, '[3]');
|
SELECT l2_distance('[1,2]'::vector, '[3]');
|
||||||
SELECT l2_distance('[3e38]'::vector, '[-3e38]');
|
SELECT l2_distance('[3e38]'::vector, '[-3e38]');
|
||||||
|
SELECT l2_distance('[1,1,1,1,1,1,1,1,1]'::vector, '[1,1,1,1,1,1,1,4,5]');
|
||||||
SELECT '[0,0]'::vector <-> '[3,4]';
|
SELECT '[0,0]'::vector <-> '[3,4]';
|
||||||
|
|
||||||
SELECT inner_product('[1,2]'::vector, '[3,4]');
|
SELECT inner_product('[1,2]'::vector, '[3,4]');
|
||||||
SELECT inner_product('[1,2]'::vector, '[3]');
|
SELECT inner_product('[1,2]'::vector, '[3]');
|
||||||
SELECT inner_product('[3e38]'::vector, '[3e38]');
|
SELECT inner_product('[3e38]'::vector, '[3e38]');
|
||||||
|
SELECT inner_product('[1,1,1,1,1,1,1,1,1]'::vector, '[1,2,3,4,5,6,7,8,9]');
|
||||||
SELECT '[1,2]'::vector <#> '[3,4]';
|
SELECT '[1,2]'::vector <#> '[3,4]';
|
||||||
|
|
||||||
SELECT cosine_distance('[1,2]'::vector, '[2,4]');
|
SELECT cosine_distance('[1,2]'::vector, '[2,4]');
|
||||||
@@ -62,12 +64,17 @@ SELECT cosine_distance('[1,2]'::vector, '[3]');
|
|||||||
SELECT cosine_distance('[1,1]'::vector, '[1.1,1.1]');
|
SELECT cosine_distance('[1,1]'::vector, '[1.1,1.1]');
|
||||||
SELECT cosine_distance('[1,1]'::vector, '[-1.1,-1.1]');
|
SELECT cosine_distance('[1,1]'::vector, '[-1.1,-1.1]');
|
||||||
SELECT cosine_distance('[3e38]'::vector, '[3e38]');
|
SELECT cosine_distance('[3e38]'::vector, '[3e38]');
|
||||||
|
SELECT cosine_distance('[1,2,3,4,5,6,7,8,9]'::vector, '[1,2,3,4,5,6,7,8,9]');
|
||||||
|
SELECT cosine_distance('[1,2,3,4,5,6,7,8,9]'::vector, '[-1,-2,-3,-4,-5,-6,-7,-8,-9]');
|
||||||
SELECT '[1,2]'::vector <=> '[2,4]';
|
SELECT '[1,2]'::vector <=> '[2,4]';
|
||||||
|
|
||||||
SELECT l1_distance('[0,0]'::vector, '[3,4]');
|
SELECT l1_distance('[0,0]'::vector, '[3,4]');
|
||||||
SELECT l1_distance('[0,0]'::vector, '[0,1]');
|
SELECT l1_distance('[0,0]'::vector, '[0,1]');
|
||||||
SELECT l1_distance('[1,2]'::vector, '[3]');
|
SELECT l1_distance('[1,2]'::vector, '[3]');
|
||||||
SELECT l1_distance('[3e38]'::vector, '[-3e38]');
|
SELECT l1_distance('[3e38]'::vector, '[-3e38]');
|
||||||
|
SELECT l1_distance('[1,2,3,4,5,6,7,8,9]'::vector, '[1,2,3,4,5,6,7,8,9]');
|
||||||
|
SELECT l1_distance('[1,2,3,4,5,6,7,8,9]'::vector, '[0,3,2,5,4,7,6,9,8]');
|
||||||
|
SELECT '[0,0]'::vector <+> '[3,4]';
|
||||||
|
|
||||||
SELECT l2_normalize('[3,4]'::vector);
|
SELECT l2_normalize('[3,4]'::vector);
|
||||||
SELECT l2_normalize('[3,0]'::vector);
|
SELECT l2_normalize('[3,0]'::vector);
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ for (1 .. 20)
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Check each index type
|
# Check each index type
|
||||||
my @operators = ("<->", "<#>", "<=>");
|
my @operators = ("<->", "<#>", "<=>", "<+>");
|
||||||
my @opclasses = ("vector_l2_ops", "vector_ip_ops", "vector_cosine_ops");
|
my @opclasses = ("vector_l2_ops", "vector_ip_ops", "vector_cosine_ops", "vector_l1_ops");
|
||||||
|
|
||||||
for my $i (0 .. $#operators)
|
for my $i (0 .. $#operators)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -64,8 +64,8 @@ for (1 .. 20)
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Check each index type
|
# Check each index type
|
||||||
my @operators = ("<->", "<#>", "<=>");
|
my @operators = ("<->", "<#>", "<=>", "<+>");
|
||||||
my @opclasses = ("vector_l2_ops", "vector_ip_ops", "vector_cosine_ops");
|
my @opclasses = ("vector_l2_ops", "vector_ip_ops", "vector_cosine_ops", "vector_l1_ops");
|
||||||
|
|
||||||
for my $i (0 .. $#operators)
|
for my $i (0 .. $#operators)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ for (1 .. 20)
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Check each index type
|
# Check each index type
|
||||||
my @operators = ("<->", "<#>", "<=>");
|
my @operators = ("<->", "<#>", "<=>", "<+>");
|
||||||
my @opclasses = ("halfvec_l2_ops", "halfvec_ip_ops", "halfvec_cosine_ops");
|
my @opclasses = ("halfvec_l2_ops", "halfvec_ip_ops", "halfvec_cosine_ops", "halfvec_l1_ops");
|
||||||
|
|
||||||
for my $i (0 .. $#operators)
|
for my $i (0 .. $#operators)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ for (1 .. 20)
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Check each index type
|
# Check each index type
|
||||||
my @operators = ("<->", "<#>", "<=>");
|
my @operators = ("<->", "<#>", "<=>", "<+>");
|
||||||
my @opclasses = ("sparsevec_l2_ops", "sparsevec_ip_ops", "sparsevec_cosine_ops");
|
my @opclasses = ("sparsevec_l2_ops", "sparsevec_ip_ops", "sparsevec_cosine_ops", "sparsevec_l1_ops");
|
||||||
|
|
||||||
for my $i (0 .. $#operators)
|
for my $i (0 .. $#operators)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -68,8 +68,8 @@ for (1 .. 20)
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Check each index type
|
# Check each index type
|
||||||
my @operators = ("<->", "<#>", "<=>");
|
my @operators = ("<->", "<#>", "<=>", "<+>");
|
||||||
my @opclasses = ("halfvec_l2_ops", "halfvec_ip_ops", "halfvec_cosine_ops");
|
my @opclasses = ("halfvec_l2_ops", "halfvec_ip_ops", "halfvec_cosine_ops", "halfvec_l1_ops");
|
||||||
|
|
||||||
for my $i (0 .. $#operators)
|
for my $i (0 .. $#operators)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -64,8 +64,8 @@ for (1 .. 20)
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Check each index type
|
# Check each index type
|
||||||
my @operators = ("<->", "<#>", "<=>");
|
my @operators = ("<->", "<#>", "<=>", "<+>");
|
||||||
my @opclasses = ("sparsevec_l2_ops", "sparsevec_ip_ops", "sparsevec_cosine_ops");
|
my @opclasses = ("sparsevec_l2_ops", "sparsevec_ip_ops", "sparsevec_cosine_ops", "sparsevec_l1_ops");
|
||||||
|
|
||||||
for my $i (0 .. $#operators)
|
for my $i (0 .. $#operators)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ for (1 .. 20)
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Check each index type
|
# Check each index type
|
||||||
my @operators = ("<~>", "<\%>");
|
my @operators = ("<~>");
|
||||||
my @opclasses = ("bit_hamming_ops", "bit_jaccard_ops");
|
my @opclasses = ("bit_hamming_ops");
|
||||||
|
|
||||||
for my $i (0 .. $#operators)
|
for my $i (0 .. $#operators)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user