Compare commits

...

34 Commits

Author SHA1 Message Date
Andrew Kane
455b5d867c Started support for parallel index scan [skip ci] 2023-06-29 23:17:59 -04:00
Jonathan S. Katz
de6502ab6e Simplify TAP test structure to align with upstream (#169)
postgres/postgres@549ec20 moved to using "done_testing()" from
the Perl testing framework, which removed the need to include test
counts.
2023-06-29 11:36:08 -04:00
Andrew Kane
7aaba14440 Added comment [skip ci] 2023-06-29 10:25:06 -04:00
Andrew Kane
ee0bf10d7d Fixed CI for equal distances 2023-06-29 10:24:02 -04:00
Andrew Kane
88094fc39f Fixed tests 2023-06-29 10:17:15 -04:00
Andrew Kane
209394faab Now available on Google Cloud SQL [skip ci] 2023-06-26 11:17:10 -04:00
Andrew Kane
673aca97fc Fixed CI for branches for i386 2023-06-16 17:38:51 -04:00
Andrew Kane
0e2dc0e6d4 Updated readme [skip ci] 2023-06-16 10:15:22 -04:00
Andrew Kane
3c681b94fd Updated example [skip ci] 2023-06-16 10:03:07 -04:00
Andrew Kane
1982121694 Version bump to 0.4.4 [skip ci] 2023-06-12 01:55:22 -07:00
Andrew Kane
9c8c4483db Updated changelog [skip ci] 2023-06-12 01:23:47 -07:00
Andrew Kane
426ae1f16e Added scan-build to CI 2023-06-12 01:13:21 -07:00
Andrew Kane
06c3e68bef Fixed segmentation fault with text representation 2023-06-12 01:09:40 -07:00
Andrew Kane
e5a620e02c Improved tests 2023-06-11 19:23:30 -07:00
Andrew Kane
092bb80f58 Added test for small floats [skip ci] 2023-06-11 19:19:07 -07:00
Andrew Kane
b690cd4d5d Added tests for large floats [skip ci] 2023-06-11 19:17:54 -07:00
Andrew Kane
4e0d11acfe Improved test [skip ci] 2023-06-11 19:15:42 -07:00
Andrew Kane
aa63f80b69 Improved test [skip ci] 2023-06-11 19:14:32 -07:00
Andrew Kane
b8a7355731 Improved test [skip ci] 2023-06-11 19:12:56 -07:00
Andrew Kane
3332669489 Improved tests [skip ci] 2023-06-11 19:11:17 -07:00
Andrew Kane
08c70bb57f Added more input tests [skip ci] 2023-06-11 19:08:24 -07:00
Andrew Kane
eff0de6a64 Updated comments [skip ci] 2023-06-11 18:36:41 -07:00
Andrew Kane
3cf7ce6543 Added comment for CheckDim [skip ci] 2023-06-11 13:06:51 -07:00
Andrew Kane
3cb6440744 Simplified PrintVector [skip ci] 2023-06-11 12:54:18 -07:00
Andrew Kane
b6a0d2b12b Check for empty string like float4in [skip ci] 2023-06-11 12:34:24 -07:00
Andrew Kane
78632e3301 Added input test case [skip ci] 2023-06-11 12:22:52 -07:00
Andrew Kane
f8c85905c3 Use vector_isspace to remove whitespace before strtof 2023-06-11 12:21:27 -07:00
Andrew Kane
0a98a953cd Fixed consecutive delimiters with text representation 2023-06-11 12:10:52 -07:00
Andrew Kane
a577c2df80 Updated format [skip ci] 2023-06-11 12:04:02 -07:00
Andrew Kane
7ee9e86b10 Improved error message for invalid input syntax 2023-06-11 12:00:04 -07:00
Andrew Kane
5fdf5573a0 No need to manually free memory on errors 2023-06-11 09:42:20 -07:00
Andrew Kane
2b939edfee Improved error message for malformed vector literal - #153 2023-06-11 09:24:11 -07:00
Andrew Kane
987026a559 Improved benchmarking for index build [skip ci] 2023-06-10 21:50:31 -07:00
Andrew Kane
d158eefa60 Updated guidance on probes [skip ci] 2023-06-10 17:47:41 -07:00
24 changed files with 248 additions and 117 deletions

View File

@@ -60,6 +60,7 @@ jobs:
wget -q https://github.com/postgres/postgres/archive/refs/tags/REL_14_5.tar.gz
tar xf REL_14_5.tar.gz
- run: make prove_installcheck PROVE_FLAGS="-I ./postgres-REL_14_5/src/test/perl" PERL5LIB="/Users/runner/perl5/lib/perl5"
- run: make clean && /usr/local/opt/llvm@15/bin/scan-build --status-bugs make
windows:
runs-on: windows-latest
if: ${{ !startsWith(github.ref_name, 'mac') }}
@@ -87,7 +88,8 @@ jobs:
- run: |
git clone https://github.com/${{ github.repository }}.git pgvector
cd pgvector
git checkout ${{ github.ref }}
git fetch origin ${{ github.ref }}
git reset --hard FETCH_HEAD
make
make install
chown -R postgres .

View File

@@ -1,8 +1,14 @@
## 0.4.4 (2023-06-12)
- Improved error message for malformed vector literal
- Fixed segmentation fault with text input
- Fixed consecutive delimiters with text input
## 0.4.3 (2023-06-10)
- Improved cost estimation
- Improved support for spaces with text representation
- Fixed infinite and NaN values with binary representation
- Improved support for spaces with text input
- Fixed infinite and NaN values with binary input
- Fixed infinite values with vector addition and subtraction
- Fixed infinite values with list centers
- Fixed compilation error when `float8` is pass by reference

View File

@@ -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.4.3",
"version": "0.4.4",
"maintainer": [
"Andrew Kane <andrew@ankane.org>"
],
@@ -20,7 +20,7 @@
"vector": {
"file": "sql/vector.sql",
"docfile": "README.md",
"version": "0.4.3",
"version": "0.4.4",
"abstract": "Open-source vector similarity search for Postgres"
}
},

