Compare commits

...

16 Commits

Author SHA1 Message Date
Andrew Kane
5af768752f Version bump to 0.3.0 [skip ci] 2022-10-15 14:38:43 -07:00
Andrew Kane
f03bcc4fd8 Updated Dockerfile to Postgres 15 [skip ci] 2022-10-14 16:01:25 -07:00
Andrew Kane
74fc4b9aaa Added .pm to .editorconfig [skip ci] 2022-10-14 14:05:20 -07:00
Andrew Kane
6870ba96ba Removed Postgres 9.6 from CI 2022-10-14 13:47:07 -07:00
Andrew Kane
2575cfdaa8 Fixed CI 2022-10-14 13:45:16 -07:00
Andrew Kane
9ff5ceacca Dropped support for Postgres 9.6 [skip ci] 2022-10-14 13:44:13 -07:00
Andrew Kane
9a58ee609a Added Postgres 15 to CI 2022-10-14 13:42:04 -07:00
Andrew Kane
66a31bef36 Simplified define [skip ci] 2022-10-10 15:01:16 -07:00
Andrew Kane
163ecdf063 Use define for RandomDouble 2022-10-10 14:59:10 -07:00
Andrew Kane
c9c6b96eed Added support for Postgres 15 [skip ci] 2022-10-05 16:11:37 -07:00
Andrew Kane
48e9a6830b Added link to pgvector-elixir [skip ci] 2022-08-03 23:12:25 -07:00
Andrew Kane
f22b47ca46 Added link to pgvector-php - #30 [skip ci] 2022-08-03 13:50:34 -07:00
Andrew Kane
2a057c055c Updated example [skip ci] 2022-08-01 00:06:45 -07:00
Andrew Kane
b89b58b893 Updated examples to be runnable - fixes #24 [skip ci] 2022-07-31 22:36:46 -07:00
Andrew Kane
2e77650e1d Updated example [skip ci] 2022-07-31 22:34:03 -07:00
Andrew Kane
0a68b040fb DRY code 2022-07-31 21:56:44 -07:00
16 changed files with 103 additions and 50 deletions

View File

@@ -1,6 +1,6 @@
root = true
[*.{c,h,pl}]
[*.{c,h,pl,pm}]
indent_style = tab
indent_size = tab
tab_width = 4

View File

@@ -7,12 +7,12 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
postgres: [14, 13, 12, 11, 10, 9.6]
postgres: [15, 14, 13, 12, 11, 10]
include:
- os: macos-latest
postgres: 14
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: ankane/setup-postgres@v1
with:
postgres-version: ${{ matrix.postgres }}
@@ -33,6 +33,6 @@ jobs:
- if: ${{ startsWith(matrix.os, 'macos') }}
run: |
brew install cpanm && cpanm IPC::Run
wget -q https://github.com/postgres/postgres/archive/refs/tags/REL_14_4.tar.gz
tar xf REL_14_4.tar.gz
make prove_installcheck PROVE=prove PERL5LIB="postgres-REL_14_4/src/test/perl:/Users/runner/perl5/lib/perl5"
wget -q https://github.com/postgres/postgres/archive/refs/tags/REL_14_5.tar.gz
tar xf REL_14_5.tar.gz
make prove_installcheck PROVE=prove PROVE_FLAGS="-I ./postgres-REL_14_5/src/test/perl" PERL5LIB="/Users/runner/perl5/lib/perl5"

View File

@@ -1,3 +1,8 @@
## 0.3.0 (2022-10-15)
- Added support for Postgres 15
- Dropped support for Postgres 9.6
## 0.2.7 (2022-07-31)
- Fixed `unexpected data beyond EOF` error

View File

