mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-11 23:26:55 +08:00
Started half indexing
This commit is contained in:
@@ -75,3 +75,8 @@ CREATE OPERATOR <=> (
|
|||||||
LEFTARG = half[], RIGHTARG = half[], PROCEDURE = cosine_distance,
|
LEFTARG = half[], RIGHTARG = half[], PROCEDURE = cosine_distance,
|
||||||
COMMUTATOR = '<=>'
|
COMMUTATOR = '<=>'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE OPERATOR CLASS half_l2_ops
|
||||||
|
FOR TYPE half[] USING hnsw AS
|
||||||
|
OPERATOR 1 <-> (half[], half[]) FOR ORDER BY float_ops,
|
||||||
|
FUNCTION 1 half_l2_squared_distance(half[], half[]);
|
||||||
|
|||||||
@@ -377,3 +377,10 @@ CREATE OPERATOR <=> (
|
|||||||
LEFTARG = half[], RIGHTARG = half[], PROCEDURE = cosine_distance,
|
LEFTARG = half[], RIGHTARG = half[], PROCEDURE = cosine_distance,
|
||||||
COMMUTATOR = '<=>'
|
COMMUTATOR = '<=>'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- half opclasses
|
||||||
|
|
||||||
|
CREATE OPERATOR CLASS half_l2_ops
|
||||||
|
FOR TYPE half[] USING hnsw AS
|
||||||
|
OPERATOR 1 <-> (half[], half[]) FOR ORDER BY float_ops,
|
||||||
|
FUNCTION 1 half_l2_squared_distance(half[], half[]);
|
||||||
|
|||||||
@@ -462,8 +462,8 @@ InitBuildState(HnswBuildState * buildstate, Relation heap, Relation index, Index
|
|||||||
buildstate->dimensions = TupleDescAttr(index->rd_att, 0)->atttypmod;
|
buildstate->dimensions = TupleDescAttr(index->rd_att, 0)->atttypmod;
|
||||||
|
|
||||||
/* Require column to have dimensions to be indexed */
|
/* Require column to have dimensions to be indexed */
|
||||||
if (buildstate->dimensions < 0)
|
// if (buildstate->dimensions < 0)
|
||||||
elog(ERROR, "column does not have dimensions");
|
// elog(ERROR, "column does not have dimensions");
|
||||||
|
|
||||||
if (buildstate->dimensions > HNSW_MAX_DIM)
|
if (buildstate->dimensions > HNSW_MAX_DIM)
|
||||||
elog(ERROR, "column cannot have more than %d dimensions for hnsw index", HNSW_MAX_DIM);
|
elog(ERROR, "column cannot have more than %d dimensions for hnsw index", HNSW_MAX_DIM);
|
||||||
|
|||||||
93
test/t/019_hnsw_half.pl
Normal file
93
test/t/019_hnsw_half.pl
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use PostgresNode;
|
||||||
|
use TestLib;
|
||||||
|
use Test::More;
|
||||||
|
|
||||||
|
my $node;
|
||||||
|
my @queries = ();
|
||||||
|
my @expected;
|
||||||
|
my $limit = 20;
|
||||||
|
|
||||||
|
sub test_recall
|
||||||
|
{
|
||||||
|
my ($min, $operator) = @_;
|
||||||
|
my $correct = 0;
|
||||||
|
my $total = 0;
|
||||||
|
|
||||||
|
my $explain = $node->safe_psql("postgres", qq(
|
||||||
|
SET enable_seqscan = off;
|
||||||
|
EXPLAIN ANALYZE SELECT i FROM tst ORDER BY v $operator '$queries[0]' LIMIT $limit;
|
||||||
|
));
|
||||||
|
like($explain, qr/Index Scan/);
|
||||||
|
|
||||||
|
for my $i (0 .. $#queries)
|
||||||
|
{
|
||||||
|
my $actual = $node->safe_psql("postgres", qq(
|
||||||
|
SET enable_seqscan = off;
|
||||||
|
SELECT i FROM tst ORDER BY v $operator '$queries[$i]' LIMIT $limit;
|
||||||
|
));
|
||||||
|
my @actual_ids = split("\n", $actual);
|
||||||
|
my %actual_set = map { $_ => 1 } @actual_ids;
|
||||||
|
|
||||||
|
my @expected_ids = split("\n", $expected[$i]);
|
||||||
|
|
||||||
|
foreach (@expected_ids)
|
||||||
|
{
|
||||||
|
if (exists($actual_set{$_}))
|
||||||
|
{
|
||||||
|
$correct++;
|
||||||
|
}
|
||||||
|
$total++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmp_ok($correct / $total, ">=", $min, $operator);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize node
|
||||||
|
$node = get_new_node('node');
|
||||||
|
$node->init;
|
||||||
|
$node->start;
|
||||||
|
|
||||||
|
# Create table
|
||||||
|
$node->safe_psql("postgres", "CREATE EXTENSION vector;");
|
||||||
|
$node->safe_psql("postgres", "CREATE TABLE tst (i int4, v half[3]);");
|
||||||
|
$node->safe_psql("postgres",
|
||||||
|
"INSERT INTO tst SELECT i, ARRAY[random(), random(), random()]::numeric[]::half[] FROM generate_series(1, 10000) i;"
|
||||||
|
);
|
||||||
|
|
||||||
|
# Generate queries
|
||||||
|
for (1 .. 20)
|
||||||
|
{
|
||||||
|
my $r1 = rand();
|
||||||
|
my $r2 = rand();
|
||||||
|
my $r3 = rand();
|
||||||
|
push(@queries, "{$r1,$r2,$r3}");
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check each index type
|
||||||
|
my @operators = ("<->");
|
||||||
|
my @opclasses = ("half_l2_ops");
|
||||||
|
|
||||||
|
for my $i (0 .. $#operators)
|
||||||
|
{
|
||||||
|
my $operator = $operators[$i];
|
||||||
|
my $opclass = $opclasses[$i];
|
||||||
|
|
||||||
|
# Get exact results
|
||||||
|
@expected = ();
|
||||||
|
foreach (@queries)
|
||||||
|
{
|
||||||
|
my $res = $node->safe_psql("postgres", "SELECT i FROM tst ORDER BY v $operator '$_' LIMIT $limit;");
|
||||||
|
push(@expected, $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add index
|
||||||
|
$node->safe_psql("postgres", "CREATE INDEX ON tst USING hnsw (v $opclass);");
|
||||||
|
|
||||||
|
my $min = $operator eq "<#>" ? 0.80 : 0.99;
|
||||||
|
test_recall($min, $operator);
|
||||||
|
}
|
||||||
|
|
||||||
|
done_testing();
|
||||||
Reference in New Issue
Block a user