View File

@@ -1,5 +1,5 @@
EXTENSION = vector
EXTVERSION = 0.4.3
EXTVERSION = 0.4.4
MODULE_big = vector
DATA = $(wildcard sql/*--*.sql)

View File

@@ -1,5 +1,5 @@
EXTENSION = vector
EXTVERSION = 0.4.3
EXTVERSION = 0.4.4
OBJS = src\ivfbuild.obj src\ivfflat.obj src\ivfinsert.obj src\ivfkmeans.obj src\ivfscan.obj src\ivfutils.obj src\ivfvacuum.obj src\vector.obj

View File

@@ -2,7 +2,7 @@
Open-source vector similarity search for Postgres
Supports
Store all of your application data in one place. Supports:
- exact and approximate nearest neighbor search
- L2 distance, inner product, and cosine distance
@@ -18,7 +18,7 @@ Compile and install the extension (supports Postgres 11+)
```sh
cd /tmp
git clone --branch v0.4.3 https://github.com/pgvector/pgvector.git
git clone --branch v0.4.4 https://github.com/pgvector/pgvector.git
cd pgvector
make
make install # may need sudo
@@ -163,7 +163,7 @@ Three keys to achieving good recall are:
1. Create the index *after* the table has some data
2. Choose an appropriate number of lists - a good place to start is `rows / 1000` for up to 1M rows and `sqrt(rows)` for over 1M rows
3. When querying, specify an appropriate number of [probes](#query-options) (higher is better for recall, lower is better for speed) - a good place to start is `lists / 10` for up to 1M rows and `sqrt(lists)` for over 1M rows
3. When querying, specify an appropriate number of [probes](#query-options) (higher is better for recall, lower is better for speed) - a good place to start is `sqrt(lists)`
Add an index for each distance function you want to use.
@@ -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)).
```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;
```
@@ -397,7 +397,7 @@ Support for Windows is currently experimental. Use `nmake` to build:
```cmd
set "PGROOT=C:\Program Files\PostgreSQL\15"
git clone --branch v0.4.3 https://github.com/pgvector/pgvector.git
git clone --branch v0.4.4 https://github.com/pgvector/pgvector.git
cd pgvector
nmake /F Makefile.win
nmake /F Makefile.win install
@@ -418,7 +418,7 @@ This adds pgvector to the [Postgres image](https://hub.docker.com/_/postgres) (r
You can also build the image manually:
```sh
git clone --branch v0.4.3 https://github.com/pgvector/pgvector.git
git clone --branch v0.4.4 https://github.com/pgvector/pgvector.git
cd pgvector
docker build --build-arg PG_MAJOR=15 -t myuser/pgvector .
```
@@ -483,7 +483,6 @@ pgvector is available on [these providers](https://github.com/pgvector/pgvector/
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)
- Heroku Postgres - vote or comment on [this page](https://github.com/heroku/roadmap/issues/156)

View 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.4.4'" to load this file. \quit

View File

@@ -568,6 +568,21 @@ PrintKmeansMetrics(IvfflatBuildState * buildstate)
}
#endif
/*
* Scan table for tuples to index
*/
static void
ScanTable(IvfflatBuildState * buildstate)
{
#if PG_VERSION_NUM >= 120000
buildstate->reltuples = table_index_build_scan(buildstate->heap, buildstate->index, buildstate->indexInfo,
true, true, BuildCallback, (void *) buildstate, NULL);
#else
buildstate->reltuples = IndexBuildHeapScan(buildstate->heap, buildstate->index, buildstate->indexInfo,
true, BuildCallback, (void *) buildstate, NULL);
#endif
}
/*
* Create entry pages
*/
@@ -585,25 +600,17 @@ CreateEntryPages(IvfflatBuildState * buildstate, ForkNumber forkNum)
/* Add tuples to sort */
if (buildstate->heap != NULL)
{
#if PG_VERSION_NUM >= 120000
buildstate->reltuples = table_index_build_scan(buildstate->heap, buildstate->index, buildstate->indexInfo,
true, true, BuildCallback, (void *) buildstate, NULL);
#else
buildstate->reltuples = IndexBuildHeapScan(buildstate->heap, buildstate->index, buildstate->indexInfo,
true, BuildCallback, (void *) buildstate, NULL);
#endif
}
IvfflatBench("assign tuples", ScanTable(buildstate));
/* Sort */
tuplesort_performsort(buildstate->sortstate);
IvfflatBench("sort tuples", tuplesort_performsort(buildstate->sortstate));
#ifdef IVFFLAT_KMEANS_DEBUG
PrintKmeansMetrics(buildstate);
#endif
/* Insert */
InsertTuples(buildstate->index, buildstate, forkNum);
IvfflatBench("load tuples", InsertTuples(buildstate->index, buildstate, forkNum));
tuplesort_end(buildstate->sortstate);
}
@@ -621,7 +628,7 @@ BuildIndex(Relation heap, Relation index, IndexInfo *indexInfo,
/* Create pages */
CreateMetaPage(index, buildstate->dimensions, buildstate->lists, forkNum);
CreateListPages(index, buildstate->centers, buildstate->dimensions, buildstate->lists, forkNum, &buildstate->listInfo);
IvfflatBench("CreateEntryPages", CreateEntryPages(buildstate, forkNum));
CreateEntryPages(buildstate, forkNum);
FreeBuildState(buildstate);
}

