mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-22 03:57:34 +08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
434dc904c1 | ||
|
|
92a671eeb1 | ||
|
|
94eeb83abe | ||
|
|
6866939090 | ||
|
|
ba2fb6ad8c | ||
|
|
51fe8aff02 | ||
|
|
df3dc151d5 | ||
|
|
6687430589 | ||
|
|
f128a455d1 | ||
|
|
56cb5f3503 |
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@@ -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_1.tar.gz
|
||||
tar xf REL_14_1.tar.gz
|
||||
make prove_installcheck PROVE=prove PERL5LIB=postgres-REL_14_1/src/test/perl
|
||||
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"
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
## 0.2.6 (unreleased)
|
||||
## 0.2.7 (2022-07-31)
|
||||
|
||||
- Fixed `unexpected data beyond EOF` error
|
||||
|
||||
## 0.2.6 (2022-05-22)
|
||||
|
||||
- Improved performance of index creation for Postgres < 12
|
||||
|
||||
|
||||
@@ -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.5",
|
||||
"version": "0.2.7",
|
||||
"maintainer": [
|
||||
"Andrew Kane <andrew@ankane.org>"
|
||||
],
|
||||
@@ -20,7 +20,7 @@
|
||||
"vector": {
|
||||
"file": "sql/vector.sql",
|
||||
"docfile": "README.md",
|
||||
"version": "0.2.5",
|
||||
"version": "0.2.7",
|
||||
"abstract": "Open-source vector similarity search for Postgres"
|
||||
}
|
||||
},
|
||||
|
||||
2
Makefile
2
Makefile
@@ -1,5 +1,5 @@
|
||||
EXTENSION = vector
|
||||
EXTVERSION = 0.2.5
|
||||
EXTVERSION = 0.2.7
|
||||
|
||||
MODULE_big = vector
|
||||
DATA = $(wildcard sql/*--*.sql)
|
||||
|
||||
@@ -17,7 +17,7 @@ Supports L2 distance, inner product, and cosine distance
|
||||
Compile and install the extension (supports Postgres 9.6+)
|
||||
|
||||
```sh
|
||||
git clone --branch v0.2.5 https://github.com/pgvector/pgvector.git
|
||||
git clone --branch v0.2.7 https://github.com/pgvector/pgvector.git
|
||||
cd pgvector
|
||||
make
|
||||
make install # may need sudo
|
||||
@@ -220,14 +220,14 @@ 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.5 https://github.com/pgvector/pgvector.git
|
||||
git clone --branch v0.2.7 https://github.com/pgvector/pgvector.git
|
||||
cd pgvector
|
||||
docker build -t pgvector .
|
||||
```
|
||||
|
||||
### Homebrew
|
||||
|
||||
On Mac with Homebrew Postgres, you can use:
|
||||
With Homebrew Postgres, you can use:
|
||||
|
||||
```sh
|
||||
brew install pgvector/brew/pgvector
|
||||
|
||||
2
sql/vector--0.2.5--0.2.6.sql
Normal file
2
sql/vector--0.2.5--0.2.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.2.6'" to load this file. \quit
|
||||
2
sql/vector--0.2.6--0.2.7.sql
Normal file
2
sql/vector--0.2.6--0.2.7.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.7'" to load this file. \quit
|
||||
@@ -53,18 +53,6 @@ FindInsertPage(Relation rel, Datum *values, BlockNumber *insertPage, ListInfo *
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare to insert an index tuple
|
||||
*/
|
||||
static void
|
||||
LoadInsertPage(Relation index, Buffer *buf, Page *page, GenericXLogState **state, BlockNumber insertPage)
|
||||
{
|
||||
*buf = ReadBuffer(index, insertPage);
|
||||
LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);
|
||||
*state = GenericXLogStart(index);
|
||||
*page = GenericXLogRegisterBuffer(*state, *buf, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a tuple into the index
|
||||
*/
|
||||
@@ -87,11 +75,18 @@ InsertTuple(Relation rel, IndexTuple itup, Relation heapRel, Datum *values)
|
||||
itemsz = MAXALIGN(IndexTupleSize(itup));
|
||||
Assert(itemsz <= BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - MAXALIGN(sizeof(IvfflatPageOpaqueData)));
|
||||
|
||||
LoadInsertPage(rel, &buf, &page, &state, insertPage);
|
||||
|
||||
/* Find a page to insert the item */
|
||||
while (PageGetFreeSpace(page) < itemsz)
|
||||
for (;;)
|
||||
{
|
||||
buf = ReadBuffer(rel, insertPage);
|
||||
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
|
||||
|
||||
state = GenericXLogStart(rel);
|
||||
page = GenericXLogRegisterBuffer(state, buf, 0);
|
||||
|
||||
if (PageGetFreeSpace(page) >= itemsz)
|
||||
break;
|
||||
|
||||
insertPage = IvfflatPageGetOpaque(page)->nextblkno;
|
||||
|
||||
if (BlockNumberIsValid(insertPage))
|
||||
@@ -99,15 +94,31 @@ InsertTuple(Relation rel, IndexTuple itup, Relation heapRel, Datum *values)
|
||||
/* Move to next page */
|
||||
GenericXLogAbort(state);
|
||||
UnlockReleaseBuffer(buf);
|
||||
|
||||
LoadInsertPage(rel, &buf, &page, &state, insertPage);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Add a new page */
|
||||
IvfflatAppendPage(rel, &buf, &page, &state, MAIN_FORKNUM);
|
||||
Buffer newbuf = IvfflatNewBuffer(rel, MAIN_FORKNUM);
|
||||
Page newpage = GenericXLogRegisterBuffer(state, buf, GENERIC_XLOG_FULL_IMAGE);
|
||||
|
||||
insertPage = BufferGetBlockNumber(buf);
|
||||
insertPage = BufferGetBlockNumber(newbuf);
|
||||
|
||||
/* Update previous buffer */
|
||||
IvfflatPageGetOpaque(page)->nextblkno = insertPage;
|
||||
|
||||
/* Init page */
|
||||
PageInit(newpage, BufferGetPageSize(newbuf), sizeof(IvfflatPageOpaqueData));
|
||||
IvfflatPageGetOpaque(newpage)->nextblkno = InvalidBlockNumber;
|
||||
IvfflatPageGetOpaque(newpage)->page_id = IVFFLAT_PAGE_ID;
|
||||
|
||||
/* Commit */
|
||||
MarkBufferDirty(buf);
|
||||
MarkBufferDirty(newbuf);
|
||||
GenericXLogFinish(state);
|
||||
|
||||
/* Unlock */
|
||||
UnlockReleaseBuffer(buf);
|
||||
UnlockReleaseBuffer(newbuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -135,17 +135,29 @@ IvfflatCommitBuffer(Buffer buf, GenericXLogState *state)
|
||||
void
|
||||
IvfflatAppendPage(Relation index, Buffer *buf, Page *page, GenericXLogState **state, ForkNumber forkNum)
|
||||
{
|
||||
Buffer prevbuf = *buf;
|
||||
|
||||
/* Get new buffer */
|
||||
*buf = IvfflatNewBuffer(index, forkNum);
|
||||
Buffer newbuf = IvfflatNewBuffer(index, forkNum);
|
||||
Page newpage = GenericXLogRegisterBuffer(*state, newbuf, GENERIC_XLOG_FULL_IMAGE);
|
||||
|
||||
/* Update and commit previous buffer */
|
||||
IvfflatPageGetOpaque(*page)->nextblkno = BufferGetBlockNumber(*buf);
|
||||
IvfflatCommitBuffer(prevbuf, *state);
|
||||
/* Update the previous buffer */
|
||||
IvfflatPageGetOpaque(*page)->nextblkno = BufferGetBlockNumber(newbuf);
|
||||
|
||||
/* Init new page */
|
||||
IvfflatInitPage(index, buf, page, state);
|
||||
PageInit(newpage, BufferGetPageSize(newbuf), sizeof(IvfflatPageOpaqueData));
|
||||
IvfflatPageGetOpaque(newpage)->nextblkno = InvalidBlockNumber;
|
||||
IvfflatPageGetOpaque(newpage)->page_id = IVFFLAT_PAGE_ID;
|
||||
|
||||
/* Commit */
|
||||
MarkBufferDirty(*buf);
|
||||
MarkBufferDirty(newbuf);
|
||||
GenericXLogFinish(*state);
|
||||
|
||||
/* Unlock */
|
||||
UnlockReleaseBuffer(*buf);
|
||||
|
||||
*state = GenericXLogStart(index);
|
||||
*page = GenericXLogRegisterBuffer(*state, newbuf, GENERIC_XLOG_FULL_IMAGE);
|
||||
*buf = newbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -7,6 +7,8 @@ use PostgresNode;
|
||||
use TestLib;
|
||||
use Test::More tests => 31;
|
||||
|
||||
my $dim = 32;
|
||||
|
||||
my $node_primary;
|
||||
my $node_replica;
|
||||
|
||||
@@ -30,13 +32,15 @@ sub test_index_replay
|
||||
$node_primary->poll_query_until('postgres', $caughtup_query)
|
||||
or die "Timed out while waiting for replica 1 to catch up";
|
||||
|
||||
my $r1 = rand();
|
||||
my $r2 = rand();
|
||||
my $r3 = rand();
|
||||
my @r = ();
|
||||
for (1 .. $dim) {
|
||||
push(@r, rand());
|
||||
}
|
||||
my $sql = join(",", @r);
|
||||
|
||||
my $queries = qq(
|
||||
SET enable_seqscan = off;
|
||||
SELECT * FROM tst ORDER BY v <-> '[$r1,$r2,$r3]' LIMIT 10;
|
||||
SELECT * FROM tst ORDER BY v <-> '[$sql]' LIMIT 10;
|
||||
);
|
||||
|
||||
# Run test queries and compare their result
|
||||
@@ -50,6 +54,10 @@ sub test_index_replay
|
||||
# Initialize primary node
|
||||
$node_primary = get_new_node('primary');
|
||||
$node_primary->init(allows_streaming => 1);
|
||||
if ($dim > 32) {
|
||||
# TODO use wal_keep_segments for Postgres < 13
|
||||
$node_primary->append_conf('postgresql.conf', qq(wal_keep_size = 1GB));
|
||||
}
|
||||
$node_primary->start;
|
||||
my $backup_name = 'my_backup';
|
||||
|
||||
@@ -64,9 +72,9 @@ $node_replica->start;
|
||||
|
||||
# Create ivfflat index on primary
|
||||
$node_primary->safe_psql("postgres", "CREATE EXTENSION vector;");
|
||||
$node_primary->safe_psql("postgres", "CREATE TABLE tst (i int4, v vector(3));");
|
||||
$node_primary->safe_psql("postgres", "CREATE TABLE tst (i int4, v vector($dim));");
|
||||
$node_primary->safe_psql("postgres",
|
||||
"INSERT INTO tst SELECT i % 10, ARRAY[random(), random(), random()] FROM generate_series(1, 100000) i;"
|
||||
"INSERT INTO tst SELECT i % 10, (SELECT array_agg(random()) FROM generate_series(1, $dim)) FROM generate_series(1, 100000) i;"
|
||||
);
|
||||
$node_primary->safe_psql("postgres", "CREATE INDEX ON tst USING ivfflat (v);");
|
||||
|
||||
@@ -82,7 +90,7 @@ for my $i (1 .. 10)
|
||||
test_index_replay("vacuum $i");
|
||||
my ($start, $end) = (100001 + ($i - 1) * 10000, 100000 + $i * 10000);
|
||||
$node_primary->safe_psql("postgres",
|
||||
"INSERT INTO tst SELECT i % 10, ARRAY[random(), random(), random()] FROM generate_series($start, $end) i;"
|
||||
"INSERT INTO tst SELECT i % 10, (SELECT array_agg(random()) FROM generate_series(1, $dim)) FROM generate_series($start, $end) i;"
|
||||
);
|
||||
test_index_replay("insert $i");
|
||||
}
|
||||
|
||||
33
test/t/007_inserts.pl
Normal file
33
test/t/007_inserts.pl
Normal file
@@ -0,0 +1,33 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
use PostgresNode;
|
||||
use TestLib;
|
||||
use Test::More tests => 3;
|
||||
|
||||
# Initialize node
|
||||
my $node = get_new_node('node');
|
||||
$node->init;
|
||||
$node->start;
|
||||
|
||||
# Create table and index
|
||||
$node->safe_psql("postgres", "CREATE EXTENSION vector;");
|
||||
$node->safe_psql("postgres", "CREATE TABLE tst (v vector(768));");
|
||||
$node->safe_psql("postgres",
|
||||
"INSERT INTO tst SELECT (SELECT array_agg(random()) FROM generate_series(1, 768)) FROM generate_series(1, 10000) i;"
|
||||
);
|
||||
$node->safe_psql("postgres", "CREATE INDEX ON tst USING ivfflat (v);");
|
||||
|
||||
$node->pgbench(
|
||||
"--no-vacuum --client=5 --transactions=100",
|
||||
0,
|
||||
[qr{actually processed}],
|
||||
[qr{^$}],
|
||||
"concurrent INSERTs",
|
||||
{
|
||||
"007_concurrent" => q(
|
||||
BEGIN;
|
||||
INSERT INTO tst SELECT (SELECT array_agg(random()) FROM generate_series(1, 768)) FROM generate_series(1, 10) i;
|
||||
COMMIT;
|
||||
),
|
||||
}
|
||||
);
|
||||
@@ -1,4 +1,4 @@
|
||||
comment = 'vector data type and ivfflat access method'
|
||||
default_version = '0.2.5'
|
||||
default_version = '0.2.7'
|
||||
module_pathname = '$libdir/vector'
|
||||
relocatable = true
|
||||
|
||||
Reference in New Issue
Block a user