mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-22 20:15:46 +08:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b89bed701 | ||
|
|
ad7cad5ecd | ||
|
|
2a8b9d689e | ||
|
|
18cd8a60c3 | ||
|
|
8c91a9f56a | ||
|
|
9249e7e2de | ||
|
|
9e91af5989 | ||
|
|
9dcf1bdc80 | ||
|
|
0eceaa3966 | ||
|
|
49c1f13095 | ||
|
|
ff9b22977e | ||
|
|
0468cbf6e6 | ||
|
|
258eaf58fd | ||
|
|
fa8d2df1cc | ||
|
|
69f49290fb | ||
|
|
ad91451266 | ||
|
|
cafd2f6641 | ||
|
|
7923c44efe | ||
|
|
9b269e2612 | ||
|
|
9894ca3e4e | ||
|
|
19cbbfdd69 | ||
|
|
24c8a2ff40 | ||
|
|
6df583a6f6 | ||
|
|
999a2e53dd |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,3 +1,14 @@
|
|||||||
|
## 0.7.2 (2024-06-11)
|
||||||
|
|
||||||
|
- Fixed initialization fork for indexes on unlogged tables
|
||||||
|
|
||||||
|
## 0.7.1 (2024-06-03)
|
||||||
|
|
||||||
|
- Improved performance of on-disk HNSW index builds
|
||||||
|
- Fixed `undefined symbol` error with GCC 8
|
||||||
|
- Fixed compilation error with universal binaries on Mac
|
||||||
|
- Fixed compilation warning with Clang < 14
|
||||||
|
|
||||||
## 0.7.0 (2024-04-29)
|
## 0.7.0 (2024-04-29)
|
||||||
|
|
||||||
- Added `halfvec` type
|
- Added `halfvec` type
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "vector",
|
"name": "vector",
|
||||||
"abstract": "Open-source vector similarity search for Postgres",
|
"abstract": "Open-source vector similarity search for Postgres",
|
||||||
"description": "Supports L2 distance, inner product, and cosine distance",
|
"description": "Supports L2 distance, inner product, and cosine distance",
|
||||||
"version": "0.7.0",
|
"version": "0.7.2",
|
||||||
"maintainer": [
|
"maintainer": [
|
||||||
"Andrew Kane <andrew@ankane.org>"
|
"Andrew Kane <andrew@ankane.org>"
|
||||||
],
|
],
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
"vector": {
|
"vector": {
|
||||||
"file": "sql/vector.sql",
|
"file": "sql/vector.sql",
|
||||||
"docfile": "README.md",
|
"docfile": "README.md",
|
||||||
"version": "0.7.0",
|
"version": "0.7.2",
|
||||||
"abstract": "Open-source vector similarity search for Postgres"
|
"abstract": "Open-source vector similarity search for Postgres"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -1,5 +1,5 @@
|
|||||||
EXTENSION = vector
|
EXTENSION = vector
|
||||||
EXTVERSION = 0.7.0
|
EXTVERSION = 0.7.2
|
||||||
|
|
||||||
MODULE_big = vector
|
MODULE_big = vector
|
||||||
DATA = $(wildcard sql/*--*.sql)
|
DATA = $(wildcard sql/*--*.sql)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
EXTENSION = vector
|
EXTENSION = vector
|
||||||
EXTVERSION = 0.7.0
|
EXTVERSION = 0.7.2
|
||||||
|
|
||||||
OBJS = src\bitutils.obj src\bitvec.obj src\halfutils.obj src\halfvec.obj src\hnsw.obj src\hnswbuild.obj src\hnswinsert.obj src\hnswscan.obj src\hnswutils.obj src\hnswvacuum.obj src\ivfbuild.obj src\ivfflat.obj src\ivfinsert.obj src\ivfkmeans.obj src\ivfscan.obj src\ivfutils.obj src\ivfvacuum.obj src\sparsevec.obj src\vector.obj
|
OBJS = src\bitutils.obj src\bitvec.obj src\halfutils.obj src\halfvec.obj src\hnsw.obj src\hnswbuild.obj src\hnswinsert.obj src\hnswscan.obj src\hnswutils.obj src\hnswvacuum.obj src\ivfbuild.obj src\ivfflat.obj src\ivfinsert.obj src\ivfkmeans.obj src\ivfscan.obj src\ivfutils.obj src\ivfvacuum.obj src\sparsevec.obj src\vector.obj
|
||||||
HEADERS = src\halfvec.h src\sparsevec.h src\vector.h
|
HEADERS = src\halfvec.h src\sparsevec.h src\vector.h
|
||||||
|
|
||||||
REGRESS = bit btree cast copy halfvec hnsw_bit hnsw_halfvec hnsw_sparsevec hnsw_vector ivfflat_bit ivfflat_halfvec ivfflat_vector sparsevec vector
|
REGRESS = bit btree cast copy halfvec hnsw_bit hnsw_halfvec hnsw_sparsevec hnsw_vector ivfflat_bit ivfflat_halfvec ivfflat_vector sparsevec vector_type
|
||||||
REGRESS_OPTS = --inputdir=test --load-extension=$(EXTENSION)
|
REGRESS_OPTS = --inputdir=test --load-extension=$(EXTENSION)
|
||||||
|
|
||||||
# For /arch flags
|
# For /arch flags
|
||||||
|
|||||||
18
README.md
18
README.md
@@ -21,7 +21,7 @@ Compile and install the extension (supports Postgres 12+)
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd /tmp
|
cd /tmp
|
||||||
git clone --branch v0.7.0 https://github.com/pgvector/pgvector.git
|
git clone --branch v0.7.2 https://github.com/pgvector/pgvector.git
|
||||||
cd pgvector
|
cd pgvector
|
||||||
make
|
make
|
||||||
make install # may need sudo
|
make install # may need sudo
|
||||||
@@ -46,7 +46,7 @@ Then use `nmake` to build:
|
|||||||
```cmd
|
```cmd
|
||||||
set "PGROOT=C:\Program Files\PostgreSQL\16"
|
set "PGROOT=C:\Program Files\PostgreSQL\16"
|
||||||
cd %TEMP%
|
cd %TEMP%
|
||||||
git clone --branch v0.7.0 https://github.com/pgvector/pgvector.git
|
git clone --branch v0.7.2 https://github.com/pgvector/pgvector.git
|
||||||
cd pgvector
|
cd pgvector
|
||||||
nmake /F Makefile.win
|
nmake /F Makefile.win
|
||||||
nmake /F Makefile.win install
|
nmake /F Makefile.win install
|
||||||
@@ -217,6 +217,8 @@ L2 distance
|
|||||||
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);
|
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note: Use `halfvec_l2_ops` for `halfvec` and `sparsevec_l2_ops` for `sparsevec` (and similar with the other distance functions)
|
||||||
|
|
||||||
Inner product
|
Inner product
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
@@ -345,6 +347,8 @@ L2 distance
|
|||||||
CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 100);
|
CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 100);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note: Use `halfvec_l2_ops` for `halfvec` (and similar with the other distance functions)
|
||||||
|
|
||||||
Inner product
|
Inner product
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
@@ -455,7 +459,7 @@ CREATE TABLE items (id bigserial PRIMARY KEY, embedding halfvec(3));
|
|||||||
|
|
||||||
*Added in 0.7.0*
|
*Added in 0.7.0*
|
||||||
|
|
||||||
Index vectors at half precision for smaller indexes and faster build times
|
Index vectors at half precision for smaller indexes
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE INDEX ON items USING hnsw ((embedding::halfvec(3)) halfvec_l2_ops);
|
CREATE INDEX ON items USING hnsw ((embedding::halfvec(3)) halfvec_l2_ops);
|
||||||
@@ -727,7 +731,7 @@ Yes, pgvector uses the write-ahead log (WAL), which allows for replication and p
|
|||||||
|
|
||||||
#### What if I want to index vectors with more than 2,000 dimensions?
|
#### What if I want to index vectors with more than 2,000 dimensions?
|
||||||
|
|
||||||
You’ll need to use [dimensionality reduction](https://en.wikipedia.org/wiki/Dimensionality_reduction) at the moment.
|
You can use [half-precision indexing](#half-precision-indexing) to index up to 4,000 dimensions or [binary quantization](#binary-quantization) to index up to 64,000 dimensions. Another option is [dimensionality reduction](https://en.wikipedia.org/wiki/Dimensionality_reduction).
|
||||||
|
|
||||||
#### Can I store vectors with different dimensions in the same column?
|
#### Can I store vectors with different dimensions in the same column?
|
||||||
|
|
||||||
@@ -790,7 +794,7 @@ SELECT pg_size_pretty(pg_relation_size('index_name'));
|
|||||||
|
|
||||||
#### Why isn’t a query using an index?
|
#### Why isn’t a query using an index?
|
||||||
|
|
||||||
The query needs to have an `ORDER BY` and `LIMIT`, and the `ORDER BY` must be the result of a distance operator, not an expression.
|
The query needs to have an `ORDER BY` and `LIMIT`, and the `ORDER BY` must be the result of a distance operator (not an expression) in ascending order.
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
-- index
|
-- index
|
||||||
@@ -1047,9 +1051,9 @@ This adds pgvector to the [Postgres image](https://hub.docker.com/_/postgres) (r
|
|||||||
You can also build the image manually:
|
You can also build the image manually:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone --branch v0.7.0 https://github.com/pgvector/pgvector.git
|
git clone --branch v0.7.2 https://github.com/pgvector/pgvector.git
|
||||||
cd pgvector
|
cd pgvector
|
||||||
docker build --build-arg PG_MAJOR=16 -t myuser/pgvector .
|
docker build --pull --build-arg PG_MAJOR=16 -t myuser/pgvector .
|
||||||
```
|
```
|
||||||
|
|
||||||
### Homebrew
|
### Homebrew
|
||||||
|
|||||||
2
sql/vector--0.7.0--0.7.1.sql
Normal file
2
sql/vector--0.7.0--0.7.1.sql
Normal 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.7.1'" to load this file. \quit
|
||||||
2
sql/vector--0.7.1--0.7.2.sql
Normal file
2
sql/vector--0.7.1--0.7.2.sql
Normal 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.7.2'" to load this file. \quit
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
#ifdef BIT_DISPATCH
|
#ifdef BIT_DISPATCH
|
||||||
#include <immintrin.h>
|
#include <immintrin.h>
|
||||||
|
|
||||||
#if defined(HAVE__GET_CPUID)
|
#if defined(USE__GET_CPUID)
|
||||||
#include <cpuid.h>
|
#include <cpuid.h>
|
||||||
#else
|
#else
|
||||||
#include <intrin.h>
|
#include <intrin.h>
|
||||||
@@ -173,7 +173,7 @@ SupportsAvx512Popcount()
|
|||||||
{
|
{
|
||||||
unsigned int exx[4] = {0, 0, 0, 0};
|
unsigned int exx[4] = {0, 0, 0, 0};
|
||||||
|
|
||||||
#if defined(HAVE__GET_CPUID)
|
#if defined(USE__GET_CPUID)
|
||||||
__get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
|
__get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
|
||||||
#else
|
#else
|
||||||
__cpuid(exx, 1);
|
__cpuid(exx, 1);
|
||||||
@@ -187,7 +187,7 @@ SupportsAvx512Popcount()
|
|||||||
if ((_xgetbv(0) & 0xe6) != 0xe6)
|
if ((_xgetbv(0) & 0xe6) != 0xe6)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
#if defined(HAVE__GET_CPUID)
|
#if defined(USE__GET_CPUID)
|
||||||
__get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
|
__get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
|
||||||
#else
|
#else
|
||||||
__cpuidex(exx, 7, 0);
|
__cpuidex(exx, 7, 0);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#ifdef HALFVEC_DISPATCH
|
#ifdef HALFVEC_DISPATCH
|
||||||
#include <immintrin.h>
|
#include <immintrin.h>
|
||||||
|
|
||||||
#if defined(HAVE__GET_CPUID)
|
#if defined(USE__GET_CPUID)
|
||||||
#include <cpuid.h>
|
#include <cpuid.h>
|
||||||
#else
|
#else
|
||||||
#include <intrin.h>
|
#include <intrin.h>
|
||||||
@@ -254,7 +254,7 @@ SupportsCpuFeature(unsigned int feature)
|
|||||||
{
|
{
|
||||||
unsigned int exx[4] = {0, 0, 0, 0};
|
unsigned int exx[4] = {0, 0, 0, 0};
|
||||||
|
|
||||||
#if defined(HAVE__GET_CPUID)
|
#if defined(USE__GET_CPUID)
|
||||||
__get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
|
__get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
|
||||||
#else
|
#else
|
||||||
__cpuid(exx, 1);
|
__cpuid(exx, 1);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
/* TODO Move to better place */
|
/* TODO Move to better place */
|
||||||
#ifndef DISABLE_DISPATCH
|
#ifndef DISABLE_DISPATCH
|
||||||
/* Only enable for more recent compilers to keep build process simple */
|
/* Only enable for more recent compilers to keep build process simple */
|
||||||
#if defined(__x86_64__) && defined(__GNUC__) && __GNUC__ >= 8
|
#if defined(__x86_64__) && defined(__GNUC__) && __GNUC__ >= 9
|
||||||
#define USE_DISPATCH
|
#define USE_DISPATCH
|
||||||
#elif defined(__x86_64__) && defined(__clang_major__) && __clang_major__ >= 7
|
#elif defined(__x86_64__) && defined(__clang_major__) && __clang_major__ >= 7
|
||||||
#define USE_DISPATCH
|
#define USE_DISPATCH
|
||||||
@@ -19,9 +19,17 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* target_clones requires glibc */
|
/* target_clones requires glibc */
|
||||||
#if defined(USE_DISPATCH) && defined(__gnu_linux__)
|
#if defined(USE_DISPATCH) && defined(__gnu_linux__) && defined(__has_attribute)
|
||||||
|
/* Use separate line for portability */
|
||||||
|
#if __has_attribute(target_clones)
|
||||||
#define USE_TARGET_CLONES
|
#define USE_TARGET_CLONES
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Apple clang check needed for universal binaries on Mac */
|
||||||
|
#if defined(USE_DISPATCH) && (defined(HAVE__GET_CPUID) || defined(__apple_build_version__))
|
||||||
|
#define USE__GET_CPUID
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(USE_DISPATCH)
|
#if defined(USE_DISPATCH)
|
||||||
#define HALFVEC_DISPATCH
|
#define HALFVEC_DISPATCH
|
||||||
|
|||||||
@@ -393,7 +393,7 @@ void HnswInitNeighbors(char *base, HnswElement element, int m, HnswAllocator *
|
|||||||
bool HnswInsertTupleOnDisk(Relation index, Datum value, Datum *values, bool *isnull, ItemPointer heap_tid, bool building);
|
bool HnswInsertTupleOnDisk(Relation index, Datum value, Datum *values, bool *isnull, ItemPointer heap_tid, bool building);
|
||||||
void HnswUpdateNeighborsOnDisk(Relation index, FmgrInfo *procinfo, Oid collation, HnswElement e, int m, bool checkExisting, bool building);
|
void HnswUpdateNeighborsOnDisk(Relation index, FmgrInfo *procinfo, Oid collation, HnswElement e, int m, bool checkExisting, bool building);
|
||||||
void HnswLoadElementFromTuple(HnswElement element, HnswElementTuple etup, bool loadHeaptids, bool loadVec);
|
void HnswLoadElementFromTuple(HnswElement element, HnswElementTuple etup, bool loadHeaptids, bool loadVec);
|
||||||
void HnswLoadElement(HnswElement element, float *distance, Datum *q, Relation index, FmgrInfo *procinfo, Oid collation, bool loadVec);
|
void HnswLoadElement(HnswElement element, float *distance, Datum *q, Relation index, FmgrInfo *procinfo, Oid collation, bool loadVec, float *maxDistance);
|
||||||
void HnswSetElementTuple(char *base, HnswElementTuple etup, HnswElement element);
|
void HnswSetElementTuple(char *base, HnswElementTuple etup, HnswElement element);
|
||||||
void HnswUpdateConnection(char *base, HnswElement element, HnswCandidate * hc, int lm, int lc, int *updateIdx, Relation index, FmgrInfo *procinfo, Oid collation);
|
void HnswUpdateConnection(char *base, HnswElement element, HnswCandidate * hc, int lm, int lc, int *updateIdx, Relation index, FmgrInfo *procinfo, Oid collation);
|
||||||
void HnswLoadNeighbors(HnswElement element, Relation index, int m);
|
void HnswLoadNeighbors(HnswElement element, Relation index, int m);
|
||||||
|
|||||||
@@ -1121,8 +1121,8 @@ BuildIndex(Relation heap, Relation index, IndexInfo *indexInfo,
|
|||||||
|
|
||||||
BuildGraph(buildstate, forkNum);
|
BuildGraph(buildstate, forkNum);
|
||||||
|
|
||||||
if (RelationNeedsWAL(index))
|
if (RelationNeedsWAL(index) || forkNum == INIT_FORKNUM)
|
||||||
log_newpage_range(index, forkNum, 0, RelationGetNumberOfBlocks(index), true);
|
log_newpage_range(index, forkNum, 0, RelationGetNumberOfBlocksInFork(index, forkNum), true);
|
||||||
|
|
||||||
FreeBuildState(buildstate);
|
FreeBuildState(buildstate);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -300,6 +300,9 @@ HnswGetMetaPageInfo(Relation index, int *m, HnswElement * entryPoint)
|
|||||||
page = BufferGetPage(buf);
|
page = BufferGetPage(buf);
|
||||||
metap = HnswPageGetMeta(page);
|
metap = HnswPageGetMeta(page);
|
||||||
|
|
||||||
|
if (unlikely(metap->magicNumber != HNSW_MAGIC_NUMBER))
|
||||||
|
elog(ERROR, "hnsw index is not valid");
|
||||||
|
|
||||||
if (m != NULL)
|
if (m != NULL)
|
||||||
*m = metap->m;
|
*m = metap->m;
|
||||||
|
|
||||||
@@ -545,7 +548,7 @@ HnswLoadElementFromTuple(HnswElement element, HnswElementTuple etup, bool loadHe
|
|||||||
* Load an element and optionally get its distance from q
|
* Load an element and optionally get its distance from q
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
HnswLoadElement(HnswElement element, float *distance, Datum *q, Relation index, FmgrInfo *procinfo, Oid collation, bool loadVec)
|
HnswLoadElement(HnswElement element, float *distance, Datum *q, Relation index, FmgrInfo *procinfo, Oid collation, bool loadVec, float *maxDistance)
|
||||||
{
|
{
|
||||||
Buffer buf;
|
Buffer buf;
|
||||||
Page page;
|
Page page;
|
||||||
@@ -560,9 +563,6 @@ HnswLoadElement(HnswElement element, float *distance, Datum *q, Relation index,
|
|||||||
|
|
||||||
Assert(HnswIsElementTuple(etup));
|
Assert(HnswIsElementTuple(etup));
|
||||||
|
|
||||||
/* Load element */
|
|
||||||
HnswLoadElementFromTuple(element, etup, true, loadVec);
|
|
||||||
|
|
||||||
/* Calculate distance */
|
/* Calculate distance */
|
||||||
if (distance != NULL)
|
if (distance != NULL)
|
||||||
{
|
{
|
||||||
@@ -572,6 +572,10 @@ HnswLoadElement(HnswElement element, float *distance, Datum *q, Relation index,
|
|||||||
*distance = (float) DatumGetFloat8(FunctionCall2Coll(procinfo, collation, *q, PointerGetDatum(&etup->data)));
|
*distance = (float) DatumGetFloat8(FunctionCall2Coll(procinfo, collation, *q, PointerGetDatum(&etup->data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Load element */
|
||||||
|
if (distance == NULL || maxDistance == NULL || *distance < *maxDistance)
|
||||||
|
HnswLoadElementFromTuple(element, etup, true, loadVec);
|
||||||
|
|
||||||
UnlockReleaseBuffer(buf);
|
UnlockReleaseBuffer(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -599,7 +603,7 @@ HnswEntryCandidate(char *base, HnswElement entryPoint, Datum q, Relation index,
|
|||||||
if (index == NULL)
|
if (index == NULL)
|
||||||
hc->distance = GetCandidateDistance(base, hc, q, procinfo, collation);
|
hc->distance = GetCandidateDistance(base, hc, q, procinfo, collation);
|
||||||
else
|
else
|
||||||
HnswLoadElement(entryPoint, &hc->distance, &q, index, procinfo, collation, loadVec);
|
HnswLoadElement(entryPoint, &hc->distance, &q, index, procinfo, collation, loadVec, NULL);
|
||||||
return hc;
|
return hc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -795,25 +799,27 @@ HnswSearchLayer(char *base, Datum q, List *ep, int ef, int lc, Relation index, F
|
|||||||
{
|
{
|
||||||
float eDistance;
|
float eDistance;
|
||||||
HnswElement eElement = HnswPtrAccess(base, e->element);
|
HnswElement eElement = HnswPtrAccess(base, e->element);
|
||||||
|
bool alwaysAdd = wlen < ef;
|
||||||
|
|
||||||
f = ((HnswPairingHeapNode *) pairingheap_first(W))->inner;
|
f = ((HnswPairingHeapNode *) pairingheap_first(W))->inner;
|
||||||
|
|
||||||
if (index == NULL)
|
if (index == NULL)
|
||||||
eDistance = GetCandidateDistance(base, e, q, procinfo, collation);
|
eDistance = GetCandidateDistance(base, e, q, procinfo, collation);
|
||||||
else
|
else
|
||||||
HnswLoadElement(eElement, &eDistance, &q, index, procinfo, collation, inserting);
|
HnswLoadElement(eElement, &eDistance, &q, index, procinfo, collation, inserting, alwaysAdd ? NULL : &f->distance);
|
||||||
|
|
||||||
Assert(!eElement->deleted);
|
if (eDistance < f->distance || alwaysAdd)
|
||||||
|
|
||||||
/* Make robust to issues */
|
|
||||||
if (eElement->level < lc)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (eDistance < f->distance || wlen < ef)
|
|
||||||
{
|
{
|
||||||
/* Copy e */
|
HnswCandidate *ec;
|
||||||
HnswCandidate *ec = palloc(sizeof(HnswCandidate));
|
|
||||||
|
|
||||||
|
Assert(!eElement->deleted);
|
||||||
|
|
||||||
|
/* Make robust to issues */
|
||||||
|
if (eElement->level < lc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Copy e */
|
||||||
|
ec = palloc(sizeof(HnswCandidate));
|
||||||
HnswPtrStore(base, ec->element, eElement);
|
HnswPtrStore(base, ec->element, eElement);
|
||||||
ec->distance = eDistance;
|
ec->distance = eDistance;
|
||||||
|
|
||||||
@@ -1102,7 +1108,7 @@ HnswUpdateConnection(char *base, HnswElement element, HnswCandidate * hc, int lm
|
|||||||
HnswElement hc3Element = HnswPtrAccess(base, hc3->element);
|
HnswElement hc3Element = HnswPtrAccess(base, hc3->element);
|
||||||
|
|
||||||
if (HnswPtrIsNull(base, hc3Element->value))
|
if (HnswPtrIsNull(base, hc3Element->value))
|
||||||
HnswLoadElement(hc3Element, &hc3->distance, &q, index, procinfo, collation, true);
|
HnswLoadElement(hc3Element, &hc3->distance, &q, index, procinfo, collation, true, NULL);
|
||||||
else
|
else
|
||||||
hc3->distance = GetCandidateDistance(base, hc3, q, procinfo, collation);
|
hc3->distance = GetCandidateDistance(base, hc3, q, procinfo, collation);
|
||||||
|
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ RepairGraphEntryPoint(HnswVacuumState * vacuumstate)
|
|||||||
LockPage(index, HNSW_UPDATE_LOCK, ShareLock);
|
LockPage(index, HNSW_UPDATE_LOCK, ShareLock);
|
||||||
|
|
||||||
/* Load element */
|
/* Load element */
|
||||||
HnswLoadElement(highestPoint, NULL, NULL, index, vacuumstate->procinfo, vacuumstate->collation, true);
|
HnswLoadElement(highestPoint, NULL, NULL, index, vacuumstate->procinfo, vacuumstate->collation, true, NULL);
|
||||||
|
|
||||||
/* Repair if needed */
|
/* Repair if needed */
|
||||||
if (NeedsUpdated(vacuumstate, highestPoint))
|
if (NeedsUpdated(vacuumstate, highestPoint))
|
||||||
@@ -294,7 +294,7 @@ RepairGraphEntryPoint(HnswVacuumState * vacuumstate)
|
|||||||
* is outdated, this can remove connections at higher levels in
|
* is outdated, this can remove connections at higher levels in
|
||||||
* the graph until they are repaired, but this should be fine.
|
* the graph until they are repaired, but this should be fine.
|
||||||
*/
|
*/
|
||||||
HnswLoadElement(entryPoint, NULL, NULL, index, vacuumstate->procinfo, vacuumstate->collation, true);
|
HnswLoadElement(entryPoint, NULL, NULL, index, vacuumstate->procinfo, vacuumstate->collation, true, NULL);
|
||||||
|
|
||||||
if (NeedsUpdated(vacuumstate, entryPoint))
|
if (NeedsUpdated(vacuumstate, entryPoint))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1006,6 +1006,10 @@ BuildIndex(Relation heap, Relation index, IndexInfo *indexInfo,
|
|||||||
CreateListPages(index, buildstate->centers, buildstate->dimensions, buildstate->lists, forkNum, &buildstate->listInfo);
|
CreateListPages(index, buildstate->centers, buildstate->dimensions, buildstate->lists, forkNum, &buildstate->listInfo);
|
||||||
CreateEntryPages(buildstate, forkNum);
|
CreateEntryPages(buildstate, forkNum);
|
||||||
|
|
||||||
|
/* Write WAL for initialization fork since GenericXLog functions do not */
|
||||||
|
if (forkNum == INIT_FORKNUM)
|
||||||
|
log_newpage_range(index, forkNum, 0, RelationGetNumberOfBlocksInFork(index, forkNum), true);
|
||||||
|
|
||||||
FreeBuildState(buildstate);
|
FreeBuildState(buildstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -94,6 +94,9 @@ InsertTuple(Relation index, Datum *values, bool *isnull, ItemPointer heap_tid, R
|
|||||||
value = IvfflatNormValue(typeInfo, collation, value);
|
value = IvfflatNormValue(typeInfo, collation, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensure index is valid */
|
||||||
|
IvfflatGetMetaPageInfo(index, NULL, NULL);
|
||||||
|
|
||||||
/* Find the insert page - sets the page and list info */
|
/* Find the insert page - sets the page and list info */
|
||||||
FindInsertPage(index, values, &insertPage, &listInfo);
|
FindInsertPage(index, values, &insertPage, &listInfo);
|
||||||
Assert(BlockNumberIsValid(insertPage));
|
Assert(BlockNumberIsValid(insertPage));
|
||||||
|
|||||||
@@ -170,7 +170,11 @@ IvfflatGetMetaPageInfo(Relation index, int *lists, int *dimensions)
|
|||||||
page = BufferGetPage(buf);
|
page = BufferGetPage(buf);
|
||||||
metap = IvfflatPageGetMeta(page);
|
metap = IvfflatPageGetMeta(page);
|
||||||
|
|
||||||
*lists = metap->lists;
|
if (unlikely(metap->magicNumber != IVFFLAT_MAGIC_NUMBER))
|
||||||
|
elog(ERROR, "ivfflat index is not valid");
|
||||||
|
|
||||||
|
if (lists != NULL)
|
||||||
|
*lists = metap->lists;
|
||||||
|
|
||||||
if (dimensions != NULL)
|
if (dimensions != NULL)
|
||||||
*dimensions = metap->dimensions;
|
*dimensions = metap->dimensions;
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
|
||||||
\echo Use "CREATE EXTENSION vector" to load this file. \quit
|
|
||||||
Use "CREATE EXTENSION vector" to load this file.
|
|
||||||
672
test/expected/vector_type.out
Normal file
672
test/expected/vector_type.out
Normal file
@@ -0,0 +1,672 @@
|
|||||||
|
SELECT '[1,2,3]'::vector;
|
||||||
|
vector
|
||||||
|
---------
|
||||||
|
[1,2,3]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[-1,-2,-3]'::vector;
|
||||||
|
vector
|
||||||
|
------------
|
||||||
|
[-1,-2,-3]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1.,2.,3.]'::vector;
|
||||||
|
vector
|
||||||
|
---------
|
||||||
|
[1,2,3]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT ' [ 1, 2 , 3 ] '::vector;
|
||||||
|
vector
|
||||||
|
---------
|
||||||
|
[1,2,3]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1.23456]'::vector;
|
||||||
|
vector
|
||||||
|
-----------
|
||||||
|
[1.23456]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[hello,1]'::vector;
|
||||||
|
ERROR: invalid input syntax for type vector: "[hello,1]"
|
||||||
|
LINE 1: SELECT '[hello,1]'::vector;
|
||||||
|
^
|
||||||
|
SELECT '[NaN,1]'::vector;
|
||||||
|
ERROR: NaN not allowed in vector
|
||||||
|
LINE 1: SELECT '[NaN,1]'::vector;
|
||||||
|
^
|
||||||
|
SELECT '[Infinity,1]'::vector;
|
||||||
|
ERROR: infinite value not allowed in vector
|
||||||
|
LINE 1: SELECT '[Infinity,1]'::vector;
|
||||||
|
^
|
||||||
|
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: "4e38" is out of range for type vector
|
||||||
|
LINE 1: SELECT '[4e38,1]'::vector;
|
||||||
|
^
|
||||||
|
SELECT '[-4e38,1]'::vector;
|
||||||
|
ERROR: "-4e38" is out of range for type vector
|
||||||
|
LINE 1: SELECT '[-4e38,1]'::vector;
|
||||||
|
^
|
||||||
|
SELECT '[1e-46,1]'::vector;
|
||||||
|
vector
|
||||||
|
--------
|
||||||
|
[0,1]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[-1e-46,1]'::vector;
|
||||||
|
vector
|
||||||
|
--------
|
||||||
|
[-0,1]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1,2,3'::vector;
|
||||||
|
ERROR: invalid input syntax for type vector: "[1,2,3"
|
||||||
|
LINE 1: SELECT '[1,2,3'::vector;
|
||||||
|
^
|
||||||
|
SELECT '[1,2,3]9'::vector;
|
||||||
|
ERROR: invalid input syntax for type vector: "[1,2,3]9"
|
||||||
|
LINE 1: SELECT '[1,2,3]9'::vector;
|
||||||
|
^
|
||||||
|
DETAIL: Junk after closing right brace.
|
||||||
|
SELECT '1,2,3'::vector;
|
||||||
|
ERROR: invalid input syntax for type vector: "1,2,3"
|
||||||
|
LINE 1: SELECT '1,2,3'::vector;
|
||||||
|
^
|
||||||
|
DETAIL: Vector contents must start with "[".
|
||||||
|
SELECT ''::vector;
|
||||||
|
ERROR: invalid input syntax for type vector: ""
|
||||||
|
LINE 1: SELECT ''::vector;
|
||||||
|
^
|
||||||
|
DETAIL: Vector contents must start with "[".
|
||||||
|
SELECT '['::vector;
|
||||||
|
ERROR: invalid input syntax for type vector: "["
|
||||||
|
LINE 1: SELECT '['::vector;
|
||||||
|
^
|
||||||
|
SELECT '[ '::vector;
|
||||||
|
ERROR: invalid input syntax for type vector: "[ "
|
||||||
|
LINE 1: SELECT '[ '::vector;
|
||||||
|
^
|
||||||
|
SELECT '[,'::vector;
|
||||||
|
ERROR: invalid input syntax for type vector: "[,"
|
||||||
|
LINE 1: SELECT '[,'::vector;
|
||||||
|
^
|
||||||
|
SELECT '[]'::vector;
|
||||||
|
ERROR: vector must have at least 1 dimension
|
||||||
|
LINE 1: SELECT '[]'::vector;
|
||||||
|
^
|
||||||
|
SELECT '[ ]'::vector;
|
||||||
|
ERROR: vector must have at least 1 dimension
|
||||||
|
LINE 1: SELECT '[ ]'::vector;
|
||||||
|
^
|
||||||
|
SELECT '[,]'::vector;
|
||||||
|
ERROR: invalid input syntax for type vector: "[,]"
|
||||||
|
LINE 1: SELECT '[,]'::vector;
|
||||||
|
^
|
||||||
|
SELECT '[1,]'::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: invalid input syntax for type vector: "[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(3);
|
||||||
|
vector
|
||||||
|
---------
|
||||||
|
[1,2,3]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1,2,3]'::vector(2);
|
||||||
|
ERROR: expected 2 dimensions, not 3
|
||||||
|
SELECT '[1,2,3]'::vector(3, 2);
|
||||||
|
ERROR: invalid type modifier
|
||||||
|
LINE 1: SELECT '[1,2,3]'::vector(3, 2);
|
||||||
|
^
|
||||||
|
SELECT '[1,2,3]'::vector('a');
|
||||||
|
ERROR: invalid input syntax for type integer: "a"
|
||||||
|
LINE 1: SELECT '[1,2,3]'::vector('a');
|
||||||
|
^
|
||||||
|
SELECT '[1,2,3]'::vector(0);
|
||||||
|
ERROR: dimensions for type vector must be at least 1
|
||||||
|
LINE 1: SELECT '[1,2,3]'::vector(0);
|
||||||
|
^
|
||||||
|
SELECT '[1,2,3]'::vector(16001);
|
||||||
|
ERROR: dimensions for type vector cannot exceed 16000
|
||||||
|
LINE 1: SELECT '[1,2,3]'::vector(16001);
|
||||||
|
^
|
||||||
|
SELECT unnest('{"[1,2,3]", "[4,5,6]"}'::vector[]);
|
||||||
|
unnest
|
||||||
|
---------
|
||||||
|
[1,2,3]
|
||||||
|
[4,5,6]
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
SELECT '{"[1,2,3]"}'::vector(2)[];
|
||||||
|
ERROR: expected 2 dimensions, not 3
|
||||||
|
SELECT '[1,2,3]'::vector + '[4,5,6]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
[5,7,9]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[3e38]'::vector + '[3e38]';
|
||||||
|
ERROR: value out of range: overflow
|
||||||
|
SELECT '[1,2]'::vector + '[3]';
|
||||||
|
ERROR: different vector dimensions 2 and 1
|
||||||
|
SELECT '[1,2,3]'::vector - '[4,5,6]';
|
||||||
|
?column?
|
||||||
|
------------
|
||||||
|
[-3,-3,-3]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[-3e38]'::vector - '[3e38]';
|
||||||
|
ERROR: value out of range: overflow
|
||||||
|
SELECT '[1,2]'::vector - '[3]';
|
||||||
|
ERROR: different vector dimensions 2 and 1
|
||||||
|
SELECT '[1,2,3]'::vector * '[4,5,6]';
|
||||||
|
?column?
|
||||||
|
-----------
|
||||||
|
[4,10,18]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1e37]'::vector * '[1e37]';
|
||||||
|
ERROR: value out of range: overflow
|
||||||
|
SELECT '[1e-37]'::vector * '[1e-37]';
|
||||||
|
ERROR: value out of range: underflow
|
||||||
|
SELECT '[1,2]'::vector * '[3]';
|
||||||
|
ERROR: different vector dimensions 2 and 1
|
||||||
|
SELECT '[1,2,3]'::vector || '[4,5]';
|
||||||
|
?column?
|
||||||
|
-------------
|
||||||
|
[1,2,3,4,5]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT array_fill(0, ARRAY[16000])::vector || '[1]';
|
||||||
|
ERROR: vector cannot have more than 16000 dimensions
|
||||||
|
SELECT '[1,2,3]'::vector < '[1,2,3]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1,2,3]'::vector < '[1,2]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1,2,3]'::vector <= '[1,2,3]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1,2,3]'::vector <= '[1,2]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1,2,3]'::vector = '[1,2,3]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1,2,3]'::vector = '[1,2]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1,2,3]'::vector != '[1,2,3]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1,2,3]'::vector != '[1,2]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1,2,3]'::vector >= '[1,2,3]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1,2,3]'::vector >= '[1,2]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1,2,3]'::vector > '[1,2,3]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1,2,3]'::vector > '[1,2]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT vector_cmp('[1,2,3]', '[1,2,3]');
|
||||||
|
vector_cmp
|
||||||
|
------------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT vector_cmp('[1,2,3]', '[0,0,0]');
|
||||||
|
vector_cmp
|
||||||
|
------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT vector_cmp('[0,0,0]', '[1,2,3]');
|
||||||
|
vector_cmp
|
||||||
|
------------
|
||||||
|
-1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT vector_cmp('[1,2]', '[1,2,3]');
|
||||||
|
vector_cmp
|
||||||
|
------------
|
||||||
|
-1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT vector_cmp('[1,2,3]', '[1,2]');
|
||||||
|
vector_cmp
|
||||||
|
------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT vector_cmp('[1,2]', '[2,3,4]');
|
||||||
|
vector_cmp
|
||||||
|
------------
|
||||||
|
-1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT vector_cmp('[2,3]', '[1,2,3]');
|
||||||
|
vector_cmp
|
||||||
|
------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT vector_dims('[1,2,3]'::vector);
|
||||||
|
vector_dims
|
||||||
|
-------------
|
||||||
|
3
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT round(vector_norm('[1,1]')::numeric, 5);
|
||||||
|
round
|
||||||
|
---------
|
||||||
|
1.41421
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT vector_norm('[3,4]');
|
||||||
|
vector_norm
|
||||||
|
-------------
|
||||||
|
5
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT vector_norm('[0,1]');
|
||||||
|
vector_norm
|
||||||
|
-------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT vector_norm('[3e37,4e37]')::real;
|
||||||
|
vector_norm
|
||||||
|
-------------
|
||||||
|
5e+37
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT vector_norm('[0,0]');
|
||||||
|
vector_norm
|
||||||
|
-------------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT vector_norm('[2]');
|
||||||
|
vector_norm
|
||||||
|
-------------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l2_distance('[0,0]'::vector, '[3,4]');
|
||||||
|
l2_distance
|
||||||
|
-------------
|
||||||
|
5
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l2_distance('[0,0]'::vector, '[0,1]');
|
||||||
|
l2_distance
|
||||||
|
-------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l2_distance('[1,2]'::vector, '[3]');
|
||||||
|
ERROR: different vector dimensions 2 and 1
|
||||||
|
SELECT l2_distance('[3e38]'::vector, '[-3e38]');
|
||||||
|
l2_distance
|
||||||
|
-------------
|
||||||
|
Infinity
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l2_distance('[1,1,1,1,1,1,1,1,1]'::vector, '[1,1,1,1,1,1,1,4,5]');
|
||||||
|
l2_distance
|
||||||
|
-------------
|
||||||
|
5
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[0,0]'::vector <-> '[3,4]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
5
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT inner_product('[1,2]'::vector, '[3,4]');
|
||||||
|
inner_product
|
||||||
|
---------------
|
||||||
|
11
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT inner_product('[1,2]'::vector, '[3]');
|
||||||
|
ERROR: different vector dimensions 2 and 1
|
||||||
|
SELECT inner_product('[3e38]'::vector, '[3e38]');
|
||||||
|
inner_product
|
||||||
|
---------------
|
||||||
|
Infinity
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT inner_product('[1,1,1,1,1,1,1,1,1]'::vector, '[1,2,3,4,5,6,7,8,9]');
|
||||||
|
inner_product
|
||||||
|
---------------
|
||||||
|
45
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1,2]'::vector <#> '[3,4]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
-11
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT cosine_distance('[1,2]'::vector, '[2,4]');
|
||||||
|
cosine_distance
|
||||||
|
-----------------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT cosine_distance('[1,2]'::vector, '[0,0]');
|
||||||
|
cosine_distance
|
||||||
|
-----------------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT cosine_distance('[1,1]'::vector, '[1,1]');
|
||||||
|
cosine_distance
|
||||||
|
-----------------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT cosine_distance('[1,0]'::vector, '[0,2]');
|
||||||
|
cosine_distance
|
||||||
|
-----------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT cosine_distance('[1,1]'::vector, '[-1,-1]');
|
||||||
|
cosine_distance
|
||||||
|
-----------------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT cosine_distance('[1,2]'::vector, '[3]');
|
||||||
|
ERROR: different vector dimensions 2 and 1
|
||||||
|
SELECT cosine_distance('[1,1]'::vector, '[1.1,1.1]');
|
||||||
|
cosine_distance
|
||||||
|
-----------------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT cosine_distance('[1,1]'::vector, '[-1.1,-1.1]');
|
||||||
|
cosine_distance
|
||||||
|
-----------------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT cosine_distance('[3e38]'::vector, '[3e38]');
|
||||||
|
cosine_distance
|
||||||
|
-----------------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT cosine_distance('[1,2,3,4,5,6,7,8,9]'::vector, '[1,2,3,4,5,6,7,8,9]');
|
||||||
|
cosine_distance
|
||||||
|
-----------------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT cosine_distance('[1,2,3,4,5,6,7,8,9]'::vector, '[-1,-2,-3,-4,-5,-6,-7,-8,-9]');
|
||||||
|
cosine_distance
|
||||||
|
-----------------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[1,2]'::vector <=> '[2,4]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l1_distance('[0,0]'::vector, '[3,4]');
|
||||||
|
l1_distance
|
||||||
|
-------------
|
||||||
|
7
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l1_distance('[0,0]'::vector, '[0,1]');
|
||||||
|
l1_distance
|
||||||
|
-------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l1_distance('[1,2]'::vector, '[3]');
|
||||||
|
ERROR: different vector dimensions 2 and 1
|
||||||
|
SELECT l1_distance('[3e38]'::vector, '[-3e38]');
|
||||||
|
l1_distance
|
||||||
|
-------------
|
||||||
|
Infinity
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l1_distance('[1,2,3,4,5,6,7,8,9]'::vector, '[1,2,3,4,5,6,7,8,9]');
|
||||||
|
l1_distance
|
||||||
|
-------------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l1_distance('[1,2,3,4,5,6,7,8,9]'::vector, '[0,3,2,5,4,7,6,9,8]');
|
||||||
|
l1_distance
|
||||||
|
-------------
|
||||||
|
9
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT '[0,0]'::vector <+> '[3,4]';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
7
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l2_normalize('[3,4]'::vector);
|
||||||
|
l2_normalize
|
||||||
|
--------------
|
||||||
|
[0.6,0.8]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l2_normalize('[3,0]'::vector);
|
||||||
|
l2_normalize
|
||||||
|
--------------
|
||||||
|
[1,0]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l2_normalize('[0,0.1]'::vector);
|
||||||
|
l2_normalize
|
||||||
|
--------------
|
||||||
|
[0,1]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l2_normalize('[0,0]'::vector);
|
||||||
|
l2_normalize
|
||||||
|
--------------
|
||||||
|
[0,0]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT l2_normalize('[3e38]'::vector);
|
||||||
|
l2_normalize
|
||||||
|
--------------
|
||||||
|
[1]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT binary_quantize('[1,0,-1]'::vector);
|
||||||
|
binary_quantize
|
||||||
|
-----------------
|
||||||
|
100
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT binary_quantize('[0,0.1,-0.2,-0.3,0.4,0.5,0.6,-0.7,0.8,-0.9,1]'::vector);
|
||||||
|
binary_quantize
|
||||||
|
-----------------
|
||||||
|
01001110101
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT subvector('[1,2,3,4,5]'::vector, 1, 3);
|
||||||
|
subvector
|
||||||
|
-----------
|
||||||
|
[1,2,3]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT subvector('[1,2,3,4,5]'::vector, 3, 2);
|
||||||
|
subvector
|
||||||
|
-----------
|
||||||
|
[3,4]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT subvector('[1,2,3,4,5]'::vector, -1, 3);
|
||||||
|
subvector
|
||||||
|
-----------
|
||||||
|
[1]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT subvector('[1,2,3,4,5]'::vector, 3, 9);
|
||||||
|
subvector
|
||||||
|
-----------
|
||||||
|
[3,4,5]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT subvector('[1,2,3,4,5]'::vector, 1, 0);
|
||||||
|
ERROR: vector must have at least 1 dimension
|
||||||
|
SELECT subvector('[1,2,3,4,5]'::vector, 3, -1);
|
||||||
|
ERROR: vector must have at least 1 dimension
|
||||||
|
SELECT subvector('[1,2,3,4,5]'::vector, -1, 2);
|
||||||
|
ERROR: vector must have at least 1 dimension
|
||||||
|
SELECT subvector('[1,2,3,4,5]'::vector, 2147483647, 10);
|
||||||
|
ERROR: vector must have at least 1 dimension
|
||||||
|
SELECT subvector('[1,2,3,4,5]'::vector, 3, 2147483647);
|
||||||
|
subvector
|
||||||
|
-----------
|
||||||
|
[3,4,5]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT subvector('[1,2,3,4,5]'::vector, -2147483644, 2147483647);
|
||||||
|
subvector
|
||||||
|
-----------
|
||||||
|
[1,2]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT avg(v) FROM unnest(ARRAY['[1,2,3]'::vector, '[3,5,7]']) v;
|
||||||
|
avg
|
||||||
|
-----------
|
||||||
|
[2,3.5,5]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT avg(v) FROM unnest(ARRAY['[1,2,3]'::vector, '[3,5,7]', NULL]) v;
|
||||||
|
avg
|
||||||
|
-----------
|
||||||
|
[2,3.5,5]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT avg(v) FROM unnest(ARRAY[]::vector[]) v;
|
||||||
|
avg
|
||||||
|
-----
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT avg(v) FROM unnest(ARRAY['[1,2]'::vector, '[3]']) v;
|
||||||
|
ERROR: expected 2 dimensions, not 1
|
||||||
|
SELECT avg(v) FROM unnest(ARRAY['[3e38]'::vector, '[3e38]']) v;
|
||||||
|
avg
|
||||||
|
---------
|
||||||
|
[3e+38]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT vector_avg(array_agg(n)) FROM generate_series(1, 16002) n;
|
||||||
|
ERROR: vector cannot have more than 16000 dimensions
|
||||||
|
SELECT sum(v) FROM unnest(ARRAY['[1,2,3]'::vector, '[3,5,7]']) v;
|
||||||
|
sum
|
||||||
|
----------
|
||||||
|
[4,7,10]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT sum(v) FROM unnest(ARRAY['[1,2,3]'::vector, '[3,5,7]', NULL]) v;
|
||||||
|
sum
|
||||||
|
----------
|
||||||
|
[4,7,10]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT sum(v) FROM unnest(ARRAY[]::vector[]) v;
|
||||||
|
sum
|
||||||
|
-----
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT sum(v) FROM unnest(ARRAY['[1,2]'::vector, '[3]']) v;
|
||||||
|
ERROR: different vector dimensions 2 and 1
|
||||||
|
SELECT sum(v) FROM unnest(ARRAY['[3e38]'::vector, '[3e38]']) v;
|
||||||
|
ERROR: value out of range: overflow
|
||||||
@@ -91,7 +91,7 @@ for my $i (0 .. $#operators)
|
|||||||
));
|
));
|
||||||
|
|
||||||
# Test approximate results
|
# Test approximate results
|
||||||
my $min = $operator eq "<#>" ? 0.98 : 0.99;
|
my $min = $operator eq "<#>" ? 0.97 : 0.99;
|
||||||
test_recall($min, $operator);
|
test_recall($min, $operator);
|
||||||
|
|
||||||
$node->safe_psql("postgres", "DROP INDEX idx;");
|
$node->safe_psql("postgres", "DROP INDEX idx;");
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ for my $i (0 .. $#operators)
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Test approximate results
|
# Test approximate results
|
||||||
my $min = $operator eq "<#>" ? 0.98 : 0.99;
|
my $min = $operator eq "<#>" ? 0.97 : 0.99;
|
||||||
test_recall($min, $operator);
|
test_recall($min, $operator);
|
||||||
|
|
||||||
$node->safe_psql("postgres", "DROP INDEX idx;");
|
$node->safe_psql("postgres", "DROP INDEX idx;");
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ for my $i (0 .. $#operators)
|
|||||||
));
|
));
|
||||||
|
|
||||||
# Test approximate results
|
# Test approximate results
|
||||||
my $min = $operator eq "<#>" ? 0.98 : 0.99;
|
my $min = $operator eq "<#>" ? 0.97 : 0.99;
|
||||||
test_recall($min, $operator);
|
test_recall($min, $operator);
|
||||||
|
|
||||||
$node->safe_psql("postgres", "DROP INDEX idx;");
|
$node->safe_psql("postgres", "DROP INDEX idx;");
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ for my $i (0 .. $#operators)
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Test approximate results
|
# Test approximate results
|
||||||
my $min = $operator eq "<#>" ? 0.98 : 0.99;
|
my $min = $operator eq "<#>" ? 0.97 : 0.99;
|
||||||
test_recall($min, $operator);
|
test_recall($min, $operator);
|
||||||
|
|
||||||
$node->safe_psql("postgres", "DROP INDEX idx;");
|
$node->safe_psql("postgres", "DROP INDEX idx;");
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
comment = 'vector data type and ivfflat and hnsw access methods'
|
comment = 'vector data type and ivfflat and hnsw access methods'
|
||||||
default_version = '0.7.0'
|
default_version = '0.7.2'
|
||||||
module_pathname = '$libdir/vector'
|
module_pathname = '$libdir/vector'
|
||||||
relocatable = true
|
relocatable = true
|
||||||
|
|||||||
Reference in New Issue
Block a user