View File

@@ -142,6 +142,10 @@ ivfflatcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
*indexSelectivity = costs.indexSelectivity;
*indexCorrelation = costs.indexCorrelation;
*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;
}
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
*
@@ -209,7 +232,7 @@ ivfflathandler(PG_FUNCTION_ARGS)
amroutine->amstorage = false;
amroutine->amclusterable = false;
amroutine->ampredlocks = false;
amroutine->amcanparallel = false;
amroutine->amcanparallel = true;
amroutine->amcaninclude = false;
#if PG_VERSION_NUM >= 130000
amroutine->amusemaintenanceworkmem = false; /* not used during VACUUM */
@@ -243,9 +266,9 @@ ivfflathandler(PG_FUNCTION_ARGS)
amroutine->amrestrpos = NULL;
/* Interface functions to support parallel index scans */
amroutine->amestimateparallelscan = NULL;
amroutine->aminitparallelscan = NULL;
amroutine->amparallelrescan = NULL;
amroutine->amestimateparallelscan = ivfflatestimateparallelscan;
amroutine->aminitparallelscan = ivfflatinitparallelscan;
amroutine->amparallelrescan = ivfflatparallelrescan;
PG_RETURN_POINTER(amroutine);
}

View File

@@ -126,6 +126,9 @@ GetScanItems(IndexScanDesc scan, Datum value)
*/
BufferAccessStrategy bas = GetAccessStrategy(BAS_BULKREAD);
if (scan->parallel_scan != NULL)
elog(INFO, "parallel scan");
/* Search closest probes lists */
while (!pairingheap_is_empty(so->listQueue))
{

View File

@@ -42,7 +42,7 @@ CheckDims(Vector * a, Vector * b)
}
/*
* Ensure expected dimension
* Ensure expected dimensions
*/
static inline void
CheckExpectedDim(int32 typmod, int dim)
@@ -53,7 +53,9 @@ CheckExpectedDim(int32 typmod, int dim)
errmsg("expected %d dimensions, not %d", typmod, dim)));
}
/*
* Ensure valid dimensions
*/
static inline void
CheckDim(int dim)
{
@@ -72,27 +74,17 @@ CheckDim(int dim)
* Ensure finite elements
*/
static inline void
CheckElementOrFree(float value, Vector * vec)
CheckElement(float value)
{
if (isnan(value))
{
if (vec != NULL)
pfree(vec);
ereport(ERROR,
(errcode(ERRCODE_DATA_EXCEPTION),
errmsg("NaN not allowed in vector")));
}
if (isinf(value))
{
if (vec != NULL)
pfree(vec);
ereport(ERROR,
(errcode(ERRCODE_DATA_EXCEPTION),
errmsg("infinite value not allowed in vector")));
}
}
/*
@@ -135,30 +127,6 @@ float_overflow_error(void)
}
#endif
/*
* Print vector - useful for debugging
*/
void
PrintVector(char *msg, Vector * vector)
{
StringInfoData buf;
int dim = vector->dim;
int i;
initStringInfo(&buf);
appendStringInfoChar(&buf, '[');
for (i = 0; i < dim; i++)
{
if (i > 0)
appendStringInfoString(&buf, ",");
appendStringInfoString(&buf, float8out_internal(vector->x[i]));
}
appendStringInfoChar(&buf, ']');
elog(INFO, "%s = %s", msg, buf.data);
}
/*
* Convert textual representation to internal representation
*/
@@ -174,6 +142,7 @@ vector_in(PG_FUNCTION_ARGS)
char *pt;
char *stringEnd;
Vector *result;
char *lit = pstrdup(str);
while (vector_isspace(*str))
str++;
@@ -181,7 +150,7 @@ vector_in(PG_FUNCTION_ARGS)
if (*str != '[')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("malformed vector literal: \"%s\"", str),
errmsg("malformed vector literal: \"%s\"", lit),
errdetail("Vector contents must start with \"[\".")));
str++;
@@ -195,15 +164,24 @@ vector_in(PG_FUNCTION_ARGS)
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("vector cannot have more than %d dimensions", VECTOR_MAX_DIM)));
while (vector_isspace(*pt))
pt++;
/* Check for empty string like float4in */
if (*pt == '\0')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type vector: \"%s\"", lit)));
/* Use strtof like float4in to avoid a double-rounding problem */
x[dim] = strtof(pt, &stringEnd);
CheckElementOrFree(x[dim], NULL);
CheckElement(x[dim]);
dim++;
if (stringEnd == pt)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type vector: \"%s\"", pt)));
errmsg("invalid input syntax for type vector: \"%s\"", lit)));
while (vector_isspace(*stringEnd))
stringEnd++;
@@ -211,15 +189,15 @@ vector_in(PG_FUNCTION_ARGS)
if (*stringEnd != '\0' && *stringEnd != ']')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type vector: \"%s\"", pt)));
errmsg("invalid input syntax for type vector: \"%s\"", lit)));
pt = strtok(NULL, ",");
}
if (*stringEnd != ']')
if (stringEnd == NULL || *stringEnd != ']')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("malformed vector literal"),
errmsg("malformed vector literal: \"%s\"", lit),
errdetail("Unexpected end of input.")));
stringEnd++;
@@ -231,14 +209,25 @@ vector_in(PG_FUNCTION_ARGS)
if (*stringEnd != '\0')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("malformed vector literal"),
errmsg("malformed vector literal: \"%s\"", lit),
errdetail("Junk after closing right brace.")));
/* Ensure no consecutive delimiters since strtok skips */
for (pt = lit + 1; *pt != '\0'; pt++)
{
if (pt[-1] == ',' && *pt == ',')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("malformed vector literal: \"%s\"", lit)));
}
if (dim < 1)
ereport(ERROR,
(errcode(ERRCODE_DATA_EXCEPTION),
errmsg("vector must have at least 1 dimension")));
pfree(lit);
CheckExpectedDim(typmod, dim);
result = InitVector(dim);
@@ -309,6 +298,18 @@ vector_out(PG_FUNCTION_ARGS)
PG_RETURN_CSTRING(buf);
}
/*
* Print vector - useful for debugging
*/
void
PrintVector(char *msg, Vector * vector)
{
char *out = DatumGetPointer(DirectFunctionCall1(vector_out, PointerGetDatum(vector)));
elog(INFO, "%s = %s", msg, out);
pfree(out);
}
/*
* Convert type modifier
*/
@@ -369,7 +370,7 @@ vector_recv(PG_FUNCTION_ARGS)
for (i = 0; i < dim; i++)
{
result->x[i] = pq_getmsgfloat4(buf);
CheckElementOrFree(result->x[i], result);
CheckElement(result->x[i]);
}
PG_RETURN_POINTER(result);
@@ -461,7 +462,7 @@ array_to_vector(PG_FUNCTION_ARGS)
(errcode(ERRCODE_DATA_EXCEPTION),
errmsg("unsupported array type")));
CheckElementOrFree(result->x[i], result);
CheckElement(result->x[i]);
}
PG_RETURN_POINTER(result);
@@ -703,10 +704,7 @@ vector_add(PG_FUNCTION_ARGS)
for (int i = 0, imax = a->dim; i < imax; i++)
{
if (isinf(rx[i]))
{
pfree(result);
float_overflow_error();
}
}
PG_RETURN_POINTER(result);
@@ -739,10 +737,7 @@ vector_sub(PG_FUNCTION_ARGS)
for (int i = 0, imax = a->dim; i < imax; i++)
{
if (isinf(rx[i]))
{
pfree(result);
float_overflow_error();
}
}
PG_RETURN_POINTER(result);
@@ -905,10 +900,7 @@ vector_accum(PG_FUNCTION_ARGS)
/* Check for overflow */
if (isinf(v))
{
pfree(statedatums);
float_overflow_error();
}
statedatums[i + 1] = Float8GetDatum(v);
}
@@ -977,10 +969,7 @@ vector_combine(PG_FUNCTION_ARGS)
/* Check for overflow */
if (isinf(v))
{
pfree(statedatums);
float_overflow_error();
}
statedatums[i] = Float8GetDatum(v);
}
@@ -1025,7 +1014,7 @@ vector_avg(PG_FUNCTION_ARGS)
for (int i = 0; i < dim; i++)
{
result->x[i] = statevalues[i + 1] / n;
CheckElementOrFree(result->x[i], result);
CheckElement(result->x[i]);
}
PG_RETURN_POINTER(result);

