Added support for indexing sparsevec with L1 distance [skip ci]

This commit is contained in:
Andrew Kane
2024-04-22 13:08:12 -07:00
parent 70b299a7ff
commit 9f4b770db3
6 changed files with 57 additions and 4 deletions

View File

@@ -483,6 +483,11 @@ CREATE OPERATOR <=> (
COMMUTATOR = '<=>' COMMUTATOR = '<=>'
); );
CREATE OPERATOR <+> (
LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = l1_distance,
COMMUTATOR = '<+>'
);
CREATE OPERATOR < ( CREATE OPERATOR < (
LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = sparsevec_lt, LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = sparsevec_lt,
COMMUTATOR = > , NEGATOR = >= , COMMUTATOR = > , NEGATOR = >= ,
@@ -543,3 +548,8 @@ CREATE OPERATOR CLASS sparsevec_cosine_ops
OPERATOR 1 <=> (sparsevec, sparsevec) FOR ORDER BY float_ops, OPERATOR 1 <=> (sparsevec, sparsevec) FOR ORDER BY float_ops,
FUNCTION 1 sparsevec_negative_inner_product(sparsevec, sparsevec), FUNCTION 1 sparsevec_negative_inner_product(sparsevec, sparsevec),
FUNCTION 2 l2_norm(sparsevec); FUNCTION 2 l2_norm(sparsevec);
CREATE OPERATOR CLASS sparsevec_l1_ops
FOR TYPE sparsevec USING hnsw AS
OPERATOR 1 <+> (sparsevec, sparsevec) FOR ORDER BY float_ops,
FUNCTION 1 l1_distance(sparsevec, sparsevec);

View File

@@ -804,6 +804,11 @@ CREATE OPERATOR <=> (
COMMUTATOR = '<=>' COMMUTATOR = '<=>'
); );
CREATE OPERATOR <+> (
LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = l1_distance,
COMMUTATOR = '<+>'
);
CREATE OPERATOR < ( CREATE OPERATOR < (
LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = sparsevec_lt, LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = sparsevec_lt,
COMMUTATOR = > , NEGATOR = >= , COMMUTATOR = > , NEGATOR = >= ,
@@ -866,3 +871,8 @@ CREATE OPERATOR CLASS sparsevec_cosine_ops
OPERATOR 1 <=> (sparsevec, sparsevec) FOR ORDER BY float_ops, OPERATOR 1 <=> (sparsevec, sparsevec) FOR ORDER BY float_ops,
FUNCTION 1 sparsevec_negative_inner_product(sparsevec, sparsevec), FUNCTION 1 sparsevec_negative_inner_product(sparsevec, sparsevec),
FUNCTION 2 l2_norm(sparsevec); FUNCTION 2 l2_norm(sparsevec);
CREATE OPERATOR CLASS sparsevec_l1_ops
FOR TYPE sparsevec USING hnsw AS
OPERATOR 1 <+> (sparsevec, sparsevec) FOR ORDER BY float_ops,
FUNCTION 1 l1_distance(sparsevec, sparsevec);

View File

@@ -0,0 +1,21 @@
SET enable_seqscan = off;
CREATE TABLE t (val sparsevec(3));
INSERT INTO t (val) VALUES ('{}/3'), ('{1:1,2:2,3:3}/3'), ('{1:1,2:1,3:1}/3'), (NULL);
CREATE INDEX ON t USING hnsw (val sparsevec_l1_ops);
INSERT INTO t (val) VALUES ('{1:1,2:2,3:4}/3');
SELECT * FROM t ORDER BY val <+> '{1:3,2:3,3:3}/3';
val
-----------------
{1:1,2:2,3:3}/3
{1:1,2:2,3:4}/3
{1:1,2:1,3:1}/3
{}/3
(4 rows)
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <+> (SELECT NULL::sparsevec)) t2;
count
-------
4
(1 row)
DROP TABLE t;

View File

@@ -0,0 +1,12 @@
SET enable_seqscan = off;
CREATE TABLE t (val sparsevec(3));
INSERT INTO t (val) VALUES ('{}/3'), ('{1:1,2:2,3:3}/3'), ('{1:1,2:1,3:1}/3'), (NULL);
CREATE INDEX ON t USING hnsw (val sparsevec_l1_ops);
INSERT INTO t (val) VALUES ('{1:1,2:2,3:4}/3');
SELECT * FROM t ORDER BY val <+> '{1:3,2:3,3:3}/3';
SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <+> (SELECT NULL::sparsevec)) t2;
DROP TABLE t;

View File

@@ -67,8 +67,8 @@ for (1 .. 20)
} }
# Check each index type # Check each index type
my @operators = ("<->", "<#>", "<=>"); my @operators = ("<->", "<#>", "<=>", "<+>");
my @opclasses = ("sparsevec_l2_ops", "sparsevec_ip_ops", "sparsevec_cosine_ops"); my @opclasses = ("sparsevec_l2_ops", "sparsevec_ip_ops", "sparsevec_cosine_ops", "sparsevec_l1_ops");
for my $i (0 .. $#operators) for my $i (0 .. $#operators)
{ {

View File

@@ -64,8 +64,8 @@ for (1 .. 20)
} }
# Check each index type # Check each index type
my @operators = ("<->", "<#>", "<=>"); my @operators = ("<->", "<#>", "<=>", "<+>");
my @opclasses = ("sparsevec_l2_ops", "sparsevec_ip_ops", "sparsevec_cosine_ops"); my @opclasses = ("sparsevec_l2_ops", "sparsevec_ip_ops", "sparsevec_cosine_ops", "sparsevec_l1_ops");
for my $i (0 .. $#operators) for my $i (0 .. $#operators)
{ {