@@ -1,9 +1,9 @@
FROM postgres:14
FROM postgres:15
COPY . /tmp/pgvector
RUN apt-get update && \
apt-get install -y --no-install-recommends build-essential postgresql-server-dev-14 && \
apt-get install -y --no-install-recommends build-essential postgresql-server-dev-15 && \
cd /tmp/pgvector && \
make clean && \
make OPTFLAGS="" && \
@@ -11,6 +11,6 @@ RUN apt-get update && \
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 remove -y build-essential postgresql-server-dev-15 && \
apt-get autoremove -y && \
rm -rf /var/lib/apt/lists/*

View File

@@ -2,7 +2,7 @@
"name": "vector",
"abstract": "Open-source vector similarity search for Postgres",
"description": "Supports L2 distance, inner product, and cosine distance",
"version": "0.2.7",
"version": "0.3.0",
"maintainer": [
"Andrew Kane <andrew@ankane.org>"
],
@@ -12,7 +12,7 @@
"prereqs": {
"runtime": {
"requires": {
"PostgreSQL": "9.6.0"
"PostgreSQL": "10.0"
}
}
},
@@ -20,7 +20,7 @@
"vector": {
"file": "sql/vector.sql",
"docfile": "README.md",
"version": "0.2.7",
"version": "0.3.0",
"abstract": "Open-source vector similarity search for Postgres"
}
},

View File

@@ -1,5 +1,5 @@
EXTENSION = vector
EXTVERSION = 0.2.7
EXTVERSION = 0.3.0
MODULE_big = vector
DATA = $(wildcard sql/*--*.sql)
@@ -40,6 +40,9 @@ PG_CONFIG ?= pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
# for Postgres 15
PROVE_FLAGS += -I ./test/perl
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),test/t/*.pl)

View File

@@ -3,9 +3,9 @@
Open-source vector similarity search for Postgres
```sql
CREATE TABLE table (column vector(3));
CREATE INDEX ON table USING ivfflat (column vector_l2_ops);
SELECT * FROM table ORDER BY column <-> '[1,2,3]' LIMIT 5;
CREATE TABLE items (embedding vector(3));
CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops);
SELECT * FROM items ORDER BY embedding <-> '[1,2,3]' LIMIT 5;
```
Supports L2 distance, inner product, and cosine distance
@@ -14,10 +14,10 @@ Supports L2 distance, inner product, and cosine distance
## Installation
Compile and install the extension (supports Postgres 9.6+)
Compile and install the extension (supports Postgres 10+)
```sh
git clone --branch v0.2.7 https://github.com/pgvector/pgvector.git
git clone --branch v0.3.0 https://github.com/pgvector/pgvector.git
cd pgvector
make
make install # may need sudo
@@ -33,22 +33,22 @@ You can also install it with [Docker](#docker), [Homebrew](#homebrew), or [PGXN]
## Getting Started
Create a vector column with 3 dimensions (replace `table` and `column` with non-reserved names)
Create a vector column with 3 dimensions
```sql
CREATE TABLE table (column vector(3));
CREATE TABLE items (embedding vector(3));
```
Insert values
```sql
INSERT INTO table VALUES ('[1,2,3]'), ('[4,5,6]');
INSERT INTO items VALUES ('[1,2,3]'), ('[4,5,6]');
```
Get the nearest neighbor by L2 distance
```sql
SELECT * FROM table ORDER BY column <-> '[3,1,2]' LIMIT 1;
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 1;
```
Also supports inner product (`<#>`) and cosine distance (`<=>`)
@@ -62,19 +62,19 @@ Speed up queries with an approximate index. Add an index for each distance funct
L2 distance
```sql
CREATE INDEX ON table USING ivfflat (column vector_l2_ops);
CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops);
```
Inner product
```sql
CREATE INDEX ON table USING ivfflat (column vector_ip_ops);
CREATE INDEX ON items USING ivfflat (embedding vector_ip_ops);
```
Cosine distance
```sql
CREATE INDEX ON table USING ivfflat (column vector_cosine_ops);
CREATE INDEX ON items USING ivfflat (embedding vector_cosine_ops);
```
Indexes should be created after the table has some data for optimal clustering. Also, unlike typical indexes which only affect performance, you may see different results for queries after adding an approximate index.
@@ -84,7 +84,7 @@ Indexes should be created after the table has some data for optimal clustering.
Specify the number of inverted lists (100 by default)
```sql
CREATE INDEX ON table USING ivfflat (column opclass) WITH (lists = 100);
CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 100);
```
A [good place to start](https://github.com/facebookresearch/faiss/issues/112) is `4 * sqrt(rows)`
@@ -131,10 +131,20 @@ Note: `tuples_done` and `tuples_total` are only populated during the `loading tu
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);
SELECT * FROM items WHERE category_id = 123 ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
```
To index many different values of `other_column`, consider [partitioning](https://www.postgresql.org/docs/current/ddl-partitioning.html) on `other_column`.
can be indexed with:
```sql
CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WHERE (category_id = 123);
```
To index many different values of `category_id`, consider [partitioning](https://www.postgresql.org/docs/current/ddl-partitioning.html) on `category_id`.
```sql
CREATE TABLE items (embedding vector(3), category_id int) PARTITION BY LIST(category_id);
```
## Performance
@@ -147,7 +157,7 @@ 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);
CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 1000);
```
## Reference
@@ -185,8 +195,10 @@ Libraries that use pgvector:
- [pgvector-ruby](https://github.com/pgvector/pgvector-ruby) (Ruby)
- [pgvector-node](https://github.com/pgvector/pgvector-node) (Node.js)
- [pgvector-go](https://github.com/pgvector/pgvector-go) (Go)
- [pgvector-php](https://github.com/pgvector/pgvector-php) (PHP)
- [pgvector-rust](https://github.com/pgvector/pgvector-rust) (Rust)
- [pgvector-cpp](https://github.com/pgvector/pgvector-cpp) (C++)
- [pgvector-elixir](https://github.com/pgvector/pgvector-elixir) (Elixir)
## Frequently Asked Questions
@@ -220,7 +232,7 @@ 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.7 https://github.com/pgvector/pgvector.git
git clone --branch v0.3.0 https://github.com/pgvector/pgvector.git
cd pgvector
docker build -t pgvector .
```

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.3.0'" to load this file. \quit

View File

@@ -80,7 +80,11 @@ SampleCallback(Relation index, CALLBACK_ITEM_POINTER, Datum *values,
if (buildstate->rowstoskip <= 0)
{
#if PG_VERSION_NUM >= 150000
int k = (int) (targsamples * sampler_random_fract(&buildstate->rstate.randstate));
#else
int k = (int) (targsamples * sampler_random_fract(buildstate->rstate.randstate));
#endif
Assert(k >= 0 && k < targsamples);
VectorArraySet(samples, k, DatumGetVector(value));
@@ -255,7 +259,7 @@ InsertTuples(Relation index, IvfflatBuildState * buildstate, ForkNumber forkNum)
CHECK_FOR_INTERRUPTS();
buf = IvfflatNewBuffer(index, forkNum);
IvfflatInitPage(index, &buf, &page, &state);
IvfflatInitRegisterPage(index, &buf, &page, &state);
startPage = BufferGetBlockNumber(buf);
@@ -412,7 +416,7 @@ CreateMetaPage(Relation index, int dimensions, int lists, ForkNumber forkNum)
IvfflatMetaPage metap;
buf = IvfflatNewBuffer(index, forkNum);
IvfflatInitPage(index, &buf, &page, &state);
IvfflatInitRegisterPage(index, &buf, &page, &state);
/* Set metapage data */
metap = IvfflatPageGetMeta(page);
@@ -445,7 +449,7 @@ CreateListPages(Relation index, VectorArray centers, int dimensions,
list = palloc(itemsz);
buf = IvfflatNewBuffer(index, forkNum);
IvfflatInitPage(index, &buf, &page, &state);
IvfflatInitRegisterPage(index, &buf, &page, &state);
for (i = 0; i < lists; i++)
{

View File

@@ -14,8 +14,8 @@
#include "portability/instr_time.h"
#endif
#if PG_VERSION_NUM < 90600
#error "Requires PostgreSQL 9.6+"
#if PG_VERSION_NUM < 100000
#error "Requires PostgreSQL 10+"
#endif
/* Support functions */
@@ -208,7 +208,8 @@ void IvfflatUpdateList(Relation index, GenericXLogState *state, ListInfo listIn
void IvfflatCommitBuffer(Buffer buf, GenericXLogState *state);
void IvfflatAppendPage(Relation index, Buffer *buf, Page *page, GenericXLogState **state, ForkNumber forkNum);
Buffer IvfflatNewBuffer(Relation index, ForkNumber forkNum);
void IvfflatInitPage(Relation index, Buffer *buf, Page *page, GenericXLogState **state);
void IvfflatInitPage(Buffer buf, Page page);
void IvfflatInitRegisterPage(Relation index, Buffer *buf, Page *page, GenericXLogState **state);
/* Index access methods */
IndexBuildResult *ivfflatbuild(Relation heap, Relation index, IndexInfo *indexInfo);

View File

@@ -107,9 +107,7 @@ InsertTuple(Relation rel, IndexTuple itup, Relation heapRel, Datum *values)
IvfflatPageGetOpaque(page)->nextblkno = insertPage;
/* Init page */
PageInit(newpage, BufferGetPageSize(newbuf), sizeof(IvfflatPageOpaqueData));
IvfflatPageGetOpaque(newpage)->nextblkno = InvalidBlockNumber;
IvfflatPageGetOpaque(newpage)->page_id = IVFFLAT_PAGE_ID;
IvfflatInitPage(newbuf, newpage);
/* Commit */
MarkBufferDirty(buf);

View File

@@ -5,6 +5,16 @@
#include "ivfflat.h"
#include "miscadmin.h"
#if PG_VERSION_NUM >= 150000
#include "common/pg_prng.h"
#endif
#if PG_VERSION_NUM >= 150000
#define RandomDouble() pg_prng_double(&pg_global_prng_state)
#else
#define RandomDouble() (((double) random()) / MAX_RANDOM_VALUE)
#endif
/*
* Initialize with kmeans++
*
@@ -66,7 +76,7 @@ InitCenters(Relation index, VectorArray samples, VectorArray centers, float *low
break;
/* Choose new center using weighted probability distribution. */
choice = sum * (((double) random()) / MAX_RANDOM_VALUE);
choice = sum * RandomDouble();
for (j = 0; j < numSamples - 1; j++)
{
choice -= weight[j];
@@ -145,7 +155,7 @@ QuickCenters(Relation index, VectorArray samples, VectorArray centers)
vec->dim = dimensions;
for (j = 0; j < dimensions; j++)
vec->x[j] = ((double) random()) / MAX_RANDOM_VALUE;
vec->x[j] = RandomDouble();
/* Normalize if needed (only needed for random centers) */
if (normprocinfo != NULL)
@@ -403,7 +413,7 @@ ElkanKmeans(Relation index, VectorArray samples, VectorArray centers)
{
/* TODO Handle empty centers properly */
for (k = 0; k < dimensions; k++)
vec->x[k] = ((double) random()) / MAX_RANDOM_VALUE;
vec->x[k] = RandomDouble();
}
/* Normalize if needed */

View File

@@ -107,13 +107,22 @@ IvfflatNewBuffer(Relation index, ForkNumber forkNum)
* Init page
*/
void
IvfflatInitPage(Relation index, Buffer *buf, Page *page, GenericXLogState **state)
IvfflatInitPage(Buffer buf, Page page)
{
PageInit(page, BufferGetPageSize(buf), sizeof(IvfflatPageOpaqueData));
IvfflatPageGetOpaque(page)->nextblkno = InvalidBlockNumber;
IvfflatPageGetOpaque(page)->page_id = IVFFLAT_PAGE_ID;
}
/*
* Init and register page
*/
void
IvfflatInitRegisterPage(Relation index, Buffer *buf, Page *page, GenericXLogState **state)
{
*state = GenericXLogStart(index);
*page = GenericXLogRegisterBuffer(*state, *buf, GENERIC_XLOG_FULL_IMAGE);
PageInit(*page, BufferGetPageSize(*buf), sizeof(IvfflatPageOpaqueData));
IvfflatPageGetOpaque(*page)->nextblkno = InvalidBlockNumber;
IvfflatPageGetOpaque(*page)->page_id = IVFFLAT_PAGE_ID;
IvfflatInitPage(*buf, *page);
}
/*
@@ -143,9 +152,7 @@ IvfflatAppendPage(Relation index, Buffer *buf, Page *page, GenericXLogState **st
IvfflatPageGetOpaque(*page)->nextblkno = BufferGetBlockNumber(newbuf);
/* Init new page */
PageInit(newpage, BufferGetPageSize(newbuf), sizeof(IvfflatPageOpaqueData));
IvfflatPageGetOpaque(newpage)->nextblkno = InvalidBlockNumber;
IvfflatPageGetOpaque(newpage)->page_id = IVFFLAT_PAGE_ID;
IvfflatInitPage(newbuf, newpage);
/* Commit */
MarkBufferDirty(*buf);

View File

@@ -0,0 +1,8 @@
use PostgreSQL::Test::Cluster;
sub get_new_node
{
return PostgreSQL::Test::Cluster->new(@_);
}
1;

3
test/perl/TestLib.pm Normal file
View File

@@ -0,0 +1,3 @@
use PostgreSQL::Test::Utils;
1;

View File

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