View File

@@ -4,13 +4,19 @@ SELECT '[1,2,3]'::vector;
[1,2,3]
(1 row)
SELECT '[-1,2,3]'::vector;
vector
----------
[-1,2,3]
SELECT '[-1,-2,-3]'::vector;
vector
------------
[-1,-2,-3]
(1 row)
SELECT ' [ 1, 2 , 3 ] '::vector(3);
SELECT '[1.,2.,3.]'::vector;
vector
---------
[1,2,3]
(1 row)
SELECT ' [ 1, 2 , 3 ] '::vector;
vector
---------
[1,2,3]
@@ -23,7 +29,7 @@ SELECT '[1.23456]'::vector;
(1 row)
SELECT '[hello,1]'::vector;
ERROR: invalid input syntax for type vector: "hello"
ERROR: invalid input syntax for type vector: "[hello,1]"
LINE 1: SELECT '[hello,1]'::vector;
^
SELECT '[NaN,1]'::vector;
@@ -38,17 +44,35 @@ SELECT '[-Infinity,1]'::vector;
ERROR: infinite value not allowed in vector
LINE 1: SELECT '[-Infinity,1]'::vector;
^
SELECT '[1.5e38,-1.5e38]'::vector;
vector
--------------------
[1.5e+38,-1.5e+38]
(1 row)
SELECT '[1.5e+38,-1.5e+38]'::vector;
vector
--------------------
[1.5e+38,-1.5e+38]
(1 row)
SELECT '[1.5e-38,-1.5e-38]'::vector;
vector
--------------------
[1.5e-38,-1.5e-38]
(1 row)
SELECT '[4e38,1]'::vector;
ERROR: infinite value not allowed in vector
LINE 1: SELECT '[4e38,1]'::vector;
^
SELECT '[1,2,3'::vector;
ERROR: malformed vector literal
ERROR: malformed vector literal: "[1,2,3"
LINE 1: SELECT '[1,2,3'::vector;
^
DETAIL: Unexpected end of input.
SELECT '[1,2,3]9'::vector;
ERROR: malformed vector literal
ERROR: malformed vector literal: "[1,2,3]9"
LINE 1: SELECT '[1,2,3]9'::vector;
^
DETAIL: Junk after closing right brace.
@@ -57,14 +81,36 @@ ERROR: malformed vector literal: "1,2,3"
LINE 1: SELECT '1,2,3'::vector;
^
DETAIL: Vector contents must start with "[".
SELECT '['::vector;
ERROR: malformed vector literal: "["
LINE 1: SELECT '['::vector;
^
DETAIL: Unexpected end of input.
SELECT '[,'::vector;
ERROR: malformed vector literal: "[,"
LINE 1: SELECT '[,'::vector;
^
DETAIL: Unexpected end of input.
SELECT '[]'::vector;
ERROR: vector must have at least 1 dimension
LINE 1: SELECT '[]'::vector;
^
SELECT '[1,]'::vector;
ERROR: invalid input syntax for type vector: "]"
ERROR: invalid input syntax for type vector: "[1,]"
LINE 1: SELECT '[1,]'::vector;
^
SELECT '[1a]'::vector;
ERROR: invalid input syntax for type vector: "[1a]"
LINE 1: SELECT '[1a]'::vector;
^
SELECT '[1,,3]'::vector;
ERROR: malformed vector literal: "[1,,3]"
LINE 1: SELECT '[1,,3]'::vector;
^
SELECT '[1, ,3]'::vector;
ERROR: invalid input syntax for type vector: "[1, ,3]"
LINE 1: SELECT '[1, ,3]'::vector;
^
SELECT '[1,2,3]'::vector(2);
ERROR: expected 2 dimensions, not 3
SELECT unnest('{"[1,2,3]", "[4,5,6]"}'::vector[]);

