Compare commits

..

14 Commits

Author SHA1 Message Date
Andrew Kane
e0854e6381 Version bump to 0.1.1 [skip ci] 2021-04-25 15:02:14 -07:00
Andrew Kane
2515cf050d Removed pow 2021-04-24 17:15:53 -07:00
Andrew Kane
fb015adc25 Updated changelog [skip ci] 2021-04-23 03:32:58 -07:00
Andrew Kane
236447824e Marked functions as PARALLEL SAFE 2021-04-23 03:29:22 -07:00
Andrew Kane
969823c49f Fixed CI 2021-04-22 21:25:37 -07:00
Andrew Kane
79ae168dc3 Updated changelog [skip ci] 2021-04-22 19:20:47 -07:00
Andrew Kane
29b43a1e24 Use pq_sendint instead of pq_sendint16 for Postgres < 11 2021-04-22 19:18:14 -07:00
Andrew Kane
d14a6bca4b Fixed upgrade filename 2021-04-22 19:11:03 -07:00
Andrew Kane
8ebab9bf6d Added external binary representation for vector type 2021-04-22 19:06:14 -07:00
Andrew Kane
c4baa335d3 Moved libraries [skip ci] 2021-04-21 17:46:54 -07:00
Andrew Kane
4b7053b544 Added libraries section [skip ci] 2021-04-21 17:36:19 -07:00
Andrew Kane
d08544f676 Run apt-get update on CI 2021-04-20 16:03:12 -07:00
Andrew Kane
b1df1ec83e Simplified CI 2021-04-20 15:59:56 -07:00
Andrew Kane
5e721daa2a Updated readme [skip ci] 2021-04-20 15:10:39 -07:00
10 changed files with 208 additions and 50 deletions

View File

@@ -10,14 +10,10 @@ jobs:
postgres: [13, 12, 11, 10, 9.6]
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
- run: sudo apt-get update && sudo apt-get install postgresql-server-dev-${{ matrix.postgres }} libipc-run-perl
- run: make
- run: |
export PG_CONFIG=`which pg_config`

View File

@@ -1,3 +1,8 @@
## 0.1.1 (2021-04-25)
- Added binary representation for `COPY`
- Marked functions as `PARALLEL SAFE`
## 0.1.0 (2021-04-20)
- First release

View File

@@ -1,11 +1,11 @@
EXTENSION = vector
DATA = vector--0.1.0.sql
DATA = vector--0.1.1.sql vector--0.1.0--0.1.1.sql
MODULE_big = vector
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)
REGRESS = btree cast functions ivfflat_cosine ivfflat_ip ivfflat_l2 ivfflat_unlogged vector
REGRESS = btree cast copy functions ivfflat_cosine ivfflat_ip ivfflat_l2 ivfflat_unlogged vector
PG_CONFIG ?= pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)

View File

@@ -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.1.1 https://github.com/ankane/pgvector.git
cd pgvector
make
make install # may need sudo
@@ -130,6 +130,22 @@ l2_distance(vector, vector) | Euclidean distance
vector_dims(vector) | number of dimensions
vector_norm(vector) | Euclidean norm
## Libraries
Libraries that use pgvector:
- [Neighbor](https://github.com/ankane/neighbor) (Ruby)
## Upgrading
### 0.1.1
Follow the [installation instructions](#installation) and run:
```sql
ALTER EXTENSION vector UPDATE TO '0.1.1';
```
## Thanks
Thanks to:

18
expected/copy.out Normal file
View 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;

15
sql/copy.sql Normal file
View 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;

View File

@@ -6,6 +6,7 @@
#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"
@@ -40,6 +41,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 +233,53 @@ 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);
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 +322,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);
@@ -308,11 +361,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 +385,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 +454,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 +511,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));
}

39
vector--0.1.0--0.1.1.sql Normal file
View 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;

View File

@@ -6,88 +6,96 @@
CREATE TYPE vector;
CREATE FUNCTION vector_in(cstring, oid, integer) RETURNS vector
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE FUNCTION vector_out(vector) RETURNS cstring
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE FUNCTION vector_typmod_in(cstring[]) RETURNS integer
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
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
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;
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE FUNCTION inner_product(vector, vector) RETURNS float8
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE FUNCTION cosine_distance(vector, vector) RETURNS float8
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE FUNCTION vector_dims(vector) RETURNS integer
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE FUNCTION vector_norm(vector) RETURNS float8
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE FUNCTION vector_add(vector, vector) RETURNS vector
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE FUNCTION vector_sub(vector, vector) RETURNS vector
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
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;
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE FUNCTION vector_le(vector, vector) RETURNS bool
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE FUNCTION vector_eq(vector, vector) RETURNS bool
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE FUNCTION vector_ne(vector, vector) RETURNS bool
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE FUNCTION vector_ge(vector, vector) RETURNS bool
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE FUNCTION vector_gt(vector, vector) RETURNS bool
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE FUNCTION vector_cmp(vector, vector) RETURNS int4
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
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;
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;
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;
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;
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;
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;
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;
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
-- casts

View File

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