mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-22 20:15:46 +08:00
Compare commits
42 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 |
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -8,10 +8,10 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
postgres: [13, 12, 11, 10, 9.6]
|
postgres: [14, 13, 12, 11, 10, 9.6]
|
||||||
include:
|
include:
|
||||||
- os: macos-latest
|
- os: macos-latest
|
||||||
postgres: 13
|
postgres: 14
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: ankane/setup-postgres@v1
|
- uses: ankane/setup-postgres@v1
|
||||||
|
|||||||
24
CHANGELOG.md
24
CHANGELOG.md
@@ -1,3 +1,27 @@
|
|||||||
|
## 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)
|
## 0.1.4 (2021-05-09)
|
||||||
|
|
||||||
- Fixed kmeans for inner product
|
- Fixed kmeans for inner product
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
FROM postgres
|
FROM postgres:14
|
||||||
|
|
||||||
COPY . /tmp/pgvector
|
COPY . /tmp/pgvector
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y --no-install-recommends build-essential postgresql-server-dev-13 && \
|
apt-get install -y --no-install-recommends build-essential postgresql-server-dev-14 && \
|
||||||
cd /tmp/pgvector && \
|
cd /tmp/pgvector && \
|
||||||
make clean && \
|
make clean && \
|
||||||
make OPTFLAGS="" && \
|
make OPTFLAGS="" && \
|
||||||
@@ -11,6 +11,6 @@ RUN apt-get update && \
|
|||||||
mkdir /usr/share/doc/pgvector && \
|
mkdir /usr/share/doc/pgvector && \
|
||||||
cp LICENSE README.md /usr/share/doc/pgvector && \
|
cp LICENSE README.md /usr/share/doc/pgvector && \
|
||||||
rm -r /tmp/pgvector && \
|
rm -r /tmp/pgvector && \
|
||||||
apt-get remove -y build-essential postgresql-server-dev-13 && \
|
apt-get remove -y build-essential postgresql-server-dev-14 && \
|
||||||
apt-get autoremove -y && \
|
apt-get autoremove -y && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "vector",
|
"name": "vector",
|
||||||
"abstract": "Open-source vector similarity search for Postgres",
|
"abstract": "Open-source vector similarity search for Postgres",
|
||||||
"description": "Supports L2 distance, inner product, and cosine distance",
|
"description": "Supports L2 distance, inner product, and cosine distance",
|
||||||
"version": "0.1.4",
|
"version": "0.2.1",
|
||||||
"maintainer": [
|
"maintainer": [
|
||||||
"Andrew Kane <andrew@ankane.org>"
|
"Andrew Kane <andrew@ankane.org>"
|
||||||
],
|
],
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
"vector": {
|
"vector": {
|
||||||
"file": "sql/vector.sql",
|
"file": "sql/vector.sql",
|
||||||
"docfile": "README.md",
|
"docfile": "README.md",
|
||||||
"version": "0.1.4",
|
"version": "0.2.1",
|
||||||
"abstract": "Open-source vector similarity search for Postgres"
|
"abstract": "Open-source vector similarity search for Postgres"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
7
Makefile
7
Makefile
@@ -1,5 +1,5 @@
|
|||||||
EXTENSION = vector
|
EXTENSION = vector
|
||||||
EXTVERSION = 0.1.4
|
EXTVERSION = 0.2.1
|
||||||
|
|
||||||
MODULE_big = vector
|
MODULE_big = vector
|
||||||
DATA = $(wildcard sql/*--*.sql)
|
DATA = $(wildcard sql/*--*.sql)
|
||||||
@@ -42,3 +42,8 @@ prove_installcheck:
|
|||||||
dist:
|
dist:
|
||||||
mkdir -p dist
|
mkdir -p dist
|
||||||
git archive --format zip --prefix=$(EXTENSION)-$(EXTVERSION)/ --output dist/$(EXTENSION)-$(EXTVERSION).zip master
|
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 .
|
||||||
|
|||||||
60
README.md
60
README.md
@@ -4,7 +4,7 @@ Open-source vector similarity search for Postgres
|
|||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE table (column vector(3));
|
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;
|
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+)
|
Compile and install the extension (supports Postgres 9.6+)
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone --branch v0.1.4 https://github.com/ankane/pgvector.git
|
git clone --branch v0.2.1 https://github.com/ankane/pgvector.git
|
||||||
cd pgvector
|
cd pgvector
|
||||||
make
|
make
|
||||||
make install # may need sudo
|
make install # may need sudo
|
||||||
@@ -62,7 +62,7 @@ Speed up queries with an approximate index. Add an index for each distance funct
|
|||||||
L2 distance
|
L2 distance
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE INDEX ON table USING ivfflat (column);
|
CREATE INDEX ON table USING ivfflat (column vector_l2_ops);
|
||||||
```
|
```
|
||||||
|
|
||||||
Inner product
|
Inner product
|
||||||
@@ -77,16 +77,30 @@ Cosine distance
|
|||||||
CREATE INDEX ON table USING ivfflat (column vector_cosine_ops);
|
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
|
### Index Options
|
||||||
|
|
||||||
Specify the number of inverted lists (100 by default)
|
Specify the number of inverted lists (100 by default)
|
||||||
|
|
||||||
```sql
|
```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
|
### Query Options
|
||||||
|
|
||||||
Specify the number of probes (1 by default)
|
Specify the number of probes (1 by default)
|
||||||
@@ -106,6 +120,30 @@ SELECT ...
|
|||||||
COMMIT;
|
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
|
## Reference
|
||||||
|
|
||||||
### Vector Type
|
### Vector Type
|
||||||
@@ -136,7 +174,12 @@ vector_norm(vector) | Euclidean norm
|
|||||||
|
|
||||||
Libraries that use pgvector:
|
Libraries that use pgvector:
|
||||||
|
|
||||||
|
- [pgvector-python](https://github.com/ankane/pgvector-python) (Python)
|
||||||
- [Neighbor](https://github.com/ankane/neighbor) (Ruby)
|
- [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
|
## Additional Installation Methods
|
||||||
|
|
||||||
@@ -153,7 +196,7 @@ This adds pgvector to the [Postgres image](https://hub.docker.com/_/postgres).
|
|||||||
You can also build the image manually
|
You can also build the image manually
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone --branch v0.1.4 https://github.com/ankane/pgvector.git
|
git clone --branch v0.2.1 https://github.com/ankane/pgvector.git
|
||||||
cd pgvector
|
cd pgvector
|
||||||
docker build -t pgvector .
|
docker build -t pgvector .
|
||||||
```
|
```
|
||||||
@@ -181,10 +224,11 @@ Some Postgres providers only support specific extensions. To request a new exten
|
|||||||
- Amazon RDS - follow the instructions on [this page](https://aws.amazon.com/rds/postgresql/faqs/)
|
- 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)
|
- 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)
|
- 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
|
## Upgrading
|
||||||
|
|
||||||
Compile and install the latest version and run:
|
Install the latest version and run:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
ALTER EXTENSION vector UPDATE;
|
ALTER EXTENSION vector UPDATE;
|
||||||
@@ -232,7 +276,7 @@ make prove_installcheck # TAP tests
|
|||||||
To run single tests:
|
To run single tests:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
make installcheck REGRESS=vector # regression test
|
make installcheck REGRESS=functions # regression test
|
||||||
make prove_installcheck PROVE_TESTS=test/t/001_wal.pl # TAP test
|
make prove_installcheck PROVE_TESTS=test/t/001_wal.pl # TAP test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
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;
|
||||||
@@ -97,19 +97,31 @@ CREATE FUNCTION array_to_vector(real[], integer, boolean) RETURNS vector
|
|||||||
CREATE FUNCTION array_to_vector(double precision[], integer, boolean) RETURNS vector
|
CREATE FUNCTION array_to_vector(double precision[], integer, boolean) RETURNS vector
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
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
|
-- casts
|
||||||
|
|
||||||
CREATE CAST (vector AS vector)
|
CREATE CAST (vector AS vector)
|
||||||
WITH FUNCTION vector(vector, integer, boolean) AS IMPLICIT;
|
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)
|
CREATE CAST (integer[] AS vector)
|
||||||
WITH FUNCTION array_to_vector(integer[], integer, boolean) AS IMPLICIT;
|
WITH FUNCTION array_to_vector(integer[], integer, boolean) AS ASSIGNMENT;
|
||||||
|
|
||||||
CREATE CAST (real[] AS vector)
|
CREATE CAST (real[] AS vector)
|
||||||
WITH FUNCTION array_to_vector(real[], integer, boolean) AS IMPLICIT;
|
WITH FUNCTION array_to_vector(real[], integer, boolean) AS ASSIGNMENT;
|
||||||
|
|
||||||
CREATE CAST (double precision[] AS vector)
|
CREATE CAST (double precision[] AS vector)
|
||||||
WITH FUNCTION array_to_vector(double precision[], integer, boolean) AS IMPLICIT;
|
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
|
-- operators
|
||||||
|
|
||||||
|
|||||||
@@ -241,6 +241,8 @@ InsertTuples(Relation index, IvfflatBuildState * buildstate, ForkNumber forkNum)
|
|||||||
if (PageAddItem(page, (Item) itup, itemsz, InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
|
if (PageAddItem(page, (Item) itup, itemsz, InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
|
||||||
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
elog(ERROR, "failed to add index item to \"%s\"", RelationGetRelationName(index));
|
||||||
|
|
||||||
|
pfree(itup);
|
||||||
|
|
||||||
buildstate->indtuples += 1;
|
buildstate->indtuples += 1;
|
||||||
|
|
||||||
GetNextTuple(buildstate->sortstate, tupdesc, slot, &itup, &list);
|
GetNextTuple(buildstate->sortstate, tupdesc, slot, &itup, &list);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
#include "access/amapi.h"
|
#include "access/amapi.h"
|
||||||
#include "commands/vacuum.h"
|
#include "commands/vacuum.h"
|
||||||
#include "ivfflat.h"
|
#include "ivfflat.h"
|
||||||
@@ -44,18 +46,29 @@ ivfflatcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
|
|||||||
int lists;
|
int lists;
|
||||||
double ratio;
|
double ratio;
|
||||||
Relation indexRel;
|
Relation indexRel;
|
||||||
|
|
||||||
#if PG_VERSION_NUM < 120000
|
#if PG_VERSION_NUM < 120000
|
||||||
List *qinfos;
|
List *qinfos;
|
||||||
|
|
||||||
qinfos = deconstruct_indexquals(path);
|
|
||||||
#endif
|
#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));
|
MemSet(&costs, 0, sizeof(costs));
|
||||||
|
|
||||||
#if PG_VERSION_NUM >= 120000
|
#if PG_VERSION_NUM >= 120000
|
||||||
genericcostestimate(root, path, loop_count, &costs);
|
genericcostestimate(root, path, loop_count, &costs);
|
||||||
#else
|
#else
|
||||||
|
qinfos = deconstruct_indexquals(path);
|
||||||
genericcostestimate(root, path, loop_count, qinfos, &costs);
|
genericcostestimate(root, path, loop_count, qinfos, &costs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -180,6 +180,9 @@ void IvfflatInitPage(Relation index, Buffer *buf, Page *page, GenericXLogState
|
|||||||
IndexBuildResult *ivfflatbuild(Relation heap, Relation index, IndexInfo *indexInfo);
|
IndexBuildResult *ivfflatbuild(Relation heap, Relation index, IndexInfo *indexInfo);
|
||||||
void ivfflatbuildempty(Relation index);
|
void ivfflatbuildempty(Relation index);
|
||||||
bool ivfflatinsert(Relation index, Datum *values, bool *isnull, ItemPointer heap_tid, Relation heap, IndexUniqueCheck checkUnique
|
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
|
#if PG_VERSION_NUM >= 100000
|
||||||
,IndexInfo *indexInfo
|
,IndexInfo *indexInfo
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -128,6 +128,9 @@ InsertTuple(Relation rel, IndexTuple itup, Relation heapRel, Datum *values)
|
|||||||
bool
|
bool
|
||||||
ivfflatinsert(Relation index, Datum *values, bool *isnull, ItemPointer heap_tid,
|
ivfflatinsert(Relation index, Datum *values, bool *isnull, ItemPointer heap_tid,
|
||||||
Relation heap, IndexUniqueCheck checkUnique
|
Relation heap, IndexUniqueCheck checkUnique
|
||||||
|
#if PG_VERSION_NUM >= 140000
|
||||||
|
,bool indexUnchanged
|
||||||
|
#endif
|
||||||
#if PG_VERSION_NUM >= 100000
|
#if PG_VERSION_NUM >= 100000
|
||||||
,IndexInfo *indexInfo
|
,IndexInfo *indexInfo
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -251,6 +251,10 @@ ivfflatgettuple(IndexScanDesc scan, ScanDirection dir)
|
|||||||
{
|
{
|
||||||
Datum value;
|
Datum value;
|
||||||
|
|
||||||
|
/* Safety check */
|
||||||
|
if (scan->orderByData == NULL)
|
||||||
|
elog(ERROR, "cannot scan ivfflat index without order");
|
||||||
|
|
||||||
/* No items will match if null */
|
/* No items will match if null */
|
||||||
if (scan->orderByData->sk_flags & SK_ISNULL)
|
if (scan->orderByData->sk_flags & SK_ISNULL)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
38
src/vector.c
38
src/vector.c
@@ -10,11 +10,16 @@
|
|||||||
#include "utils/array.h"
|
#include "utils/array.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
|
#include "utils/numeric.h"
|
||||||
|
|
||||||
#if PG_VERSION_NUM >= 120000
|
#if PG_VERSION_NUM >= 120000
|
||||||
#include "utils/float.h"
|
#include "utils/float.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if PG_VERSION_NUM < 130000
|
||||||
|
#define TYPALIGN_INT 'i'
|
||||||
|
#endif
|
||||||
|
|
||||||
PG_MODULE_MAGIC;
|
PG_MODULE_MAGIC;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -244,14 +249,20 @@ vector_recv(PG_FUNCTION_ARGS)
|
|||||||
int32 typmod = PG_GETARG_INT32(2);
|
int32 typmod = PG_GETARG_INT32(2);
|
||||||
Vector *result;
|
Vector *result;
|
||||||
int16 dim;
|
int16 dim;
|
||||||
|
int16 unused;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
dim = pq_getmsgint(buf, sizeof(int16));
|
dim = pq_getmsgint(buf, sizeof(int16));
|
||||||
pq_getmsgint(buf, sizeof(int16)); /* unused */
|
unused = pq_getmsgint(buf, sizeof(int16));
|
||||||
|
|
||||||
CheckDim(dim);
|
CheckDim(dim);
|
||||||
CheckExpectedDim(typmod, 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);
|
result = InitVector(dim);
|
||||||
for (i = 0; i < dim; i++)
|
for (i = 0; i < dim; i++)
|
||||||
result->x[i] = pq_getmsgfloat4(buf);
|
result->x[i] = pq_getmsgfloat4(buf);
|
||||||
@@ -339,6 +350,8 @@ array_to_vector(PG_FUNCTION_ARGS)
|
|||||||
result->x[i] = DatumGetFloat8(elemsp[i]);
|
result->x[i] = DatumGetFloat8(elemsp[i]);
|
||||||
else if (ARR_ELEMTYPE(array) == FLOAT4OID)
|
else if (ARR_ELEMTYPE(array) == FLOAT4OID)
|
||||||
result->x[i] = DatumGetFloat4(elemsp[i]);
|
result->x[i] = DatumGetFloat4(elemsp[i]);
|
||||||
|
else if (ARR_ELEMTYPE(array) == NUMERICOID)
|
||||||
|
result->x[i] = DatumGetFloat4(DirectFunctionCall1(numeric_float4, NumericGetDatum(elemsp[i])));
|
||||||
else
|
else
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_DATA_EXCEPTION),
|
(errcode(ERRCODE_DATA_EXCEPTION),
|
||||||
@@ -350,6 +363,29 @@ array_to_vector(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_POINTER(result);
|
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
|
* Get the L2 distance between vectors
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -6,6 +6,12 @@ SELECT ARRAY[1,2,3]::vector;
|
|||||||
[1,2,3]
|
[1,2,3]
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT ARRAY[1.0,2.0,3.0]::vector;
|
||||||
|
array
|
||||||
|
---------
|
||||||
|
[1,2,3]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT ARRAY[1,2,3]::float4[]::vector;
|
SELECT ARRAY[1,2,3]::float4[]::vector;
|
||||||
array
|
array
|
||||||
---------
|
---------
|
||||||
@@ -28,3 +34,11 @@ SELECT '{-Infinity}'::real[]::vector;
|
|||||||
ERROR: infinite value not allowed in vector
|
ERROR: infinite value not allowed in vector
|
||||||
SELECT '{}'::real[]::vector;
|
SELECT '{}'::real[]::vector;
|
||||||
ERROR: vector must have at least 1 dimension
|
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
|
||||||
|
|||||||
@@ -54,3 +54,9 @@ SELECT cosine_distance('[1,2]', '[0,0]');
|
|||||||
|
|
||||||
SELECT cosine_distance('[1,2]', '[3]');
|
SELECT cosine_distance('[1,2]', '[3]');
|
||||||
ERROR: different vector dimensions 2 and 1
|
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)
|
(0 rows)
|
||||||
|
|
||||||
|
SELECT COUNT(*) FROM t;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
5
|
||||||
|
(1 row)
|
||||||
|
|
||||||
DROP TABLE t;
|
DROP TABLE t;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ SET client_min_messages = warning;
|
|||||||
CREATE EXTENSION IF NOT EXISTS vector;
|
CREATE EXTENSION IF NOT EXISTS vector;
|
||||||
|
|
||||||
SELECT ARRAY[1,2,3]::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]::float4[]::vector;
|
||||||
SELECT ARRAY[1,2,3]::float8[]::vector;
|
SELECT ARRAY[1,2,3]::float8[]::vector;
|
||||||
SELECT '{NULL}'::real[]::vector;
|
SELECT '{NULL}'::real[]::vector;
|
||||||
@@ -9,3 +10,5 @@ SELECT '{NaN}'::real[]::vector;
|
|||||||
SELECT '{Infinity}'::real[]::vector;
|
SELECT '{Infinity}'::real[]::vector;
|
||||||
SELECT '{-Infinity}'::real[]::vector;
|
SELECT '{-Infinity}'::real[]::vector;
|
||||||
SELECT '{}'::real[]::vector;
|
SELECT '{}'::real[]::vector;
|
||||||
|
SELECT '[1,2,3]'::vector::real[];
|
||||||
|
SELECT array_agg(n)::vector FROM generate_series(1, 1025) n;
|
||||||
|
|||||||
@@ -16,3 +16,5 @@ SELECT inner_product('[1,2]', '[3]');
|
|||||||
SELECT round(cosine_distance('[1,2]', '[2,4]')::numeric, 5);
|
SELECT round(cosine_distance('[1,2]', '[2,4]')::numeric, 5);
|
||||||
SELECT cosine_distance('[1,2]', '[0,0]');
|
SELECT cosine_distance('[1,2]', '[0,0]');
|
||||||
SELECT cosine_distance('[1,2]', '[3]');
|
SELECT cosine_distance('[1,2]', '[3]');
|
||||||
|
|
||||||
|
SELECT ARRAY[1,2,3] = ARRAY[1,2,3];
|
||||||
|
|||||||
@@ -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 <-> '[3,3,3]';
|
||||||
SELECT * FROM t ORDER BY val <-> (SELECT NULL::vector);
|
SELECT * FROM t ORDER BY val <-> (SELECT NULL::vector);
|
||||||
|
SELECT COUNT(*) FROM t;
|
||||||
|
|
||||||
DROP TABLE t;
|
DROP TABLE t;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
comment = 'vector data type and ivfflat access method'
|
comment = 'vector data type and ivfflat access method'
|
||||||
default_version = '0.1.4'
|
default_version = '0.2.1'
|
||||||
module_pathname = '$libdir/vector'
|
module_pathname = '$libdir/vector'
|
||||||
relocatable = true
|
relocatable = true
|
||||||
|
|||||||
Reference in New Issue
Block a user