Compare commits

..

35 Commits

Author SHA1 Message Date
Andrew Kane
647c9002be Version bump to 0.2.1 [skip ci] 2022-01-02 19:11:37 -05:00
Andrew Kane
3e6345f02a Moved function 2022-01-02 19:09:37 -05:00
Andrew Kane
2b3484ddcd Fixed CI 2022-01-02 19:03:15 -05:00
Andrew Kane
1a6debf281 Fixed operator is not unique error - fixes #20 2022-01-02 18:47:03 -05:00
Andrew Kane
bff4d7ea68 Updated link [skip ci] 2021-10-13 14:29:09 -07:00
Andrew Kane
d5b979e4fa Added guidance on lists [skip ci] 2021-10-13 14:27:01 -07:00
Andrew Kane
d52426b3fa Improved examples [skip ci] 2021-10-13 14:06:55 -07:00
Andrew Kane
b125b2debb Added section on performance [skip ci] 2021-10-13 13:56:03 -07:00
Andrew Kane
3d7186a17c Added Docker to Makefile [skip ci] 2021-10-13 13:53:29 -07:00
Andrew Kane
58ba2139ce Added instructions for reindexing - #17 [skip ci] 2021-10-13 13:48:54 -07:00
Andrew Kane
fd93c9db86 Version bump to 0.2.0 [skip ci] 2021-10-03 20:32:45 -07:00
Andrew Kane
8dde26920c Added support for Postgres 14 2021-09-30 16:28:25 -07:00
Andrew Kane
9153a545a7 Added link to pgvector-cpp [skip ci] 2021-09-10 15:22:44 -07:00
Andrew Kane
9c20f04a11 Version bump to 0.1.8 [skip ci] 2021-09-07 14:10:58 -07:00
Andrew Kane
7c12d100ce Fixed build for Postgres < 13 2021-06-20 22:06:14 -07:00
Andrew Kane
d97d9a6561 Added cast for vector to real[] 2021-06-20 21:53:06 -07:00
Andrew Kane
f15ea301c5 Added link to Node library [skip ci] 2021-06-18 15:01:32 -07:00
Andrew Kane
cfa23f2c7a Added note on partitioning [skip ci] 2021-06-17 14:20:43 -07:00
Andrew Kane
b5b7035edc Restored section on partial indexes [skip ci] 2021-06-17 14:05:48 -07:00
Andrew Kane
478d62cdbd Added link to Go library [skip ci] 2021-06-16 17:33:49 -07:00
Andrew Kane
c7df9ef3a1 Updated changelog [skip ci] 2021-06-13 12:58:10 -07:00
Andrew Kane
ea1b094d8e Version bump to 0.1.7 [skip ci] 2021-06-13 12:52:55 -07:00
Andrew Kane
63d2965e8e Added link to pgvector-python [skip ci] 2021-06-12 06:49:44 -07:00
Andrew Kane
e5e7a6ec15 Fixed message [skip ci] 2021-06-11 03:36:06 -07:00
Andrew Kane
ede572d80b Fixed identation [skip ci] 2021-06-11 03:35:17 -07:00
Andrew Kane
154e4334fb Added cast for numeric[] 2021-06-11 03:32:47 -07:00
Andrew Kane
77d54333f6 Updated link [skip ci] 2021-06-09 22:01:38 -07:00
Andrew Kane
c95732340a Version bump to 0.1.6 [skip ci] 2021-06-09 20:48:50 -07:00
Andrew Kane
2af9bdefbb Added link to pgvector.rs [skip ci] 2021-06-09 19:42:40 -07:00
Andrew Kane
bd36231871 Less space [skip ci] 2021-06-09 04:03:06 -07:00
Andrew Kane
523788d964 Improved code 2021-06-09 03:59:00 -07:00
Andrew Kane
1eed57310a Use DBL_MAX for cost 2021-06-09 03:31:41 -07:00
Andrew Kane
57e6a01214 Fixed segmentation fault with COUNT - fixes #9 2021-06-09 03:13:22 -07:00
Andrew Kane
b713cbc3b6 Added instructions for Azure [skip ci] 2021-06-08 23:36:47 -07:00
Andrew Kane
ebeac156c0 Require unused to be 0 2021-05-26 13:40:38 -07:00
24 changed files with 230 additions and 22 deletions

View File

@@ -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

View File

@@ -1,3 +1,23 @@
## 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) ## 0.1.5 (2021-05-25)
- Reduced memory usage during index creation - Reduced memory usage during index creation

View File

@@ -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/*

View File

@@ -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.5", "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.5", "version": "0.2.1",
"abstract": "Open-source vector similarity search for Postgres" "abstract": "Open-source vector similarity search for Postgres"
} }
}, },

View File

@@ -1,5 +1,5 @@
EXTENSION = vector EXTENSION = vector
EXTVERSION = 0.1.5 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 .

View File

@@ -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.5 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.5 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,6 +224,7 @@ 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

View 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

View 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;

View 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;

View 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

View 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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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
*/ */

View File

@@ -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,5 +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; SELECT array_agg(n)::vector FROM generate_series(1, 1025) n;
ERROR: vector cannot have more than 1024 dimensions ERROR: vector cannot have more than 1024 dimensions

View File

@@ -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)

View File

@@ -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;

View File

@@ -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,4 +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; SELECT array_agg(n)::vector FROM generate_series(1, 1025) n;

View File

@@ -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];

View File

@@ -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;

View File

@@ -1,4 +1,4 @@
comment = 'vector data type and ivfflat access method' comment = 'vector data type and ivfflat access method'
default_version = '0.1.5' default_version = '0.2.1'
module_pathname = '$libdir/vector' module_pathname = '$libdir/vector'
relocatable = true relocatable = true