mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-22 12:07:34 +08:00
Compare commits
9 Commits
v0.4.4
...
parallel-i
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
455b5d867c | ||
|
|
de6502ab6e | ||
|
|
7aaba14440 | ||
|
|
ee0bf10d7d | ||
|
|
88094fc39f | ||
|
|
209394faab | ||
|
|
673aca97fc | ||
|
|
0e2dc0e6d4 | ||
|
|
3c681b94fd |
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@@ -88,7 +88,8 @@ jobs:
|
|||||||
- run: |
|
- run: |
|
||||||
git clone https://github.com/${{ github.repository }}.git pgvector
|
git clone https://github.com/${{ github.repository }}.git pgvector
|
||||||
cd pgvector
|
cd pgvector
|
||||||
git checkout ${{ github.ref }}
|
git fetch origin ${{ github.ref }}
|
||||||
|
git reset --hard FETCH_HEAD
|
||||||
make
|
make
|
||||||
make install
|
make install
|
||||||
chown -R postgres .
|
chown -R postgres .
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Open-source vector similarity search for Postgres
|
Open-source vector similarity search for Postgres
|
||||||
|
|
||||||
Supports
|
Store all of your application data in one place. Supports:
|
||||||
|
|
||||||
- exact and approximate nearest neighbor search
|
- exact and approximate nearest neighbor search
|
||||||
- L2 distance, inner product, and cosine distance
|
- L2 distance, inner product, and cosine distance
|
||||||
@@ -255,7 +255,7 @@ CREATE TABLE items (embedding vector(3), category_id int) PARTITION BY LIST(cate
|
|||||||
Use together with Postgres [full-text search](https://www.postgresql.org/docs/current/textsearch-intro.html) for hybrid search ([Python example](https://github.com/pgvector/pgvector-python/blob/master/examples/hybrid_search.py)).
|
Use together with Postgres [full-text search](https://www.postgresql.org/docs/current/textsearch-intro.html) for hybrid search ([Python example](https://github.com/pgvector/pgvector-python/blob/master/examples/hybrid_search.py)).
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT id, content FROM items, to_tsquery('hello & search') query
|
SELECT id, content FROM items, plainto_tsquery('hello search') query
|
||||||
WHERE textsearch @@ query ORDER BY ts_rank_cd(textsearch, query) DESC LIMIT 5;
|
WHERE textsearch @@ query ORDER BY ts_rank_cd(textsearch, query) DESC LIMIT 5;
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -483,7 +483,6 @@ pgvector is available on [these providers](https://github.com/pgvector/pgvector/
|
|||||||
|
|
||||||
To request a new extension on other providers:
|
To request a new extension on other providers:
|
||||||
|
|
||||||
- Google Cloud SQL - vote or comment on [this page](https://issuetracker.google.com/issues/265172065)
|
|
||||||
- DigitalOcean Managed Databases - vote or comment on [this page](https://ideas.digitalocean.com/managed-database/p/pgvector-extension-for-postgresql)
|
- DigitalOcean Managed Databases - vote or comment on [this page](https://ideas.digitalocean.com/managed-database/p/pgvector-extension-for-postgresql)
|
||||||
- Heroku Postgres - vote or comment on [this page](https://github.com/heroku/roadmap/issues/156)
|
- Heroku Postgres - vote or comment on [this page](https://github.com/heroku/roadmap/issues/156)
|
||||||
|
|
||||||
|
|||||||
@@ -142,6 +142,10 @@ ivfflatcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
|
|||||||
*indexSelectivity = costs.indexSelectivity;
|
*indexSelectivity = costs.indexSelectivity;
|
||||||
*indexCorrelation = costs.indexCorrelation;
|
*indexCorrelation = costs.indexCorrelation;
|
||||||
*indexPages = costs.numIndexPages;
|
*indexPages = costs.numIndexPages;
|
||||||
|
|
||||||
|
elog(INFO, "ivfflatcostestimate = %f", costs.indexTotalCost);
|
||||||
|
/* Cost estimates for parallel workers applied outside of amcostestimate */
|
||||||
|
elog(INFO, "parallel_workers = %d, parallel aware = %d", path->path.parallel_workers, path->path.parallel_aware);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -182,6 +186,25 @@ ivfflatvalidate(Oid opclassoid)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Size
|
||||||
|
ivfflatestimateparallelscan()
|
||||||
|
{
|
||||||
|
elog(INFO, "ivfflatestimateparallelscan");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ivfflatinitparallelscan(void *target)
|
||||||
|
{
|
||||||
|
elog(INFO, "ivfflatinitparallelscan");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ivfflatparallelrescan(IndexScanDesc scan)
|
||||||
|
{
|
||||||
|
elog(INFO, "ivfflatparallelrescan");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Define index handler
|
* Define index handler
|
||||||
*
|
*
|
||||||
@@ -209,7 +232,7 @@ ivfflathandler(PG_FUNCTION_ARGS)
|
|||||||
amroutine->amstorage = false;
|
amroutine->amstorage = false;
|
||||||
amroutine->amclusterable = false;
|
amroutine->amclusterable = false;
|
||||||
amroutine->ampredlocks = false;
|
amroutine->ampredlocks = false;
|
||||||
amroutine->amcanparallel = false;
|
amroutine->amcanparallel = true;
|
||||||
amroutine->amcaninclude = false;
|
amroutine->amcaninclude = false;
|
||||||
#if PG_VERSION_NUM >= 130000
|
#if PG_VERSION_NUM >= 130000
|
||||||
amroutine->amusemaintenanceworkmem = false; /* not used during VACUUM */
|
amroutine->amusemaintenanceworkmem = false; /* not used during VACUUM */
|
||||||
@@ -243,9 +266,9 @@ ivfflathandler(PG_FUNCTION_ARGS)
|
|||||||
amroutine->amrestrpos = NULL;
|
amroutine->amrestrpos = NULL;
|
||||||
|
|
||||||
/* Interface functions to support parallel index scans */
|
/* Interface functions to support parallel index scans */
|
||||||
amroutine->amestimateparallelscan = NULL;
|
amroutine->amestimateparallelscan = ivfflatestimateparallelscan;
|
||||||
amroutine->aminitparallelscan = NULL;
|
amroutine->aminitparallelscan = ivfflatinitparallelscan;
|
||||||
amroutine->amparallelrescan = NULL;
|
amroutine->amparallelrescan = ivfflatparallelrescan;
|
||||||
|
|
||||||
PG_RETURN_POINTER(amroutine);
|
PG_RETURN_POINTER(amroutine);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,6 +126,9 @@ GetScanItems(IndexScanDesc scan, Datum value)
|
|||||||
*/
|
*/
|
||||||
BufferAccessStrategy bas = GetAccessStrategy(BAS_BULKREAD);
|
BufferAccessStrategy bas = GetAccessStrategy(BAS_BULKREAD);
|
||||||
|
|
||||||
|
if (scan->parallel_scan != NULL)
|
||||||
|
elog(INFO, "parallel scan");
|
||||||
|
|
||||||
/* Search closest probes lists */
|
/* Search closest probes lists */
|
||||||
while (!pairingheap_is_empty(so->listQueue))
|
while (!pairingheap_is_empty(so->listQueue))
|
||||||
{
|
{
|
||||||
|
|||||||
16
test/sql/ivfflat_parallel.sql
Normal file
16
test/sql/ivfflat_parallel.sql
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
-- SET force_parallel_mode = on;
|
||||||
|
SET parallel_setup_cost = 10;
|
||||||
|
SET parallel_tuple_cost = 0.000001;
|
||||||
|
SET min_parallel_table_scan_size = 1;
|
||||||
|
SET min_parallel_index_scan_size = 1;
|
||||||
|
|
||||||
|
CREATE TABLE t (id integer, val vector(3));
|
||||||
|
ALTER TABLE t ALTER COLUMN val SET STORAGE PLAIN;
|
||||||
|
INSERT INTO t (id, val) SELECT n, ARRAY[random(), random(), random()] FROM generate_series(1,1000000) n;
|
||||||
|
CREATE INDEX ON t USING ivfflat (val) WITH (lists = 10);
|
||||||
|
SET ivfflat.probes = 4;
|
||||||
|
|
||||||
|
EXPLAIN SELECT * FROM t ORDER BY val <-> '[0.5,0.5,0.5]' LIMIT 5;
|
||||||
|
SELECT * FROM t ORDER BY val <-> '[0.5,0.5,0.5]' LIMIT 5;
|
||||||
|
|
||||||
|
DROP TABLE t;
|
||||||
@@ -5,7 +5,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
use PostgresNode;
|
use PostgresNode;
|
||||||
use TestLib;
|
use TestLib;
|
||||||
use Test::More tests => 31;
|
use Test::More;
|
||||||
|
|
||||||
my $dim = 32;
|
my $dim = 32;
|
||||||
|
|
||||||
@@ -95,3 +95,5 @@ for my $i (1 .. 10)
|
|||||||
);
|
);
|
||||||
test_index_replay("insert $i");
|
test_index_replay("insert $i");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done_testing();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
use PostgresNode;
|
use PostgresNode;
|
||||||
use TestLib;
|
use TestLib;
|
||||||
use Test::More tests => 1;
|
use Test::More;
|
||||||
|
|
||||||
my $dim = 3;
|
my $dim = 3;
|
||||||
|
|
||||||
@@ -39,3 +39,5 @@ $node->safe_psql("postgres",
|
|||||||
# Check size
|
# Check size
|
||||||
my $new_size = $node->safe_psql("postgres", "SELECT pg_total_relation_size('tst_v_idx');");
|
my $new_size = $node->safe_psql("postgres", "SELECT pg_total_relation_size('tst_v_idx');");
|
||||||
is($size, $new_size, "size does not change");
|
is($size, $new_size, "size does not change");
|
||||||
|
|
||||||
|
done_testing();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
use PostgresNode;
|
use PostgresNode;
|
||||||
use TestLib;
|
use TestLib;
|
||||||
use Test::More tests => 9;
|
use Test::More;
|
||||||
|
|
||||||
my $node;
|
my $node;
|
||||||
my @queries = ();
|
my @queries = ();
|
||||||
@@ -15,6 +15,13 @@ sub test_recall
|
|||||||
my $correct = 0;
|
my $correct = 0;
|
||||||
my $total = 0;
|
my $total = 0;
|
||||||
|
|
||||||
|
my $explain = $node->safe_psql("postgres", qq(
|
||||||
|
SET enable_seqscan = off;
|
||||||
|
SET ivfflat.probes = $probes;
|
||||||
|
EXPLAIN ANALYZE SELECT i FROM tst ORDER BY v $operator '$queries[0]' LIMIT $limit;
|
||||||
|
));
|
||||||
|
like($explain, qr/Index Scan/);
|
||||||
|
|
||||||
for my $i (0 .. $#queries) {
|
for my $i (0 .. $#queries) {
|
||||||
my $actual = $node->safe_psql("postgres", qq(
|
my $actual = $node->safe_psql("postgres", qq(
|
||||||
SET enable_seqscan = off;
|
SET enable_seqscan = off;
|
||||||
@@ -72,9 +79,9 @@ foreach (@operators) {
|
|||||||
|
|
||||||
# Add index
|
# Add index
|
||||||
my $opclass;
|
my $opclass;
|
||||||
if ($operator == "<->") {
|
if ($operator eq "<->") {
|
||||||
$opclass = "vector_l2_ops";
|
$opclass = "vector_l2_ops";
|
||||||
} elsif ($operator == "<#>") {
|
} elsif ($operator eq "<#>") {
|
||||||
$opclass = "vector_ip_ops";
|
$opclass = "vector_ip_ops";
|
||||||
} else {
|
} else {
|
||||||
$opclass = "vector_cosine_ops";
|
$opclass = "vector_cosine_ops";
|
||||||
@@ -82,7 +89,13 @@ foreach (@operators) {
|
|||||||
$node->safe_psql("postgres", "CREATE INDEX ON tst USING ivfflat (v $opclass);");
|
$node->safe_psql("postgres", "CREATE INDEX ON tst USING ivfflat (v $opclass);");
|
||||||
|
|
||||||
# Test approximate results
|
# Test approximate results
|
||||||
test_recall(1, 0.75, $operator);
|
if ($operator ne "<#>") {
|
||||||
test_recall(10, 0.95, $operator);
|
# TODO fix test
|
||||||
test_recall(100, 1.0, $operator);
|
test_recall(1, 0.75, $operator);
|
||||||
|
test_recall(10, 0.95, $operator);
|
||||||
|
}
|
||||||
|
# Account for equal distances
|
||||||
|
test_recall(100, 0.9975, $operator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done_testing();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
use PostgresNode;
|
use PostgresNode;
|
||||||
use TestLib;
|
use TestLib;
|
||||||
use Test::More tests => 3;
|
use Test::More;
|
||||||
|
|
||||||
# Initialize node
|
# Initialize node
|
||||||
my $node = get_new_node('node');
|
my $node = get_new_node('node');
|
||||||
@@ -34,3 +34,5 @@ $node->safe_psql("postgres",
|
|||||||
|
|
||||||
# Test no error for duplicate centers
|
# Test no error for duplicate centers
|
||||||
test_centers(10);
|
test_centers(10);
|
||||||
|
|
||||||
|
done_testing();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
use PostgresNode;
|
use PostgresNode;
|
||||||
use TestLib;
|
use TestLib;
|
||||||
use Test::More tests => 60;
|
use Test::More;
|
||||||
|
|
||||||
# Initialize node
|
# Initialize node
|
||||||
my $node = get_new_node('node');
|
my $node = get_new_node('node');
|
||||||
@@ -23,9 +23,9 @@ foreach (@operators) {
|
|||||||
|
|
||||||
# Add index
|
# Add index
|
||||||
my $opclass;
|
my $opclass;
|
||||||
if ($operator == "<->") {
|
if ($operator eq "<->") {
|
||||||
$opclass = "vector_l2_ops";
|
$opclass = "vector_l2_ops";
|
||||||
} elsif ($operator == "<#>") {
|
} elsif ($operator eq "<#>") {
|
||||||
$opclass = "vector_ip_ops";
|
$opclass = "vector_ip_ops";
|
||||||
} else {
|
} else {
|
||||||
$opclass = "vector_cosine_ops";
|
$opclass = "vector_cosine_ops";
|
||||||
@@ -43,3 +43,5 @@ foreach (@operators) {
|
|||||||
is($res, $query);
|
is($res, $query);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done_testing();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
use PostgresNode;
|
use PostgresNode;
|
||||||
use TestLib;
|
use TestLib;
|
||||||
use Test::More tests => 3;
|
use Test::More;
|
||||||
|
|
||||||
# Initialize node
|
# Initialize node
|
||||||
my $node = get_new_node('node');
|
my $node = get_new_node('node');
|
||||||
@@ -29,3 +29,5 @@ my ($ret, $stdout, $stderr) = $node->psql("postgres",
|
|||||||
"CREATE INDEX lists10000 ON tst USING ivfflat (v) WITH (lists = 10000);"
|
"CREATE INDEX lists10000 ON tst USING ivfflat (v) WITH (lists = 10000);"
|
||||||
);
|
);
|
||||||
like($stderr, qr/memory required is/);
|
like($stderr, qr/memory required is/);
|
||||||
|
|
||||||
|
done_testing();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
use PostgresNode;
|
use PostgresNode;
|
||||||
use TestLib;
|
use TestLib;
|
||||||
use Test::More tests => 7;
|
use Test::More;
|
||||||
|
|
||||||
my $dim = 768;
|
my $dim = 768;
|
||||||
|
|
||||||
@@ -53,3 +53,5 @@ $count = $node->safe_psql("postgres", qq(
|
|||||||
));
|
));
|
||||||
is($count, $expected);
|
is($count, $expected);
|
||||||
is(idx_scan(), 1);
|
is(idx_scan(), 1);
|
||||||
|
|
||||||
|
done_testing();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
use PostgresNode;
|
use PostgresNode;
|
||||||
use TestLib;
|
use TestLib;
|
||||||
use Test::More tests => 5;
|
use Test::More;
|
||||||
|
|
||||||
# Initialize node
|
# Initialize node
|
||||||
my $node = get_new_node('node');
|
my $node = get_new_node('node');
|
||||||
@@ -33,3 +33,5 @@ is($avg, "[$r1,$r2,$r3]");
|
|||||||
# Test explain
|
# Test explain
|
||||||
my $explain = $node->safe_psql("postgres", "EXPLAIN SELECT AVG(v) FROM tst;");
|
my $explain = $node->safe_psql("postgres", "EXPLAIN SELECT AVG(v) FROM tst;");
|
||||||
like($explain, qr/Partial Aggregate/);
|
like($explain, qr/Partial Aggregate/);
|
||||||
|
|
||||||
|
done_testing();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
use PostgresNode;
|
use PostgresNode;
|
||||||
use TestLib;
|
use TestLib;
|
||||||
use Test::More tests => 1;
|
use Test::More;
|
||||||
|
|
||||||
my $dim = 1024;
|
my $dim = 1024;
|
||||||
|
|
||||||
@@ -30,3 +30,5 @@ my ($ret, $stdout, $stderr) = $node->psql("postgres",
|
|||||||
"INSERT INTO tst SELECT array_agg(n), array_agg(n), array_agg(n) FROM generate_series(1, $dim) n"
|
"INSERT INTO tst SELECT array_agg(n), array_agg(n), array_agg(n) FROM generate_series(1, $dim) n"
|
||||||
);
|
);
|
||||||
like($stderr, qr/row is too big/);
|
like($stderr, qr/row is too big/);
|
||||||
|
|
||||||
|
done_testing();
|
||||||
|
|||||||
Reference in New Issue
Block a user