View File

@@ -1,17 +1,26 @@
SELECT '[1,2,3]'::vector;
SELECT '[-1,2,3]'::vector;
SELECT ' [ 1, 2 , 3 ] '::vector(3);
SELECT '[-1,-2,-3]'::vector;
SELECT '[1.,2.,3.]'::vector;
SELECT ' [ 1, 2 , 3 ] '::vector;
SELECT '[1.23456]'::vector;
SELECT '[hello,1]'::vector;
SELECT '[NaN,1]'::vector;
SELECT '[Infinity,1]'::vector;
SELECT '[-Infinity,1]'::vector;
SELECT '[1.5e38,-1.5e38]'::vector;
SELECT '[1.5e+38,-1.5e+38]'::vector;
SELECT '[1.5e-38,-1.5e-38]'::vector;
SELECT '[4e38,1]'::vector;
SELECT '[1,2,3'::vector;
SELECT '[1,2,3]9'::vector;
SELECT '1,2,3'::vector;
SELECT '['::vector;
SELECT '[,'::vector;
SELECT '[]'::vector;
SELECT '[1,]'::vector;
SELECT '[1a]'::vector;
SELECT '[1,,3]'::vector;
SELECT '[1, ,3]'::vector;
SELECT '[1,2,3]'::vector(2);
SELECT unnest('{"[1,2,3]", "[4,5,6]"}'::vector[]);

