mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-22 03:57:34 +08:00
Compare commits
102 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
647c9002be | ||
|
|
3e6345f02a | ||
|
|
2b3484ddcd | ||
|
|
1a6debf281 | ||
|
|
bff4d7ea68 | ||
|
|
d5b979e4fa | ||
|
|
d52426b3fa | ||
|
|
b125b2debb | ||
|
|
3d7186a17c | ||
|
|
58ba2139ce | ||
|
|
fd93c9db86 | ||
|
|
8dde26920c | ||
|
|
9153a545a7 | ||
|
|
9c20f04a11 | ||
|
|
7c12d100ce | ||
|
|
d97d9a6561 | ||
|
|
f15ea301c5 | ||
|
|
cfa23f2c7a | ||
|
|
b5b7035edc | ||
|
|
478d62cdbd | ||
|
|
c7df9ef3a1 | ||
|
|
ea1b094d8e | ||
|
|
63d2965e8e | ||
|
|
e5e7a6ec15 | ||
|
|
ede572d80b | ||
|
|
154e4334fb | ||
|
|
77d54333f6 | ||
|
|
c95732340a | ||
|
|
2af9bdefbb | ||
|
|
bd36231871 | ||
|
|
523788d964 | ||
|
|
1eed57310a | ||
|
|
57e6a01214 | ||
|
|
b713cbc3b6 | ||
|
|
ebeac156c0 | ||
|
|
60bc93f938 | ||
|
|
87a1b3365e | ||
|
|
e9a762223b | ||
|
|
db83f4faa8 | ||
|
|
2cf71ec6bd | ||
|
|
a7510430e3 | ||
|
|
ea8f06e8f4 | ||
|
|
4e0c1a137c | ||
|
|
c758b7b188 | ||
|
|
3dffc01e31 | ||
|
|
b8f3688e41 | ||
|
|
67e317141b | ||
|
|
de2ce0b1eb | ||
|
|
86c1c95ef4 | ||
|
|
38be81cf20 | ||
|
|
62cc3398ed | ||
|
|
af86392a34 | ||
|
|
a9067a8101 | ||
|
|
6deca154e6 | ||
|
|
6342439eb8 | ||
|
|
21967765a3 | ||
|
|
d31b7e3997 | ||
|
|
efa85aaba1 | ||
|
|
3c820b5a50 | ||
|
|
199c0e5e34 | ||
|
|
bcab0ad8ae | ||
|
|
09e95fc8f9 | ||
|
|
6119cced74 | ||
|
|
f8c07edba1 | ||
|
|
baabbaeff9 | ||
|
|
f0993282fe | ||
|
|
01584d3df6 | ||
|
|
6f50c4f5bd | ||
|
|
31a953f8db | ||
|
|
7b3d0f2595 | ||
|
|
099b9e9027 | ||
|
|
e1f3caba49 | ||
|
|
3f0d2bbd2f | ||
|
|
c989b85f75 | ||
|
|
a9bbee4198 | ||
|
|
fb274f1197 | ||
|
|
88ba5da6a7 | ||
|
|
6a550c8b52 | ||
|
|
5748cb6b43 | ||
|
|
60814b8f39 | ||
|
|
773a63bed1 | ||
|
|
955a5a6082 | ||
|
|
8863920fdc | ||
|
|
6d9653d763 | ||
|
|
3a488c9f2f | ||
|
|
fe133bfe5d | ||
|
|
e279bb3d7e | ||
|
|
0aa39a8c0c | ||
|
|
e0854e6381 | ||
|
|
2515cf050d | ||
|
|
fb015adc25 | ||
|
|
236447824e | ||
|
|
969823c49f | ||
|
|
79ae168dc3 | ||
|
|
29b43a1e24 | ||
|
|
d14a6bca4b | ||
|
|
8ebab9bf6d | ||
|
|
c4baa335d3 | ||
|
|
4b7053b544 | ||
|
|
d08544f676 | ||
|
|
b1df1ec83e | ||
|
|
5e721daa2a |
8
.dockerignore
Normal file
8
.dockerignore
Normal file
@@ -0,0 +1,8 @@
|
||||
/.git/
|
||||
/dist/
|
||||
/results/
|
||||
/tmp_check/
|
||||
/sql/vector--?.?.?.sql
|
||||
regression.*
|
||||
*.o
|
||||
*.so
|
||||
31
.github/workflows/build.yml
vendored
31
.github/workflows/build.yml
vendored
@@ -3,24 +3,37 @@ on: [push, pull_request]
|
||||
jobs:
|
||||
build:
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
postgres: [13, 12, 11, 10, 9.6]
|
||||
os: [ubuntu-latest]
|
||||
postgres: [14, 13, 12, 11, 10, 9.6]
|
||||
include:
|
||||
- os: macos-latest
|
||||
postgres: 14
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: |
|
||||
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
|
||||
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
|
||||
sudo apt-get update
|
||||
- uses: ankane/setup-postgres@v1
|
||||
with:
|
||||
postgres-version: ${{ matrix.postgres }}
|
||||
- run: sudo apt-get install postgresql-server-dev-${{ matrix.postgres }} libipc-run-perl
|
||||
- if: ${{ startsWith(matrix.os, 'ubuntu') }}
|
||||
run: sudo apt-get update && sudo apt-get install postgresql-server-dev-${{ matrix.postgres }} libipc-run-perl
|
||||
- run: make
|
||||
- run: |
|
||||
- if: ${{ startsWith(matrix.os, 'ubuntu') }}
|
||||
run: |
|
||||
export PG_CONFIG=`which pg_config`
|
||||
sudo --preserve-env=PG_CONFIG make install
|
||||
- if: ${{ startsWith(matrix.os, 'macos') }}
|
||||
run: make install
|
||||
- run: make installcheck
|
||||
- run: make prove_installcheck
|
||||
- if: ${{ failure() }}
|
||||
run: cat regression.diffs
|
||||
- if: ${{ startsWith(matrix.os, 'ubuntu') }}
|
||||
run: make prove_installcheck
|
||||
- if: ${{ startsWith(matrix.os, 'macos') }}
|
||||
run: |
|
||||
brew install cpanm && cpanm IPC::Run
|
||||
wget -q https://github.com/postgres/postgres/archive/refs/tags/REL_13_2.tar.gz
|
||||
tar xf REL_13_2.tar.gz
|
||||
make prove_installcheck PROVE=prove PERL5LIB=postgres-REL_13_2/src/test/perl
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,5 +1,7 @@
|
||||
results
|
||||
tmp_check
|
||||
/dist/
|
||||
/results/
|
||||
/tmp_check/
|
||||
/sql/vector--?.?.?.sql
|
||||
regression.*
|
||||
*.o
|
||||
*.so
|
||||
|
||||
44
CHANGELOG.md
44
CHANGELOG.md
@@ -1,3 +1,47 @@
|
||||
## 0.2.1 (unreleased)
|
||||
|
||||
- Fixed `operator is not unique` error
|
||||
|
||||
## 0.2.0 (2021-10-03)
|
||||
|
||||
- Added support for Postgres 14
|
||||
|
||||
## 0.1.8 (2021-09-07)
|
||||
|
||||
- Added cast for `vector` to `real[]`
|
||||
|
||||
## 0.1.7 (2021-06-13)
|
||||
|
||||
- Added cast for `numeric[]` to `vector`
|
||||
|
||||
## 0.1.6 (2021-06-09)
|
||||
|
||||
- Fixed segmentation fault with `COUNT`
|
||||
|
||||
## 0.1.5 (2021-05-25)
|
||||
|
||||
- Reduced memory usage during index creation
|
||||
|
||||
## 0.1.4 (2021-05-09)
|
||||
|
||||
- Fixed kmeans for inner product
|
||||
- Fixed multiple definition error with GCC 10
|
||||
|
||||
## 0.1.3 (2021-05-06)
|
||||
|
||||
- Added Dockerfile
|
||||
- Fixed version
|
||||
|
||||
## 0.1.2 (2021-04-26)
|
||||
|
||||
- Vectorized distance calculations
|
||||
- Improved cost estimation
|
||||
|
||||
## 0.1.1 (2021-04-25)
|
||||
|
||||
- Added binary representation for `COPY`
|
||||
- Marked functions as `PARALLEL SAFE`
|
||||
|
||||
## 0.1.0 (2021-04-20)
|
||||
|
||||
- First release
|
||||
|
||||
16
Dockerfile
Normal file
16
Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
||||
FROM postgres:14
|
||||
|
||||
COPY . /tmp/pgvector
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends build-essential postgresql-server-dev-14 && \
|
||||
cd /tmp/pgvector && \
|
||||
make clean && \
|
||||
make OPTFLAGS="" && \
|
||||
make install && \
|
||||
mkdir /usr/share/doc/pgvector && \
|
||||
cp LICENSE README.md /usr/share/doc/pgvector && \
|
||||
rm -r /tmp/pgvector && \
|
||||
apt-get remove -y build-essential postgresql-server-dev-14 && \
|
||||
apt-get autoremove -y && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
49
META.json
Normal file
49
META.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "vector",
|
||||
"abstract": "Open-source vector similarity search for Postgres",
|
||||
"description": "Supports L2 distance, inner product, and cosine distance",
|
||||
"version": "0.2.1",
|
||||
"maintainer": [
|
||||
"Andrew Kane <andrew@ankane.org>"
|
||||
],
|
||||
"license": {
|
||||
"PostgreSQL": "http://www.postgresql.org/about/licence"
|
||||
},
|
||||
"prereqs": {
|
||||
"runtime": {
|
||||
"requires": {
|
||||
"PostgreSQL": "9.6.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"provides": {
|
||||
"vector": {
|
||||
"file": "sql/vector.sql",
|
||||
"docfile": "README.md",
|
||||
"version": "0.2.1",
|
||||
"abstract": "Open-source vector similarity search for Postgres"
|
||||
}
|
||||
},
|
||||
"resources": {
|
||||
"homepage": "https://github.com/ankane/pgvector",
|
||||
"bugtracker": {
|
||||
"web": "https://github.com/ankane/pgvector/issues"
|
||||
},
|
||||
"repository": {
|
||||
"url": "https://github.com/ankane/pgvector.git",
|
||||
"web": "https://github.com/ankane/pgvector",
|
||||
"type": "git"
|
||||
}
|
||||
},
|
||||
"generated_by": "Andrew Kane",
|
||||
"meta-spec": {
|
||||
"version": "1.0.0",
|
||||
"url": "http://pgxn.org/meta/spec.txt"
|
||||
},
|
||||
"tags": [
|
||||
"vectors",
|
||||
"datatype",
|
||||
"nearest neighbor search",
|
||||
"approximate nearest neighbors"
|
||||
]
|
||||
}
|
||||
41
Makefile
41
Makefile
@@ -1,11 +1,33 @@
|
||||
EXTENSION = vector
|
||||
DATA = vector--0.1.0.sql
|
||||
EXTVERSION = 0.2.1
|
||||
|
||||
MODULE_big = vector
|
||||
DATA = $(wildcard sql/*--*.sql)
|
||||
OBJS = src/ivfbuild.o src/ivfflat.o src/ivfinsert.o src/ivfkmeans.o src/ivfscan.o src/ivfutils.o src/ivfvacuum.o src/vector.o
|
||||
|
||||
TESTS = $(wildcard sql/*.sql)
|
||||
TESTS = $(wildcard test/sql/*.sql)
|
||||
REGRESS = $(patsubst test/sql/%.sql,%,$(TESTS))
|
||||
REGRESS_OPTS = --inputdir=test
|
||||
|
||||
REGRESS = btree cast functions ivfflat_cosine ivfflat_ip ivfflat_l2 ivfflat_unlogged vector
|
||||
OPTFLAGS = -march=native
|
||||
|
||||
# For auto-vectorization:
|
||||
# - GCC (needs -ftree-vectorize OR -O3) - https://gcc.gnu.org/projects/tree-ssa/vectorization.html
|
||||
# - Clang (could use pragma instead) - https://llvm.org/docs/Vectorizers.html
|
||||
PG_CFLAGS = $(OPTFLAGS) -ftree-vectorize -fassociative-math -fno-signed-zeros -fno-trapping-math
|
||||
|
||||
# Debug GCC auto-vectorization
|
||||
# PG_CFLAGS += -fopt-info-vec
|
||||
|
||||
# Debug Clang auto-vectorization
|
||||
# PG_CFLAGS += -Rpass=loop-vectorize -Rpass-analysis=loop-vectorize
|
||||
|
||||
all: sql/$(EXTENSION)--$(EXTVERSION).sql
|
||||
|
||||
sql/$(EXTENSION)--$(EXTVERSION).sql: sql/$(EXTENSION).sql
|
||||
cp $< $@
|
||||
|
||||
EXTRA_CLEAN = sql/$(EXTENSION)--$(EXTVERSION).sql
|
||||
|
||||
PG_CONFIG ?= pg_config
|
||||
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||
@@ -13,4 +35,15 @@ include $(PGXS)
|
||||
|
||||
prove_installcheck:
|
||||
rm -rf $(CURDIR)/tmp_check
|
||||
cd $(srcdir) && TESTDIR='$(CURDIR)' PATH="$(bindir):$$PATH" PGPORT='6$(DEF_PGPORT)' PG_REGRESS='$(top_builddir)/src/test/regress/pg_regress' $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS) $(if $(PROVE_TESTS),$(PROVE_TESTS),t/*.pl)
|
||||
cd $(srcdir) && TESTDIR='$(CURDIR)' PATH="$(bindir):$$PATH" PGPORT='6$(DEF_PGPORT)' PG_REGRESS='$(top_builddir)/src/test/regress/pg_regress' $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS) $(if $(PROVE_TESTS),$(PROVE_TESTS),test/t/*.pl)
|
||||
|
||||
.PHONY: dist
|
||||
|
||||
dist:
|
||||
mkdir -p dist
|
||||
git archive --format zip --prefix=$(EXTENSION)-$(EXTVERSION)/ --output dist/$(EXTENSION)-$(EXTVERSION).zip master
|
||||
|
||||
.PHONY: docker
|
||||
|
||||
docker:
|
||||
docker build --pull --no-cache -t ankane/pgvector:latest .
|
||||
|
||||
124
README.md
124
README.md
@@ -4,7 +4,7 @@ Open-source vector similarity search for Postgres
|
||||
|
||||
```sql
|
||||
CREATE TABLE table (column vector(3));
|
||||
CREATE INDEX ON table USING ivfflat (column);
|
||||
CREATE INDEX ON table USING ivfflat (column vector_l2_ops);
|
||||
SELECT * FROM table ORDER BY column <-> '[1,2,3]' LIMIT 5;
|
||||
```
|
||||
|
||||
@@ -17,7 +17,7 @@ Supports L2 distance, inner product, and cosine distance
|
||||
Compile and install the extension (supports Postgres 9.6+)
|
||||
|
||||
```sh
|
||||
git clone https://github.com/ankane/pgvector.git
|
||||
git clone --branch v0.2.1 https://github.com/ankane/pgvector.git
|
||||
cd pgvector
|
||||
make
|
||||
make install # may need sudo
|
||||
@@ -29,6 +29,8 @@ Then load it in databases where you want to use it
|
||||
CREATE EXTENSION vector;
|
||||
```
|
||||
|
||||
You can also install it with [Docker](#docker), [Homebrew](#homebrew), or [PGXN](#pgxn)
|
||||
|
||||
## Getting Started
|
||||
|
||||
Create a vector column with 3 dimensions (replace `table` and `column` with non-reserved names)
|
||||
@@ -60,7 +62,7 @@ Speed up queries with an approximate index. Add an index for each distance funct
|
||||
L2 distance
|
||||
|
||||
```sql
|
||||
CREATE INDEX ON table USING ivfflat (column);
|
||||
CREATE INDEX ON table USING ivfflat (column vector_l2_ops);
|
||||
```
|
||||
|
||||
Inner product
|
||||
@@ -75,16 +77,30 @@ Cosine distance
|
||||
CREATE INDEX ON table USING ivfflat (column vector_cosine_ops);
|
||||
```
|
||||
|
||||
Indexes should be created after the table has data for optimal clustering. Also, unlike typical indexes which only affect performance, you may see different results for queries after adding an approximate index.
|
||||
Indexes should be created after the table has data for optimal clustering. If the distribution of data changes significantly, you can reindex without downtime:
|
||||
|
||||
```sql
|
||||
-- Postgres 12+
|
||||
REINDEX INDEX CONCURRENTLY index_name;
|
||||
|
||||
-- Postgres < 12
|
||||
CREATE INDEX CONCURRENTLY temp_name ON table USING ivfflat (column opclass);
|
||||
DROP INDEX CONCURRENTLY index_name;
|
||||
ALTER INDEX temp_name RENAME TO index_name;
|
||||
```
|
||||
|
||||
Also, unlike typical indexes which only affect performance, you may see different results for queries after adding an approximate index.
|
||||
|
||||
### Index Options
|
||||
|
||||
Specify the number of inverted lists (100 by default)
|
||||
|
||||
```sql
|
||||
CREATE INDEX ON table USING ivfflat (column) WITH (lists = 100);
|
||||
CREATE INDEX ON table USING ivfflat (column opclass) WITH (lists = 100);
|
||||
```
|
||||
|
||||
A [good place to start](https://github.com/facebookresearch/faiss/issues/112) is `4 * sqrt(rows)`
|
||||
|
||||
### Query Options
|
||||
|
||||
Specify the number of probes (1 by default)
|
||||
@@ -104,6 +120,30 @@ SELECT ...
|
||||
COMMIT;
|
||||
```
|
||||
|
||||
### Partial Indexes
|
||||
|
||||
Consider [partial indexes](https://www.postgresql.org/docs/current/indexes-partial.html) for queries with a `WHERE` clause
|
||||
|
||||
```sql
|
||||
CREATE INDEX ON table USING ivfflat (column opclass) WHERE (other_column = 123);
|
||||
```
|
||||
|
||||
To index many different values of `other_column`, consider [partitioning](https://www.postgresql.org/docs/current/ddl-partitioning.html) on `other_column`.
|
||||
|
||||
## Performance
|
||||
|
||||
To speed up queries without an index, increase `max_parallel_workers_per_gather`.
|
||||
|
||||
```sql
|
||||
SET max_parallel_workers_per_gather = 4;
|
||||
```
|
||||
|
||||
To speed up queries with an index, increase the number of inverted lists (at the expense of recall).
|
||||
|
||||
```sql
|
||||
CREATE INDEX ON table USING ivfflat (column opclass) WITH (lists = 1000);
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
### Vector Type
|
||||
@@ -130,6 +170,70 @@ l2_distance(vector, vector) | Euclidean distance
|
||||
vector_dims(vector) | number of dimensions
|
||||
vector_norm(vector) | Euclidean norm
|
||||
|
||||
## Libraries
|
||||
|
||||
Libraries that use pgvector:
|
||||
|
||||
- [pgvector-python](https://github.com/ankane/pgvector-python) (Python)
|
||||
- [Neighbor](https://github.com/ankane/neighbor) (Ruby)
|
||||
- [pgvector-node](https://github.com/ankane/pgvector-node) (Node.js)
|
||||
- [pgvector-go](https://github.com/ankane/pgvector-go) (Go)
|
||||
- [pgvector-rust](https://github.com/ankane/pgvector-rust) (Rust)
|
||||
- [pgvector-cpp](https://github.com/ankane/pgvector-cpp) (C++)
|
||||
|
||||
## Additional Installation Methods
|
||||
|
||||
### Docker
|
||||
|
||||
Get the [Docker image](https://hub.docker.com/repository/docker/ankane/pgvector) with:
|
||||
|
||||
```sh
|
||||
docker pull ankane/pgvector
|
||||
```
|
||||
|
||||
This adds pgvector to the [Postgres image](https://hub.docker.com/_/postgres).
|
||||
|
||||
You can also build the image manually
|
||||
|
||||
```sh
|
||||
git clone --branch v0.2.1 https://github.com/ankane/pgvector.git
|
||||
cd pgvector
|
||||
docker build -t pgvector .
|
||||
```
|
||||
|
||||
### Homebrew
|
||||
|
||||
On Mac with Homebrew Postgres, you can use:
|
||||
|
||||
```sh
|
||||
brew install ankane/brew/pgvector
|
||||
```
|
||||
|
||||
### PGXN
|
||||
|
||||
Install from the [PostgreSQL Extension Network](https://pgxn.org/dist/vector) with:
|
||||
|
||||
```sh
|
||||
pgxn install vector
|
||||
```
|
||||
|
||||
## Hosted Postgres
|
||||
|
||||
Some Postgres providers only support specific extensions. To request a new extension:
|
||||
|
||||
- Amazon RDS - follow the instructions on [this page](https://aws.amazon.com/rds/postgresql/faqs/)
|
||||
- Google Cloud SQL - follow the instructions on [this page](https://cloud.google.com/sql/docs/postgres/extensions#requesting-support-for-a-new-extension)
|
||||
- DigitalOcean Managed Databases - follow the instructions on [this page](https://docs.digitalocean.com/products/databases/postgresql/resources/supported-extensions/#supported-extensions)
|
||||
- Azure Database for PostgreSQL - follow the instructions on [this page](https://docs.microsoft.com/en-us/azure/postgresql/concepts-extensions#next-steps)
|
||||
|
||||
## Upgrading
|
||||
|
||||
Install the latest version and run:
|
||||
|
||||
```sql
|
||||
ALTER EXTENSION vector UPDATE;
|
||||
```
|
||||
|
||||
## Thanks
|
||||
|
||||
Thanks to:
|
||||
@@ -172,16 +276,10 @@ make prove_installcheck # TAP tests
|
||||
To run single tests:
|
||||
|
||||
```sh
|
||||
make installcheck REGRESS=vector # regression test
|
||||
make prove_installcheck PROVE_TESTS=t/001_wal.pl # TAP test
|
||||
make installcheck REGRESS=functions # regression test
|
||||
make prove_installcheck PROVE_TESTS=test/t/001_wal.pl # TAP test
|
||||
```
|
||||
|
||||
Directories
|
||||
|
||||
- `expected` - expected output for regression tests
|
||||
- `sql` - regression tests
|
||||
- `t` - TAP tests
|
||||
|
||||
Resources for contributors
|
||||
|
||||
- [Extension Building Infrastructure](https://www.postgresql.org/docs/current/extend-pgxs.html)
|
||||
|
||||
39
sql/vector--0.1.0--0.1.1.sql
Normal file
39
sql/vector--0.1.0--0.1.1.sql
Normal file
@@ -0,0 +1,39 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "ALTER EXTENSION vector UPDATE TO '0.1.1'" to load this file. \quit
|
||||
|
||||
CREATE FUNCTION vector_recv(internal, oid, integer) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION vector_send(vector) RETURNS bytea
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
ALTER TYPE vector SET ( RECEIVE = vector_recv, SEND = vector_send );
|
||||
|
||||
-- functions
|
||||
|
||||
ALTER FUNCTION vector_in(cstring, oid, integer) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_out(vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_typmod_in(cstring[]) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_recv(internal, oid, integer) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_send(vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION l2_distance(vector, vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION inner_product(vector, vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION cosine_distance(vector, vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_dims(vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_norm(vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_add(vector, vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_sub(vector, vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_lt(vector, vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_le(vector, vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_eq(vector, vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_ne(vector, vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_ge(vector, vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_gt(vector, vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_cmp(vector, vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_l2_squared_distance(vector, vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_negative_inner_product(vector, vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector_spherical_distance(vector, vector) PARALLEL SAFE;
|
||||
ALTER FUNCTION vector(vector, integer, boolean) PARALLEL SAFE;
|
||||
ALTER FUNCTION array_to_vector(integer[], integer, boolean) PARALLEL SAFE;
|
||||
ALTER FUNCTION array_to_vector(real[], integer, boolean) PARALLEL SAFE;
|
||||
ALTER FUNCTION array_to_vector(double precision[], integer, boolean) PARALLEL SAFE;
|
||||
2
sql/vector--0.1.1--0.1.3.sql
Normal file
2
sql/vector--0.1.1--0.1.3.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "ALTER EXTENSION vector UPDATE TO '0.1.3'" to load this file. \quit
|
||||
2
sql/vector--0.1.3--0.1.4.sql
Normal file
2
sql/vector--0.1.3--0.1.4.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "ALTER EXTENSION vector UPDATE TO '0.1.4'" to load this file. \quit
|
||||
2
sql/vector--0.1.4--0.1.5.sql
Normal file
2
sql/vector--0.1.4--0.1.5.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "ALTER EXTENSION vector UPDATE TO '0.1.5'" to load this file. \quit
|
||||
2
sql/vector--0.1.5--0.1.6.sql
Normal file
2
sql/vector--0.1.5--0.1.6.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "ALTER EXTENSION vector UPDATE TO '0.1.6'" to load this file. \quit
|
||||
8
sql/vector--0.1.6--0.1.7.sql
Normal file
8
sql/vector--0.1.6--0.1.7.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "ALTER EXTENSION vector UPDATE TO '0.1.7'" to load this file. \quit
|
||||
|
||||
CREATE FUNCTION array_to_vector(numeric[], integer, boolean) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE CAST (numeric[] AS vector)
|
||||
WITH FUNCTION array_to_vector(numeric[], integer, boolean) AS IMPLICIT;
|
||||
8
sql/vector--0.1.7--0.1.8.sql
Normal file
8
sql/vector--0.1.7--0.1.8.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "ALTER EXTENSION vector UPDATE TO '0.1.8'" to load this file. \quit
|
||||
|
||||
CREATE FUNCTION vector_to_float4(vector, integer, boolean) RETURNS real[]
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE CAST (vector AS real[])
|
||||
WITH FUNCTION vector_to_float4(vector, integer, boolean) AS IMPLICIT;
|
||||
2
sql/vector--0.1.8--0.2.0.sql
Normal file
2
sql/vector--0.1.8--0.2.0.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "ALTER EXTENSION vector UPDATE TO '0.2.0'" to load this file. \quit
|
||||
19
sql/vector--0.2.0--0.2.1.sql
Normal file
19
sql/vector--0.2.0--0.2.1.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "ALTER EXTENSION vector UPDATE TO '0.2.1'" to load this file. \quit
|
||||
|
||||
DROP CAST (integer[] AS vector);
|
||||
DROP CAST (real[] AS vector);
|
||||
DROP CAST (double precision[] AS vector);
|
||||
DROP CAST (numeric[] AS vector);
|
||||
|
||||
CREATE CAST (integer[] AS vector)
|
||||
WITH FUNCTION array_to_vector(integer[], integer, boolean) AS ASSIGNMENT;
|
||||
|
||||
CREATE CAST (real[] AS vector)
|
||||
WITH FUNCTION array_to_vector(real[], integer, boolean) AS ASSIGNMENT;
|
||||
|
||||
CREATE CAST (double precision[] AS vector)
|
||||
WITH FUNCTION array_to_vector(double precision[], integer, boolean) AS ASSIGNMENT;
|
||||
|
||||
CREATE CAST (numeric[] AS vector)
|
||||
WITH FUNCTION array_to_vector(numeric[], integer, boolean) AS ASSIGNMENT;
|
||||
243
sql/vector.sql
243
sql/vector.sql
@@ -1,15 +1,230 @@
|
||||
SET client_min_messages = warning;
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION vector" to load this file. \quit
|
||||
|
||||
SELECT '[1,2,3]'::vector;
|
||||
SELECT '[-1,2,3]'::vector;
|
||||
SELECT '[hello,1]'::vector;
|
||||
SELECT '[NaN,1]'::vector;
|
||||
SELECT '[Infinity,1]'::vector;
|
||||
SELECT '[-Infinity,1]'::vector;
|
||||
SELECT '[1,2,3'::vector;
|
||||
SELECT '[1,2,3]9'::vector;
|
||||
SELECT '1,2,3'::vector;
|
||||
SELECT '[]'::vector;
|
||||
SELECT '[1,]'::vector;
|
||||
SELECT '[1,2,3]'::vector(2);
|
||||
-- type
|
||||
|
||||
CREATE TYPE vector;
|
||||
|
||||
CREATE FUNCTION vector_in(cstring, oid, integer) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_out(vector) RETURNS cstring
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_typmod_in(cstring[]) RETURNS integer
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_recv(internal, oid, integer) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_send(vector) RETURNS bytea
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE TYPE vector (
|
||||
INPUT = vector_in,
|
||||
OUTPUT = vector_out,
|
||||
TYPMOD_IN = vector_typmod_in,
|
||||
RECEIVE = vector_recv,
|
||||
SEND = vector_send
|
||||
);
|
||||
|
||||
-- functions
|
||||
|
||||
CREATE FUNCTION l2_distance(vector, vector) RETURNS float8
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION inner_product(vector, vector) RETURNS float8
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION cosine_distance(vector, vector) RETURNS float8
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_dims(vector) RETURNS integer
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_norm(vector) RETURNS float8
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_add(vector, vector) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_sub(vector, vector) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
-- private functions
|
||||
|
||||
CREATE FUNCTION vector_lt(vector, vector) RETURNS bool
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_le(vector, vector) RETURNS bool
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_eq(vector, vector) RETURNS bool
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_ne(vector, vector) RETURNS bool
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_ge(vector, vector) RETURNS bool
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_gt(vector, vector) RETURNS bool
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_cmp(vector, vector) RETURNS int4
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_l2_squared_distance(vector, vector) RETURNS float8
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_negative_inner_product(vector, vector) RETURNS float8
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_spherical_distance(vector, vector) RETURNS float8
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
-- cast functions
|
||||
|
||||
CREATE FUNCTION vector(vector, integer, boolean) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION array_to_vector(integer[], integer, boolean) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION array_to_vector(real[], integer, boolean) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION array_to_vector(double precision[], integer, boolean) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION array_to_vector(numeric[], integer, boolean) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION vector_to_float4(vector, integer, boolean) RETURNS real[]
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
-- casts
|
||||
|
||||
CREATE CAST (vector AS vector)
|
||||
WITH FUNCTION vector(vector, integer, boolean) AS IMPLICIT;
|
||||
|
||||
CREATE CAST (vector AS real[])
|
||||
WITH FUNCTION vector_to_float4(vector, integer, boolean) AS IMPLICIT;
|
||||
|
||||
CREATE CAST (integer[] AS vector)
|
||||
WITH FUNCTION array_to_vector(integer[], integer, boolean) AS ASSIGNMENT;
|
||||
|
||||
CREATE CAST (real[] AS vector)
|
||||
WITH FUNCTION array_to_vector(real[], integer, boolean) AS ASSIGNMENT;
|
||||
|
||||
CREATE CAST (double precision[] AS vector)
|
||||
WITH FUNCTION array_to_vector(double precision[], integer, boolean) AS ASSIGNMENT;
|
||||
|
||||
CREATE CAST (numeric[] AS vector)
|
||||
WITH FUNCTION array_to_vector(numeric[], integer, boolean) AS ASSIGNMENT;
|
||||
|
||||
-- operators
|
||||
|
||||
CREATE OPERATOR <-> (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = l2_distance,
|
||||
COMMUTATOR = '<->'
|
||||
);
|
||||
|
||||
CREATE OPERATOR <#> (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_negative_inner_product,
|
||||
COMMUTATOR = '<#>'
|
||||
);
|
||||
|
||||
CREATE OPERATOR <=> (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = cosine_distance,
|
||||
COMMUTATOR = '<=>'
|
||||
);
|
||||
|
||||
CREATE OPERATOR + (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_add,
|
||||
COMMUTATOR = +
|
||||
);
|
||||
|
||||
CREATE OPERATOR - (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_sub,
|
||||
COMMUTATOR = -
|
||||
);
|
||||
|
||||
CREATE OPERATOR < (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_lt,
|
||||
COMMUTATOR = > , NEGATOR = >= ,
|
||||
RESTRICT = scalarltsel, JOIN = scalarltjoinsel
|
||||
);
|
||||
|
||||
-- should use scalarlesel and scalarlejoinsel, but not supported in Postgres < 11
|
||||
CREATE OPERATOR <= (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_le,
|
||||
COMMUTATOR = >= , NEGATOR = > ,
|
||||
RESTRICT = scalarltsel, JOIN = scalarltjoinsel
|
||||
);
|
||||
|
||||
CREATE OPERATOR = (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_eq,
|
||||
COMMUTATOR = = , NEGATOR = <> ,
|
||||
RESTRICT = eqsel, JOIN = eqjoinsel
|
||||
);
|
||||
|
||||
CREATE OPERATOR <> (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_ne,
|
||||
COMMUTATOR = <> , NEGATOR = = ,
|
||||
RESTRICT = eqsel, JOIN = eqjoinsel
|
||||
);
|
||||
|
||||
-- should use scalargesel and scalargejoinsel, but not supported in Postgres < 11
|
||||
CREATE OPERATOR >= (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_ge,
|
||||
COMMUTATOR = <= , NEGATOR = < ,
|
||||
RESTRICT = scalargtsel, JOIN = scalargtjoinsel
|
||||
);
|
||||
|
||||
CREATE OPERATOR > (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_gt,
|
||||
COMMUTATOR = < , NEGATOR = <= ,
|
||||
RESTRICT = scalargtsel, JOIN = scalargtjoinsel
|
||||
);
|
||||
|
||||
-- access method
|
||||
|
||||
CREATE FUNCTION ivfflathandler(internal) RETURNS index_am_handler
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C;
|
||||
|
||||
CREATE ACCESS METHOD ivfflat TYPE INDEX HANDLER ivfflathandler;
|
||||
|
||||
COMMENT ON ACCESS METHOD ivfflat IS 'ivfflat index access method';
|
||||
|
||||
-- opclasses
|
||||
|
||||
CREATE OPERATOR CLASS vector_ops
|
||||
DEFAULT FOR TYPE vector USING btree AS
|
||||
OPERATOR 1 < ,
|
||||
OPERATOR 2 <= ,
|
||||
OPERATOR 3 = ,
|
||||
OPERATOR 4 >= ,
|
||||
OPERATOR 5 > ,
|
||||
FUNCTION 1 vector_cmp(vector, vector);
|
||||
|
||||
CREATE OPERATOR CLASS vector_l2_ops
|
||||
DEFAULT FOR TYPE vector USING ivfflat AS
|
||||
OPERATOR 1 <-> (vector, vector) FOR ORDER BY float_ops,
|
||||
FUNCTION 1 vector_l2_squared_distance(vector, vector),
|
||||
FUNCTION 3 l2_distance(vector, vector);
|
||||
|
||||
CREATE OPERATOR CLASS vector_ip_ops
|
||||
FOR TYPE vector USING ivfflat AS
|
||||
OPERATOR 1 <#> (vector, vector) FOR ORDER BY float_ops,
|
||||
FUNCTION 1 vector_negative_inner_product(vector, vector),
|
||||
FUNCTION 3 vector_spherical_distance(vector, vector),
|
||||
FUNCTION 4 vector_norm(vector);
|
||||
|
||||
CREATE OPERATOR CLASS vector_cosine_ops
|
||||
FOR TYPE vector USING ivfflat AS
|
||||
OPERATOR 1 <=> (vector, vector) FOR ORDER BY float_ops,
|
||||
FUNCTION 1 vector_negative_inner_product(vector, vector),
|
||||
FUNCTION 2 vector_norm(vector),
|
||||
FUNCTION 3 vector_spherical_distance(vector, vector),
|
||||
FUNCTION 4 vector_norm(vector);
|
||||
|
||||
@@ -41,10 +41,13 @@ SampleCallback(Relation index, CALLBACK_ITEM_POINTER, Datum *values,
|
||||
if (isnull[0])
|
||||
return;
|
||||
|
||||
/* Normalize the value */
|
||||
if (buildstate->normprocinfo != NULL)
|
||||
/*
|
||||
* Normalize with KMEANS_NORM_PROC since spherical distance function
|
||||
* expects unit vectors
|
||||
*/
|
||||
if (buildstate->kmeansnormprocinfo != NULL)
|
||||
{
|
||||
if (!IvfflatNormValue(buildstate->normprocinfo, buildstate->collation, &value, buildstate->normvec))
|
||||
if (!IvfflatNormValue(buildstate->kmeansnormprocinfo, buildstate->collation, &value, buildstate->normvec))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -238,6 +241,8 @@ InsertTuples(Relation index, IvfflatBuildState * buildstate, ForkNumber forkNum)
|
||||
if (PageAddItem(page, (Item) itup, itemsz, InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
|
||||
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
||||
|
||||
pfree(itup);
|
||||
|
||||
buildstate->indtuples += 1;
|
||||
|
||||
GetNextTuple(buildstate->sortstate, tupdesc, slot, &itup, &list);
|
||||
@@ -275,6 +280,7 @@ InitBuildState(IvfflatBuildState * buildstate, Relation heap, Relation index, In
|
||||
/* Get support functions */
|
||||
buildstate->procinfo = index_getprocinfo(index, 1, IVFFLAT_DISTANCE_PROC);
|
||||
buildstate->normprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_NORM_PROC);
|
||||
buildstate->kmeansnormprocinfo = IvfflatOptionalProcInfo(index, IVFFLAT_KMEANS_NORM_PROC);
|
||||
buildstate->collation = index->rd_indcollation[0];
|
||||
|
||||
/* Create tuple description for sorting */
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#include "postgres.h"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#include "access/amapi.h"
|
||||
#include "commands/vacuum.h"
|
||||
#include "ivfflat.h"
|
||||
#include "utils/guc.h"
|
||||
#include "utils/selfuncs.h"
|
||||
|
||||
int ivfflat_probes;
|
||||
static relopt_kind ivfflat_relopt_kind;
|
||||
|
||||
/*
|
||||
@@ -29,8 +32,6 @@ _PG_init(void)
|
||||
|
||||
/*
|
||||
* Estimate the cost of an index scan
|
||||
*
|
||||
* TODO Improve cost estimation
|
||||
*/
|
||||
static void
|
||||
ivfflatcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
|
||||
@@ -42,22 +43,47 @@ ivfflatcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
|
||||
)
|
||||
{
|
||||
GenericCosts costs;
|
||||
|
||||
int lists;
|
||||
double ratio;
|
||||
Relation indexRel;
|
||||
#if PG_VERSION_NUM < 120000
|
||||
List *qinfos;
|
||||
|
||||
qinfos = deconstruct_indexquals(path);
|
||||
#endif
|
||||
|
||||
/* Never use index without order */
|
||||
if (path->indexorderbys == NULL)
|
||||
{
|
||||
*indexStartupCost = DBL_MAX;
|
||||
*indexTotalCost = DBL_MAX;
|
||||
*indexSelectivity = 0;
|
||||
*indexCorrelation = 0;
|
||||
#if PG_VERSION_NUM >= 100000
|
||||
*indexPages = 0;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
MemSet(&costs, 0, sizeof(costs));
|
||||
|
||||
#if PG_VERSION_NUM >= 120000
|
||||
genericcostestimate(root, path, loop_count, &costs);
|
||||
#else
|
||||
qinfos = deconstruct_indexquals(path);
|
||||
genericcostestimate(root, path, loop_count, qinfos, &costs);
|
||||
#endif
|
||||
|
||||
*indexStartupCost = costs.indexStartupCost;
|
||||
indexRel = index_open(path->indexinfo->indexoid, NoLock);
|
||||
lists = IvfflatGetLists(indexRel);
|
||||
index_close(indexRel, NoLock);
|
||||
|
||||
ratio = ((double) ivfflat_probes) / lists;
|
||||
if (ratio > 1)
|
||||
ratio = 1;
|
||||
|
||||
costs.indexTotalCost *= ratio;
|
||||
|
||||
/* Startup cost and total cost are same */
|
||||
*indexStartupCost = costs.indexTotalCost;
|
||||
*indexTotalCost = costs.indexTotalCost;
|
||||
*indexSelectivity = costs.indexSelectivity;
|
||||
*indexCorrelation = costs.indexCorrelation;
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#endif
|
||||
|
||||
/* Variables */
|
||||
int ivfflat_probes;
|
||||
extern int ivfflat_probes;
|
||||
|
||||
typedef struct VectorArrayData
|
||||
{
|
||||
@@ -81,6 +81,7 @@ typedef struct IvfflatBuildState
|
||||
/* Support functions */
|
||||
FmgrInfo *procinfo;
|
||||
FmgrInfo *normprocinfo;
|
||||
FmgrInfo *kmeansnormprocinfo;
|
||||
Oid collation;
|
||||
|
||||
/* Variables */
|
||||
@@ -179,6 +180,9 @@ void IvfflatInitPage(Relation index, Buffer *buf, Page *page, GenericXLogState
|
||||
IndexBuildResult *ivfflatbuild(Relation heap, Relation index, IndexInfo *indexInfo);
|
||||
void ivfflatbuildempty(Relation index);
|
||||
bool ivfflatinsert(Relation index, Datum *values, bool *isnull, ItemPointer heap_tid, Relation heap, IndexUniqueCheck checkUnique
|
||||
#if PG_VERSION_NUM >= 140000
|
||||
,bool indexUnchanged
|
||||
#endif
|
||||
#if PG_VERSION_NUM >= 100000
|
||||
,IndexInfo *indexInfo
|
||||
#endif
|
||||
|
||||
@@ -128,6 +128,9 @@ InsertTuple(Relation rel, IndexTuple itup, Relation heapRel, Datum *values)
|
||||
bool
|
||||
ivfflatinsert(Relation index, Datum *values, bool *isnull, ItemPointer heap_tid,
|
||||
Relation heap, IndexUniqueCheck checkUnique
|
||||
#if PG_VERSION_NUM >= 140000
|
||||
,bool indexUnchanged
|
||||
#endif
|
||||
#if PG_VERSION_NUM >= 100000
|
||||
,IndexInfo *indexInfo
|
||||
#endif
|
||||
|
||||
@@ -251,6 +251,10 @@ ivfflatgettuple(IndexScanDesc scan, ScanDirection dir)
|
||||
{
|
||||
Datum value;
|
||||
|
||||
/* Safety check */
|
||||
if (scan->orderByData == NULL)
|
||||
elog(ERROR, "cannot scan ivfflat index without order");
|
||||
|
||||
/* No items will match if null */
|
||||
if (scan->orderByData->sk_flags & SK_ISNULL)
|
||||
return false;
|
||||
|
||||
128
src/vector.c
128
src/vector.c
@@ -6,14 +6,20 @@
|
||||
#include "fmgr.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "lib/stringinfo.h"
|
||||
#include "libpq/pqformat.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/numeric.h"
|
||||
|
||||
#if PG_VERSION_NUM >= 120000
|
||||
#include "utils/float.h"
|
||||
#endif
|
||||
|
||||
#if PG_VERSION_NUM < 130000
|
||||
#define TYPALIGN_INT 'i'
|
||||
#endif
|
||||
|
||||
PG_MODULE_MAGIC;
|
||||
|
||||
/*
|
||||
@@ -40,6 +46,21 @@ CheckExpectedDim(int32 typmod, int dim)
|
||||
errmsg("expected %d dimensions, not %d", typmod, dim)));
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
CheckDim(int dim)
|
||||
{
|
||||
if (dim < 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATA_EXCEPTION),
|
||||
errmsg("vector must have at least 1 dimension")));
|
||||
|
||||
if (dim > VECTOR_MAX_DIM)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||
errmsg("vector cannot have more than %d dimensions", VECTOR_MAX_DIM)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure finite elements
|
||||
*/
|
||||
@@ -217,6 +238,58 @@ vector_typmod_in(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_INT32(*tl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert external binary representation to internal representation
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(vector_recv);
|
||||
Datum
|
||||
vector_recv(PG_FUNCTION_ARGS)
|
||||
{
|
||||
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
||||
int32 typmod = PG_GETARG_INT32(2);
|
||||
Vector *result;
|
||||
int16 dim;
|
||||
int16 unused;
|
||||
int i;
|
||||
|
||||
dim = pq_getmsgint(buf, sizeof(int16));
|
||||
unused = pq_getmsgint(buf, sizeof(int16));
|
||||
|
||||
CheckDim(dim);
|
||||
CheckExpectedDim(typmod, dim);
|
||||
|
||||
if (unused != 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATA_EXCEPTION),
|
||||
errmsg("expected unused to be 0, not %d", unused)));
|
||||
|
||||
result = InitVector(dim);
|
||||
for (i = 0; i < dim; i++)
|
||||
result->x[i] = pq_getmsgfloat4(buf);
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert internal representation to the external binary representation
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(vector_send);
|
||||
Datum
|
||||
vector_send(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Vector *vec = PG_GETARG_VECTOR_P(0);
|
||||
StringInfoData buf;
|
||||
int i;
|
||||
|
||||
pq_begintypsend(&buf);
|
||||
pq_sendint(&buf, vec->dim, sizeof(int16));
|
||||
pq_sendint(&buf, vec->unused, sizeof(int16));
|
||||
for (i = 0; i < vec->dim; i++)
|
||||
pq_sendfloat4(&buf, vec->x[i]);
|
||||
|
||||
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert vector to vector
|
||||
*/
|
||||
@@ -259,17 +332,7 @@ array_to_vector(PG_FUNCTION_ARGS)
|
||||
deconstruct_array(array, ARR_ELEMTYPE(array), typlen, typbyval, typalign, &elemsp, &nullsp, &nelemsp);
|
||||
|
||||
if (typmod == -1)
|
||||
{
|
||||
if (nelemsp < 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATA_EXCEPTION),
|
||||
errmsg("vector must have at least 1 dimension")));
|
||||
|
||||
if (nelemsp > VECTOR_MAX_DIM)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||
errmsg("vector cannot have more than %d dimensions", VECTOR_MAX_DIM)));
|
||||
}
|
||||
CheckDim(nelemsp);
|
||||
else
|
||||
CheckExpectedDim(typmod, nelemsp);
|
||||
|
||||
@@ -287,6 +350,8 @@ array_to_vector(PG_FUNCTION_ARGS)
|
||||
result->x[i] = DatumGetFloat8(elemsp[i]);
|
||||
else if (ARR_ELEMTYPE(array) == FLOAT4OID)
|
||||
result->x[i] = DatumGetFloat4(elemsp[i]);
|
||||
else if (ARR_ELEMTYPE(array) == NUMERICOID)
|
||||
result->x[i] = DatumGetFloat4(DirectFunctionCall1(numeric_float4, NumericGetDatum(elemsp[i])));
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATA_EXCEPTION),
|
||||
@@ -298,6 +363,29 @@ array_to_vector(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert vector to float4[]
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(vector_to_float4);
|
||||
Datum
|
||||
vector_to_float4(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Vector *vec = PG_GETARG_VECTOR_P(0);
|
||||
Datum *d;
|
||||
ArrayType *result;
|
||||
int i;
|
||||
|
||||
d = (Datum *) palloc(sizeof(Datum) * vec->dim);
|
||||
|
||||
for (i = 0; i < vec->dim; i++)
|
||||
d[i] = Float4GetDatum(vec->x[i]);
|
||||
|
||||
/* Use TYPALIGN_INT for float4 */
|
||||
result = construct_array(d, vec->dim, FLOAT4OID, sizeof(float4), true, TYPALIGN_INT);
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the L2 distance between vectors
|
||||
*/
|
||||
@@ -308,11 +396,15 @@ l2_distance(PG_FUNCTION_ARGS)
|
||||
Vector *a = PG_GETARG_VECTOR_P(0);
|
||||
Vector *b = PG_GETARG_VECTOR_P(1);
|
||||
double distance = 0.0;
|
||||
double diff;
|
||||
|
||||
CheckDims(a, b);
|
||||
|
||||
for (int i = 0; i < a->dim; i++)
|
||||
distance += pow(a->x[i] - b->x[i], 2);
|
||||
{
|
||||
diff = a->x[i] - b->x[i];
|
||||
distance += diff * diff;
|
||||
}
|
||||
|
||||
PG_RETURN_FLOAT8(sqrt(distance));
|
||||
}
|
||||
@@ -328,11 +420,15 @@ vector_l2_squared_distance(PG_FUNCTION_ARGS)
|
||||
Vector *a = PG_GETARG_VECTOR_P(0);
|
||||
Vector *b = PG_GETARG_VECTOR_P(1);
|
||||
double distance = 0.0;
|
||||
double diff;
|
||||
|
||||
CheckDims(a, b);
|
||||
|
||||
for (int i = 0; i < a->dim; i++)
|
||||
distance += pow(a->x[i] - b->x[i], 2);
|
||||
{
|
||||
diff = a->x[i] - b->x[i];
|
||||
distance += diff * diff;
|
||||
}
|
||||
|
||||
PG_RETURN_FLOAT8(distance);
|
||||
}
|
||||
@@ -393,8 +489,8 @@ cosine_distance(PG_FUNCTION_ARGS)
|
||||
for (int i = 0; i < a->dim; i++)
|
||||
{
|
||||
distance += a->x[i] * b->x[i];
|
||||
norma += pow(a->x[i], 2);
|
||||
normb += pow(b->x[i], 2);
|
||||
norma += a->x[i] * a->x[i];
|
||||
normb += b->x[i] * b->x[i];
|
||||
}
|
||||
|
||||
PG_RETURN_FLOAT8(1 - (distance / (sqrt(norma) * sqrt(normb))));
|
||||
@@ -450,7 +546,7 @@ vector_norm(PG_FUNCTION_ARGS)
|
||||
double norm = 0.0;
|
||||
|
||||
for (int i = 0; i < a->dim; i++)
|
||||
norm += pow(a->x[i], 2);
|
||||
norm += a->x[i] * a->x[i];
|
||||
|
||||
PG_RETURN_FLOAT8(sqrt(norm));
|
||||
}
|
||||
|
||||
@@ -6,6 +6,12 @@ SELECT ARRAY[1,2,3]::vector;
|
||||
[1,2,3]
|
||||
(1 row)
|
||||
|
||||
SELECT ARRAY[1.0,2.0,3.0]::vector;
|
||||
array
|
||||
---------
|
||||
[1,2,3]
|
||||
(1 row)
|
||||
|
||||
SELECT ARRAY[1,2,3]::float4[]::vector;
|
||||
array
|
||||
---------
|
||||
@@ -28,3 +34,11 @@ SELECT '{-Infinity}'::real[]::vector;
|
||||
ERROR: infinite value not allowed in vector
|
||||
SELECT '{}'::real[]::vector;
|
||||
ERROR: vector must have at least 1 dimension
|
||||
SELECT '[1,2,3]'::vector::real[];
|
||||
float4
|
||||
---------
|
||||
{1,2,3}
|
||||
(1 row)
|
||||
|
||||
SELECT array_agg(n)::vector FROM generate_series(1, 1025) n;
|
||||
ERROR: vector cannot have more than 1024 dimensions
|
||||
18
test/expected/copy.out
Normal file
18
test/expected/copy.out
Normal file
@@ -0,0 +1,18 @@
|
||||
SET client_min_messages = warning;
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
CREATE TABLE t (val vector(3));
|
||||
INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), (NULL);
|
||||
CREATE TABLE t2 (val vector(3));
|
||||
\copy t TO '/tmp/data.bin' WITH (FORMAT binary)
|
||||
\copy t2 FROM '/tmp/data.bin' WITH (FORMAT binary)
|
||||
SELECT * FROM t2 ORDER BY val;
|
||||
val
|
||||
---------
|
||||
[0,0,0]
|
||||
[1,1,1]
|
||||
[1,2,3]
|
||||
|
||||
(4 rows)
|
||||
|
||||
DROP TABLE t;
|
||||
DROP TABLE t2;
|
||||
@@ -54,3 +54,9 @@ SELECT cosine_distance('[1,2]', '[0,0]');
|
||||
|
||||
SELECT cosine_distance('[1,2]', '[3]');
|
||||
ERROR: different vector dimensions 2 and 1
|
||||
SELECT ARRAY[1,2,3] = ARRAY[1,2,3];
|
||||
?column?
|
||||
----------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
@@ -19,4 +19,10 @@ SELECT * FROM t ORDER BY val <-> (SELECT NULL::vector);
|
||||
-----
|
||||
(0 rows)
|
||||
|
||||
SELECT COUNT(*) FROM t;
|
||||
count
|
||||
-------
|
||||
5
|
||||
(1 row)
|
||||
|
||||
DROP TABLE t;
|
||||
17
test/expected/ivfflat_options.out
Normal file
17
test/expected/ivfflat_options.out
Normal file
@@ -0,0 +1,17 @@
|
||||
SET client_min_messages = warning;
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
SET enable_seqscan = off;
|
||||
CREATE TABLE t (val vector(3));
|
||||
CREATE INDEX ON t USING ivfflat (val) WITH (lists = 0);
|
||||
ERROR: value 0 out of bounds for option "lists"
|
||||
DETAIL: Valid values are between "1" and "32768".
|
||||
CREATE INDEX ON t USING ivfflat (val) WITH (lists = 32769);
|
||||
ERROR: value 32769 out of bounds for option "lists"
|
||||
DETAIL: Valid values are between "1" and "32768".
|
||||
SHOW ivfflat.probes;
|
||||
ivfflat.probes
|
||||
----------------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
DROP TABLE t;
|
||||
@@ -2,6 +2,7 @@ SET client_min_messages = warning;
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
|
||||
SELECT ARRAY[1,2,3]::vector;
|
||||
SELECT ARRAY[1.0,2.0,3.0]::vector;
|
||||
SELECT ARRAY[1,2,3]::float4[]::vector;
|
||||
SELECT ARRAY[1,2,3]::float8[]::vector;
|
||||
SELECT '{NULL}'::real[]::vector;
|
||||
@@ -9,3 +10,5 @@ SELECT '{NaN}'::real[]::vector;
|
||||
SELECT '{Infinity}'::real[]::vector;
|
||||
SELECT '{-Infinity}'::real[]::vector;
|
||||
SELECT '{}'::real[]::vector;
|
||||
SELECT '[1,2,3]'::vector::real[];
|
||||
SELECT array_agg(n)::vector FROM generate_series(1, 1025) n;
|
||||
15
test/sql/copy.sql
Normal file
15
test/sql/copy.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
SET client_min_messages = warning;
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
|
||||
CREATE TABLE t (val vector(3));
|
||||
INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), (NULL);
|
||||
|
||||
CREATE TABLE t2 (val vector(3));
|
||||
|
||||
\copy t TO '/tmp/data.bin' WITH (FORMAT binary)
|
||||
\copy t2 FROM '/tmp/data.bin' WITH (FORMAT binary)
|
||||
|
||||
SELECT * FROM t2 ORDER BY val;
|
||||
|
||||
DROP TABLE t;
|
||||
DROP TABLE t2;
|
||||
@@ -16,3 +16,5 @@ SELECT inner_product('[1,2]', '[3]');
|
||||
SELECT round(cosine_distance('[1,2]', '[2,4]')::numeric, 5);
|
||||
SELECT cosine_distance('[1,2]', '[0,0]');
|
||||
SELECT cosine_distance('[1,2]', '[3]');
|
||||
|
||||
SELECT ARRAY[1,2,3] = ARRAY[1,2,3];
|
||||
15
test/sql/input.sql
Normal file
15
test/sql/input.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
SET client_min_messages = warning;
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
|
||||
SELECT '[1,2,3]'::vector;
|
||||
SELECT '[-1,2,3]'::vector;
|
||||
SELECT '[hello,1]'::vector;
|
||||
SELECT '[NaN,1]'::vector;
|
||||
SELECT '[Infinity,1]'::vector;
|
||||
SELECT '[-Infinity,1]'::vector;
|
||||
SELECT '[1,2,3'::vector;
|
||||
SELECT '[1,2,3]9'::vector;
|
||||
SELECT '1,2,3'::vector;
|
||||
SELECT '[]'::vector;
|
||||
SELECT '[1,]'::vector;
|
||||
SELECT '[1,2,3]'::vector(2);
|
||||
@@ -10,5 +10,6 @@ INSERT INTO t (val) VALUES ('[1,2,4]');
|
||||
|
||||
SELECT * FROM t ORDER BY val <-> '[3,3,3]';
|
||||
SELECT * FROM t ORDER BY val <-> (SELECT NULL::vector);
|
||||
SELECT COUNT(*) FROM t;
|
||||
|
||||
DROP TABLE t;
|
||||
@@ -21,8 +21,9 @@ sub test_index_replay
|
||||
my $caughtup_query;
|
||||
my $server_version_num = $node_primary->safe_psql("postgres", "SHOW server_version_num");
|
||||
if ($server_version_num >= 100000) {
|
||||
$caughtup_query = "SELECT pg_current_wal_lsn() <= write_lsn FROM pg_stat_replication WHERE application_name = '$applname';";
|
||||
$caughtup_query = "SELECT pg_current_wal_lsn() <= replay_lsn FROM pg_stat_replication WHERE application_name = '$applname';";
|
||||
} else {
|
||||
# TODO figure out why replay location doesn't work
|
||||
$caughtup_query = "SELECT pg_current_xlog_location() <= write_location FROM pg_stat_replication WHERE application_name = '$applname';";
|
||||
}
|
||||
|
||||
@@ -1,210 +0,0 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION vector" to load this file. \quit
|
||||
|
||||
-- type
|
||||
|
||||
CREATE TYPE vector;
|
||||
|
||||
CREATE FUNCTION vector_in(cstring, oid, integer) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION vector_out(vector) RETURNS cstring
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION vector_typmod_in(cstring[]) RETURNS integer
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE TYPE vector (
|
||||
INPUT = vector_in,
|
||||
OUTPUT = vector_out,
|
||||
TYPMOD_IN = vector_typmod_in
|
||||
);
|
||||
|
||||
-- functions
|
||||
|
||||
CREATE FUNCTION l2_distance(vector, vector) RETURNS float8
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION inner_product(vector, vector) RETURNS float8
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION cosine_distance(vector, vector) RETURNS float8
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION vector_dims(vector) RETURNS integer
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION vector_norm(vector) RETURNS float8
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION vector_add(vector, vector) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION vector_sub(vector, vector) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
-- private functions
|
||||
|
||||
CREATE FUNCTION vector_lt(vector, vector) RETURNS bool
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION vector_le(vector, vector) RETURNS bool
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION vector_eq(vector, vector) RETURNS bool
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION vector_ne(vector, vector) RETURNS bool
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION vector_ge(vector, vector) RETURNS bool
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION vector_gt(vector, vector) RETURNS bool
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION vector_cmp(vector, vector) RETURNS int4
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION vector_l2_squared_distance(vector, vector) RETURNS float8
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION vector_negative_inner_product(vector, vector) RETURNS float8
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION vector_spherical_distance(vector, vector) RETURNS float8
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
-- cast functions
|
||||
|
||||
CREATE FUNCTION vector(vector, integer, boolean) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION array_to_vector(integer[], integer, boolean) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION array_to_vector(real[], integer, boolean) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
CREATE FUNCTION array_to_vector(double precision[], integer, boolean) RETURNS vector
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
|
||||
|
||||
-- casts
|
||||
|
||||
CREATE CAST (vector AS vector)
|
||||
WITH FUNCTION vector(vector, integer, boolean) AS IMPLICIT;
|
||||
|
||||
CREATE CAST (integer[] AS vector)
|
||||
WITH FUNCTION array_to_vector(integer[], integer, boolean) AS IMPLICIT;
|
||||
|
||||
CREATE CAST (real[] AS vector)
|
||||
WITH FUNCTION array_to_vector(real[], integer, boolean) AS IMPLICIT;
|
||||
|
||||
CREATE CAST (double precision[] AS vector)
|
||||
WITH FUNCTION array_to_vector(double precision[], integer, boolean) AS IMPLICIT;
|
||||
|
||||
-- operators
|
||||
|
||||
CREATE OPERATOR <-> (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = l2_distance,
|
||||
COMMUTATOR = '<->'
|
||||
);
|
||||
|
||||
CREATE OPERATOR <#> (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_negative_inner_product,
|
||||
COMMUTATOR = '<#>'
|
||||
);
|
||||
|
||||
CREATE OPERATOR <=> (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = cosine_distance,
|
||||
COMMUTATOR = '<=>'
|
||||
);
|
||||
|
||||
CREATE OPERATOR + (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_add,
|
||||
COMMUTATOR = +
|
||||
);
|
||||
|
||||
CREATE OPERATOR - (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_sub,
|
||||
COMMUTATOR = -
|
||||
);
|
||||
|
||||
CREATE OPERATOR < (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_lt,
|
||||
COMMUTATOR = > , NEGATOR = >= ,
|
||||
RESTRICT = scalarltsel, JOIN = scalarltjoinsel
|
||||
);
|
||||
|
||||
-- should use scalarlesel and scalarlejoinsel, but not supported in Postgres < 11
|
||||
CREATE OPERATOR <= (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_le,
|
||||
COMMUTATOR = >= , NEGATOR = > ,
|
||||
RESTRICT = scalarltsel, JOIN = scalarltjoinsel
|
||||
);
|
||||
|
||||
CREATE OPERATOR = (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_eq,
|
||||
COMMUTATOR = = , NEGATOR = <> ,
|
||||
RESTRICT = eqsel, JOIN = eqjoinsel
|
||||
);
|
||||
|
||||
CREATE OPERATOR <> (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_ne,
|
||||
COMMUTATOR = <> , NEGATOR = = ,
|
||||
RESTRICT = eqsel, JOIN = eqjoinsel
|
||||
);
|
||||
|
||||
-- should use scalargesel and scalargejoinsel, but not supported in Postgres < 11
|
||||
CREATE OPERATOR >= (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_ge,
|
||||
COMMUTATOR = <= , NEGATOR = < ,
|
||||
RESTRICT = scalargtsel, JOIN = scalargtjoinsel
|
||||
);
|
||||
|
||||
CREATE OPERATOR > (
|
||||
LEFTARG = vector, RIGHTARG = vector, PROCEDURE = vector_gt,
|
||||
COMMUTATOR = < , NEGATOR = <= ,
|
||||
RESTRICT = scalargtsel, JOIN = scalargtjoinsel
|
||||
);
|
||||
|
||||
-- access method
|
||||
|
||||
CREATE FUNCTION ivfflathandler(internal) RETURNS index_am_handler
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C;
|
||||
|
||||
CREATE ACCESS METHOD ivfflat TYPE INDEX HANDLER ivfflathandler;
|
||||
|
||||
COMMENT ON ACCESS METHOD ivfflat IS 'ivfflat index access method';
|
||||
|
||||
-- opclasses
|
||||
|
||||
CREATE OPERATOR CLASS vector_ops
|
||||
DEFAULT FOR TYPE vector USING btree AS
|
||||
OPERATOR 1 < ,
|
||||
OPERATOR 2 <= ,
|
||||
OPERATOR 3 = ,
|
||||
OPERATOR 4 >= ,
|
||||
OPERATOR 5 > ,
|
||||
FUNCTION 1 vector_cmp(vector, vector);
|
||||
|
||||
CREATE OPERATOR CLASS vector_l2_ops
|
||||
DEFAULT FOR TYPE vector USING ivfflat AS
|
||||
OPERATOR 1 <-> (vector, vector) FOR ORDER BY float_ops,
|
||||
FUNCTION 1 vector_l2_squared_distance(vector, vector),
|
||||
FUNCTION 3 l2_distance(vector, vector);
|
||||
|
||||
CREATE OPERATOR CLASS vector_ip_ops
|
||||
FOR TYPE vector USING ivfflat AS
|
||||
OPERATOR 1 <#> (vector, vector) FOR ORDER BY float_ops,
|
||||
FUNCTION 1 vector_negative_inner_product(vector, vector),
|
||||
FUNCTION 3 vector_spherical_distance(vector, vector),
|
||||
FUNCTION 4 vector_norm(vector);
|
||||
|
||||
CREATE OPERATOR CLASS vector_cosine_ops
|
||||
FOR TYPE vector USING ivfflat AS
|
||||
OPERATOR 1 <=> (vector, vector) FOR ORDER BY float_ops,
|
||||
FUNCTION 1 vector_negative_inner_product(vector, vector),
|
||||
FUNCTION 2 vector_norm(vector),
|
||||
FUNCTION 3 vector_spherical_distance(vector, vector),
|
||||
FUNCTION 4 vector_norm(vector);
|
||||
@@ -1,4 +1,4 @@
|
||||
comment = 'vector data type and ivfflat access method'
|
||||
default_version = '0.1.0'
|
||||
default_version = '0.2.1'
|
||||
module_pathname = '$libdir/vector'
|
||||
relocatable = true
|
||||
|
||||
Reference in New Issue
Block a user