diff --git a/sql/vector--0.6.2--0.7.0.sql b/sql/vector--0.6.2--0.7.0.sql index 5260e59..bed067b 100644 --- a/sql/vector--0.6.2--0.7.0.sql +++ b/sql/vector--0.6.2--0.7.0.sql @@ -483,6 +483,11 @@ CREATE OPERATOR <=> ( COMMUTATOR = '<=>' ); +CREATE OPERATOR <+> ( + LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = l1_distance, + COMMUTATOR = '<+>' +); + CREATE OPERATOR < ( LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = sparsevec_lt, COMMUTATOR = > , NEGATOR = >= , @@ -543,3 +548,8 @@ CREATE OPERATOR CLASS sparsevec_cosine_ops OPERATOR 1 <=> (sparsevec, sparsevec) FOR ORDER BY float_ops, FUNCTION 1 sparsevec_negative_inner_product(sparsevec, 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); diff --git a/sql/vector.sql b/sql/vector.sql index 78951af..a169502 100644 --- a/sql/vector.sql +++ b/sql/vector.sql @@ -804,6 +804,11 @@ CREATE OPERATOR <=> ( COMMUTATOR = '<=>' ); +CREATE OPERATOR <+> ( + LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = l1_distance, + COMMUTATOR = '<+>' +); + CREATE OPERATOR < ( LEFTARG = sparsevec, RIGHTARG = sparsevec, PROCEDURE = sparsevec_lt, COMMUTATOR = > , NEGATOR = >= , @@ -866,3 +871,8 @@ CREATE OPERATOR CLASS sparsevec_cosine_ops OPERATOR 1 <=> (sparsevec, sparsevec) FOR ORDER BY float_ops, FUNCTION 1 sparsevec_negative_inner_product(sparsevec, 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); diff --git a/test/expected/hnsw_sparsevec_l1.out b/test/expected/hnsw_sparsevec_l1.out new file mode 100644 index 0000000..f854cbb --- /dev/null +++ b/test/expected/hnsw_sparsevec_l1.out @@ -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; diff --git a/test/sql/hnsw_sparsevec_l1.sql b/test/sql/hnsw_sparsevec_l1.sql new file mode 100644 index 0000000..a47961a --- /dev/null +++ b/test/sql/hnsw_sparsevec_l1.sql @@ -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; diff --git a/test/t/022_hnsw_sparsevec_build_recall.pl b/test/t/022_hnsw_sparsevec_build_recall.pl index ed8c4ea..8533e2d 100644 --- a/test/t/022_hnsw_sparsevec_build_recall.pl +++ b/test/t/022_hnsw_sparsevec_build_recall.pl @@ -67,8 +67,8 @@ for (1 .. 20) } # Check each index type -my @operators = ("<->", "<#>", "<=>"); -my @opclasses = ("sparsevec_l2_ops", "sparsevec_ip_ops", "sparsevec_cosine_ops"); +my @operators = ("<->", "<#>", "<=>", "<+>"); +my @opclasses = ("sparsevec_l2_ops", "sparsevec_ip_ops", "sparsevec_cosine_ops", "sparsevec_l1_ops"); for my $i (0 .. $#operators) { diff --git a/test/t/025_hnsw_sparsevec_insert_recall.pl b/test/t/025_hnsw_sparsevec_insert_recall.pl index ff5b76e..b6b8093 100644 --- a/test/t/025_hnsw_sparsevec_insert_recall.pl +++ b/test/t/025_hnsw_sparsevec_insert_recall.pl @@ -64,8 +64,8 @@ for (1 .. 20) } # Check each index type -my @operators = ("<->", "<#>", "<=>"); -my @opclasses = ("sparsevec_l2_ops", "sparsevec_ip_ops", "sparsevec_cosine_ops"); +my @operators = ("<->", "<#>", "<=>", "<+>"); +my @opclasses = ("sparsevec_l2_ops", "sparsevec_ip_ops", "sparsevec_cosine_ops", "sparsevec_l1_ops"); for my $i (0 .. $#operators) {