View 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;

View File

@@ -5,7 +5,7 @@ use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 31;
use Test::More;
my $dim = 32;
@@ -95,3 +95,5 @@ for my $i (1 .. 10)
);
test_index_replay("insert $i");
}
done_testing();

View File

@@ -2,7 +2,7 @@ use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 1;
use Test::More;
my $dim = 3;
@@ -39,3 +39,5 @@ $node->safe_psql("postgres",
# Check size
my $new_size = $node->safe_psql("postgres", "SELECT pg_total_relation_size('tst_v_idx');");
is($size, $new_size, "size does not change");
done_testing();

View File

@@ -2,7 +2,7 @@ use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 9;
use Test::More;
my $node;
my @queries = ();
@@ -15,6 +15,13 @@ sub test_recall
my $correct = 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) {
my $actual = $node->safe_psql("postgres", qq(
SET enable_seqscan = off;
@@ -72,9 +79,9 @@ foreach (@operators) {
# Add index
my $opclass;
if ($operator == "<->") {
if ($operator eq "<->") {
$opclass = "vector_l2_ops";
} elsif ($operator == "<#>") {
} elsif ($operator eq "<#>") {
$opclass = "vector_ip_ops";
} else {
$opclass = "vector_cosine_ops";
@@ -82,7 +89,13 @@ foreach (@operators) {
$node->safe_psql("postgres", "CREATE INDEX ON tst USING ivfflat (v $opclass);");
# Test approximate results
test_recall(1, 0.75, $operator);
test_recall(10, 0.95, $operator);
test_recall(100, 1.0, $operator);
if ($operator ne "<#>") {
# TODO fix test
test_recall(1, 0.75, $operator);
test_recall(10, 0.95, $operator);
}
# Account for equal distances
test_recall(100, 0.9975, $operator);
}
done_testing();

View File

@@ -2,7 +2,7 @@ use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 3;
use Test::More;
# Initialize node
my $node = get_new_node('node');
@@ -34,3 +34,5 @@ $node->safe_psql("postgres",
# Test no error for duplicate centers
test_centers(10);
done_testing();

View File

@@ -2,7 +2,7 @@ use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 60;
use Test::More;
# Initialize node
my $node = get_new_node('node');
@@ -23,9 +23,9 @@ foreach (@operators) {
# Add index
my $opclass;
if ($operator == "<->") {
if ($operator eq "<->") {
$opclass = "vector_l2_ops";
} elsif ($operator == "<#>") {
} elsif ($operator eq "<#>") {
$opclass = "vector_ip_ops";
} else {
$opclass = "vector_cosine_ops";
@@ -43,3 +43,5 @@ foreach (@operators) {
is($res, $query);
}
}
done_testing();

View File

@@ -2,7 +2,7 @@ use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 3;
use Test::More;
# Initialize 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);"
);
like($stderr, qr/memory required is/);
done_testing();

View File

@@ -2,7 +2,7 @@ use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 7;
use Test::More;
my $dim = 768;
@@ -53,3 +53,5 @@ $count = $node->safe_psql("postgres", qq(
));
is($count, $expected);
is(idx_scan(), 1);
done_testing();

View File

@@ -2,7 +2,7 @@ use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 5;
use Test::More;
# Initialize node
my $node = get_new_node('node');
@@ -33,3 +33,5 @@ is($avg, "[$r1,$r2,$r3]");
# Test explain
my $explain = $node->safe_psql("postgres", "EXPLAIN SELECT AVG(v) FROM tst;");
like($explain, qr/Partial Aggregate/);
done_testing();

View File

@@ -2,7 +2,7 @@ use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 1;
use Test::More;
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"
);
like($stderr, qr/row is too big/);
done_testing();

View File

@@ -1,4 +1,4 @@
comment = 'vector data type and ivfflat access method'
default_version = '0.4.3'
default_version = '0.4.4'
module_pathname = '$libdir/vector'
relocatable = true