mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-10 14:46:56 +08:00
Improved performance of bit distance functions - #519
Co-authored-by: Nathan Bossart <nathan@postgresql.org> Co-authored-by: "Jonathan S. Katz" <jkatz@users.noreply.github.com>
This commit is contained in:
2
Makefile
2
Makefile
@@ -3,7 +3,7 @@ EXTVERSION = 0.6.2
|
|||||||
|
|
||||||
MODULE_big = vector
|
MODULE_big = vector
|
||||||
DATA = $(wildcard sql/*--*.sql)
|
DATA = $(wildcard sql/*--*.sql)
|
||||||
OBJS = src/bitvector.o src/halfutils.o src/halfvec.o src/hnsw.o src/hnswbuild.o src/hnswinsert.o src/hnswscan.o src/hnswutils.o src/hnswvacuum.o src/ivfbuild.o src/ivfflat.o src/ivfinsert.o src/ivfkmeans.o src/ivfscan.o src/ivfutils.o src/ivfvacuum.o src/sparsevec.o src/vector.o
|
OBJS = src/bitutils.o src/bitvector.o src/halfutils.o src/halfvec.o src/hnsw.o src/hnswbuild.o src/hnswinsert.o src/hnswscan.o src/hnswutils.o src/hnswvacuum.o src/ivfbuild.o src/ivfflat.o src/ivfinsert.o src/ivfkmeans.o src/ivfscan.o src/ivfutils.o src/ivfvacuum.o src/sparsevec.o src/vector.o
|
||||||
HEADERS = src/halfvec.h src/sparsevec.h src/vector.h
|
HEADERS = src/halfvec.h src/sparsevec.h src/vector.h
|
||||||
|
|
||||||
TESTS = $(wildcard test/sql/*.sql)
|
TESTS = $(wildcard test/sql/*.sql)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
EXTENSION = vector
|
EXTENSION = vector
|
||||||
EXTVERSION = 0.6.2
|
EXTVERSION = 0.6.2
|
||||||
|
|
||||||
OBJS = src\bitvector.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\bitvector.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_functions btree_halfvec btree_sparsevec btree_vector cast copy halfvec_functions halfvec_input hnsw_bit_hamming hnsw_bit_jaccard hnsw_halfvec_cosine hnsw_halfvec_ip hnsw_halfvec_l2 hnsw_options hnsw_sparsevec_cosine hnsw_sparsevec_ip hnsw_sparsevec_l2 hnsw_unlogged hnsw_vector_cosine hnsw_vector_ip hnsw_vector_l2 ivfflat_halfvec_cosine ivfflat_halfvec_ip ivfflat_halfvec_l2 ivfflat_options ivfflat_unlogged ivfflat_vector_cosine ivfflat_vector_ip ivfflat_vector_l2 sparsevec_functions sparsevec_input vector_functions vector_input
|
REGRESS = bit_functions btree_halfvec btree_sparsevec btree_vector cast copy halfvec_functions halfvec_input hnsw_bit_hamming hnsw_bit_jaccard hnsw_halfvec_cosine hnsw_halfvec_ip hnsw_halfvec_l2 hnsw_options hnsw_sparsevec_cosine hnsw_sparsevec_ip hnsw_sparsevec_l2 hnsw_unlogged hnsw_vector_cosine hnsw_vector_ip hnsw_vector_l2 ivfflat_halfvec_cosine ivfflat_halfvec_ip ivfflat_halfvec_l2 ivfflat_options ivfflat_unlogged ivfflat_vector_cosine ivfflat_vector_ip ivfflat_vector_l2 sparsevec_functions sparsevec_input vector_functions vector_input
|
||||||
|
|||||||
217
src/bitutils.c
Normal file
217
src/bitutils.c
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "bitutils.h"
|
||||||
|
#include "port/pg_bitutils.h"
|
||||||
|
|
||||||
|
#ifdef BIT_DISPATCH
|
||||||
|
#include <immintrin.h>
|
||||||
|
|
||||||
|
#if defined(HAVE__GET_CPUID)
|
||||||
|
#include <cpuid.h>
|
||||||
|
#else
|
||||||
|
#include <intrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define TARGET_AVX512_POPCOUNT
|
||||||
|
#else
|
||||||
|
#define TARGET_AVX512_POPCOUNT __attribute__((target("avx512f,avx512vpopcntdq")))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Disable for LLVM due to crash with bitcode generation */
|
||||||
|
#if defined(USE_TARGET_CLONES) && !defined(__POPCNT__) && !defined(__llvm__)
|
||||||
|
#define BIT_TARGET_CLONES __attribute__((target_clones("default", "popcnt")))
|
||||||
|
#else
|
||||||
|
#define BIT_TARGET_CLONES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Use built-ins when possible for inlining */
|
||||||
|
#if defined(HAVE__BUILTIN_POPCOUNT) && defined(HAVE_LONG_INT_64)
|
||||||
|
#define popcount64(x) __builtin_popcountl(x)
|
||||||
|
#elif defined(HAVE__BUILTIN_POPCOUNT) && defined(HAVE_LONG_LONG_INT_64)
|
||||||
|
#define popcount64(x) __builtin_popcountll(x)
|
||||||
|
#elif !defined(_MSC_VER)
|
||||||
|
/* Fails to resolve with MSVC */
|
||||||
|
#define popcount64(x) pg_popcount64(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint64 (*BitHammingDistance) (uint32 bytes, unsigned char *ax, unsigned char *bx, uint64 distance);
|
||||||
|
double (*BitJaccardDistance) (uint32 bytes, unsigned char *ax, unsigned char *bx, uint64 ab, uint64 aa, uint64 bb);
|
||||||
|
|
||||||
|
BIT_TARGET_CLONES static uint64
|
||||||
|
BitHammingDistanceDefault(uint32 bytes, unsigned char *ax, unsigned char *bx, uint64 distance)
|
||||||
|
{
|
||||||
|
#ifdef popcount64
|
||||||
|
for (; bytes >= sizeof(uint64); bytes -= sizeof(uint64))
|
||||||
|
{
|
||||||
|
uint64 axs;
|
||||||
|
uint64 bxs;
|
||||||
|
|
||||||
|
/* Ensure aligned */
|
||||||
|
memcpy(&axs, ax, sizeof(uint64));
|
||||||
|
memcpy(&bxs, bx, sizeof(uint64));
|
||||||
|
|
||||||
|
distance += popcount64(axs ^ bxs);
|
||||||
|
|
||||||
|
ax += sizeof(uint64);
|
||||||
|
bx += sizeof(uint64);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < bytes; i++)
|
||||||
|
distance += pg_number_of_ones[ax[i] ^ bx[i]];
|
||||||
|
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BIT_DISPATCH
|
||||||
|
TARGET_AVX512_POPCOUNT static uint64
|
||||||
|
BitHammingDistanceAvx512Popcount(uint32 bytes, unsigned char *ax, unsigned char *bx, uint64 distance)
|
||||||
|
{
|
||||||
|
__m512i dist = _mm512_setzero_si512();
|
||||||
|
|
||||||
|
for (; bytes >= sizeof(__m512i); bytes -= sizeof(__m512i))
|
||||||
|
{
|
||||||
|
__m512i axs = _mm512_loadu_si512((const __m512i *) ax);
|
||||||
|
__m512i bxs = _mm512_loadu_si512((const __m512i *) bx);
|
||||||
|
|
||||||
|
dist = _mm512_add_epi64(dist, _mm512_popcnt_epi64(_mm512_xor_si512(axs, bxs)));
|
||||||
|
|
||||||
|
ax += sizeof(__m512i);
|
||||||
|
bx += sizeof(__m512i);
|
||||||
|
}
|
||||||
|
|
||||||
|
distance += _mm512_reduce_add_epi64(dist);
|
||||||
|
|
||||||
|
return BitHammingDistanceDefault(bytes, ax, bx, distance);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BIT_TARGET_CLONES static double
|
||||||
|
BitJaccardDistanceDefault(uint32 bytes, unsigned char *ax, unsigned char *bx, uint64 ab, uint64 aa, uint64 bb)
|
||||||
|
{
|
||||||
|
#ifdef popcount64
|
||||||
|
for (; bytes >= sizeof(uint64); bytes -= sizeof(uint64))
|
||||||
|
{
|
||||||
|
uint64 axs;
|
||||||
|
uint64 bxs;
|
||||||
|
|
||||||
|
/* Ensure aligned */
|
||||||
|
memcpy(&axs, ax, sizeof(uint64));
|
||||||
|
memcpy(&bxs, bx, sizeof(uint64));
|
||||||
|
|
||||||
|
ab += popcount64(axs & bxs);
|
||||||
|
aa += popcount64(axs);
|
||||||
|
bb += popcount64(bxs);
|
||||||
|
|
||||||
|
ax += sizeof(uint64);
|
||||||
|
bx += sizeof(uint64);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < bytes; i++)
|
||||||
|
{
|
||||||
|
ab += pg_number_of_ones[ax[i] & bx[i]];
|
||||||
|
aa += pg_number_of_ones[ax[i]];
|
||||||
|
bb += pg_number_of_ones[bx[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ab == 0)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 1 - (ab / ((double) (aa + bb - ab)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BIT_DISPATCH
|
||||||
|
TARGET_AVX512_POPCOUNT static double
|
||||||
|
BitJaccardDistanceAvx512Popcount(uint32 bytes, unsigned char *ax, unsigned char *bx, uint64 ab, uint64 aa, uint64 bb)
|
||||||
|
{
|
||||||
|
__m512i abx = _mm512_setzero_si512();
|
||||||
|
__m512i aax = _mm512_setzero_si512();
|
||||||
|
__m512i bbx = _mm512_setzero_si512();
|
||||||
|
|
||||||
|
for (; bytes >= sizeof(__m512i); bytes -= sizeof(__m512i))
|
||||||
|
{
|
||||||
|
__m512i axs = _mm512_loadu_si512((const __m512i *) ax);
|
||||||
|
__m512i bxs = _mm512_loadu_si512((const __m512i *) bx);
|
||||||
|
|
||||||
|
abx = _mm512_add_epi64(abx, _mm512_popcnt_epi64(_mm512_and_si512(axs, bxs)));
|
||||||
|
aax = _mm512_add_epi64(aax, _mm512_popcnt_epi64(axs));
|
||||||
|
bbx = _mm512_add_epi64(bbx, _mm512_popcnt_epi64(bxs));
|
||||||
|
|
||||||
|
ax += sizeof(__m512i);
|
||||||
|
bx += sizeof(__m512i);
|
||||||
|
}
|
||||||
|
|
||||||
|
ab += _mm512_reduce_add_epi64(abx);
|
||||||
|
aa += _mm512_reduce_add_epi64(aax);
|
||||||
|
bb += _mm512_reduce_add_epi64(bbx);
|
||||||
|
|
||||||
|
return BitJaccardDistanceDefault(bytes, ax, bx, ab, aa, bb);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BIT_DISPATCH
|
||||||
|
#define CPU_FEATURE_OSXSAVE (1 << 27) /* F1 ECX */
|
||||||
|
#define CPU_FEATURE_AVX512F (1 << 16) /* F7,0 EBX */
|
||||||
|
#define CPU_FEATURE_AVX512VPOPCNTDQ (1 << 14) /* F7,0 ECX */
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define TARGET_XSAVE
|
||||||
|
#else
|
||||||
|
#define TARGET_XSAVE __attribute__((target("xsave")))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TARGET_XSAVE static bool
|
||||||
|
SupportsAvx512Popcount()
|
||||||
|
{
|
||||||
|
unsigned int exx[4] = {0, 0, 0, 0};
|
||||||
|
|
||||||
|
#if defined(HAVE__GET_CPUID)
|
||||||
|
__get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
|
||||||
|
#else
|
||||||
|
__cpuid(exx, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check OS supports XSAVE */
|
||||||
|
if ((exx[2] & CPU_FEATURE_OSXSAVE) != CPU_FEATURE_OSXSAVE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Check XMM, YMM, and ZMM registers are enabled */
|
||||||
|
if ((_xgetbv(0) & 0xe6) != 0xe6)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#if defined(HAVE__GET_CPUID)
|
||||||
|
__get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
|
||||||
|
#else
|
||||||
|
__cpuidex(exx, 7, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check AVX512F */
|
||||||
|
if ((exx[1] & CPU_FEATURE_AVX512F) != CPU_FEATURE_AVX512F)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Check AVX512VPOPCNTDQ */
|
||||||
|
return (exx[2] & CPU_FEATURE_AVX512VPOPCNTDQ) == CPU_FEATURE_AVX512VPOPCNTDQ;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
BitvecInit(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Could skip pointer when single function, but no difference in
|
||||||
|
* performance
|
||||||
|
*/
|
||||||
|
BitHammingDistance = BitHammingDistanceDefault;
|
||||||
|
BitJaccardDistance = BitJaccardDistanceDefault;
|
||||||
|
|
||||||
|
#ifdef BIT_DISPATCH
|
||||||
|
if (SupportsAvx512Popcount())
|
||||||
|
{
|
||||||
|
BitHammingDistance = BitHammingDistanceAvx512Popcount;
|
||||||
|
BitJaccardDistance = BitJaccardDistanceAvx512Popcount;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
23
src/bitutils.h
Normal file
23
src/bitutils.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef BITUTILS_H
|
||||||
|
#define BITUTILS_H
|
||||||
|
|
||||||
|
/* Only enable for more recent compilers */
|
||||||
|
#if defined(__x86_64__) && defined(__GNUC__) && __GNUC__ >= 8
|
||||||
|
#define BIT_DISPATCH
|
||||||
|
#elif defined(__x86_64__) && defined(__clang_major__) && __clang_major__ >= 7
|
||||||
|
#define BIT_DISPATCH
|
||||||
|
#elif defined(_M_AMD64) && defined(_MSC_VER) && _MSC_VER >= 1920
|
||||||
|
#define BIT_DISPATCH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* target_clones requires glibc */
|
||||||
|
#if defined(BIT_DISPATCH) && defined(__gnu_linux__)
|
||||||
|
#define USE_TARGET_CLONES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern uint64 (*BitHammingDistance) (uint32 bytes, unsigned char *ax, unsigned char *bx, uint64 distance);
|
||||||
|
extern double (*BitJaccardDistance) (uint32 bytes, unsigned char *ax, unsigned char *bx, uint64 ab, uint64 aa, uint64 bb);
|
||||||
|
|
||||||
|
void BitvecInit(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "bitutils.h"
|
||||||
#include "bitvector.h"
|
#include "bitvector.h"
|
||||||
#include "port/pg_bitutils.h"
|
|
||||||
#include "utils/varbit.h"
|
#include "utils/varbit.h"
|
||||||
|
|
||||||
#if PG_VERSION_NUM >= 160000
|
#if PG_VERSION_NUM >= 160000
|
||||||
@@ -46,17 +46,10 @@ hamming_distance(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
VarBit *a = PG_GETARG_VARBIT_P(0);
|
VarBit *a = PG_GETARG_VARBIT_P(0);
|
||||||
VarBit *b = PG_GETARG_VARBIT_P(1);
|
VarBit *b = PG_GETARG_VARBIT_P(1);
|
||||||
unsigned char *ax = VARBITS(a);
|
|
||||||
unsigned char *bx = VARBITS(b);
|
|
||||||
uint64 distance = 0;
|
|
||||||
|
|
||||||
CheckDims(a, b);
|
CheckDims(a, b);
|
||||||
|
|
||||||
/* TODO Improve performance */
|
PG_RETURN_FLOAT8((double) BitHammingDistance(VARBITBYTES(a), VARBITS(a), VARBITS(b), 0));
|
||||||
for (uint32 i = 0; i < VARBITBYTES(a); i++)
|
|
||||||
distance += pg_number_of_ones[ax[i] ^ bx[i]];
|
|
||||||
|
|
||||||
PG_RETURN_FLOAT8((double) distance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -68,23 +61,8 @@ jaccard_distance(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
VarBit *a = PG_GETARG_VARBIT_P(0);
|
VarBit *a = PG_GETARG_VARBIT_P(0);
|
||||||
VarBit *b = PG_GETARG_VARBIT_P(1);
|
VarBit *b = PG_GETARG_VARBIT_P(1);
|
||||||
unsigned char *ax = VARBITS(a);
|
|
||||||
unsigned char *bx = VARBITS(b);
|
|
||||||
uint64 ab = 0;
|
|
||||||
uint64 aa;
|
|
||||||
uint64 bb;
|
|
||||||
|
|
||||||
CheckDims(a, b);
|
CheckDims(a, b);
|
||||||
|
|
||||||
/* TODO Improve performance */
|
PG_RETURN_FLOAT8(BitJaccardDistance(VARBITBYTES(a), VARBITS(a), VARBITS(b), 0, 0, 0));
|
||||||
for (uint32 i = 0; i < VARBITBYTES(a); i++)
|
|
||||||
ab += pg_number_of_ones[ax[i] & bx[i]];
|
|
||||||
|
|
||||||
if (ab == 0)
|
|
||||||
PG_RETURN_FLOAT8(1);
|
|
||||||
|
|
||||||
aa = pg_popcount((char *) ax, VARBITBYTES(a));
|
|
||||||
bb = pg_popcount((char *) bx, VARBITBYTES(b));
|
|
||||||
|
|
||||||
PG_RETURN_FLOAT8(1 - (ab / ((double) (aa + bb - ab))));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "bitutils.h"
|
||||||
#include "bitvector.h"
|
#include "bitvector.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "common/shortest_dec.h"
|
#include "common/shortest_dec.h"
|
||||||
@@ -56,6 +57,7 @@ PGDLLEXPORT void _PG_init(void);
|
|||||||
void
|
void
|
||||||
_PG_init(void)
|
_PG_init(void)
|
||||||
{
|
{
|
||||||
|
BitvecInit();
|
||||||
HalfvecInit();
|
HalfvecInit();
|
||||||
HnswInit();
|
HnswInit();
|
||||||
IvfflatInit();
|
IvfflatInit();
|
||||||
|
|||||||
@@ -28,6 +28,24 @@ SELECT hamming_distance('10101010101010101010', '01010101010101010101');
|
|||||||
20
|
20
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT hamming_distance('101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', '101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101');
|
||||||
|
hamming_distance
|
||||||
|
------------------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT hamming_distance('101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', '010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010');
|
||||||
|
hamming_distance
|
||||||
|
------------------
|
||||||
|
513
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT hamming_distance('110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011', '100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001');
|
||||||
|
hamming_distance
|
||||||
|
------------------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT hamming_distance('', '');
|
SELECT hamming_distance('', '');
|
||||||
hamming_distance
|
hamming_distance
|
||||||
------------------
|
------------------
|
||||||
@@ -86,6 +104,24 @@ SELECT jaccard_distance('10101010101010101010', '01010101010101010101');
|
|||||||
1
|
1
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT jaccard_distance('101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', '101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101');
|
||||||
|
jaccard_distance
|
||||||
|
------------------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT jaccard_distance('101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', '010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010');
|
||||||
|
jaccard_distance
|
||||||
|
------------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT jaccard_distance('110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011', '100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001');
|
||||||
|
jaccard_distance
|
||||||
|
------------------
|
||||||
|
0.5
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT jaccard_distance('', '');
|
SELECT jaccard_distance('', '');
|
||||||
jaccard_distance
|
jaccard_distance
|
||||||
------------------
|
------------------
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ SELECT hamming_distance('111', '110');
|
|||||||
SELECT hamming_distance('111', '100');
|
SELECT hamming_distance('111', '100');
|
||||||
SELECT hamming_distance('111', '000');
|
SELECT hamming_distance('111', '000');
|
||||||
SELECT hamming_distance('10101010101010101010', '01010101010101010101');
|
SELECT hamming_distance('10101010101010101010', '01010101010101010101');
|
||||||
|
SELECT hamming_distance('101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', '101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101');
|
||||||
|
SELECT hamming_distance('101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', '010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010');
|
||||||
|
SELECT hamming_distance('110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011', '100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001');
|
||||||
SELECT hamming_distance('', '');
|
SELECT hamming_distance('', '');
|
||||||
SELECT hamming_distance('111', '00');
|
SELECT hamming_distance('111', '00');
|
||||||
SELECT hamming_distance('111', '000'::varbit(4));
|
SELECT hamming_distance('111', '000'::varbit(4));
|
||||||
@@ -15,6 +18,9 @@ SELECT jaccard_distance('1111', '1000');
|
|||||||
SELECT jaccard_distance('1111', '0000');
|
SELECT jaccard_distance('1111', '0000');
|
||||||
SELECT jaccard_distance('1100', '1000');
|
SELECT jaccard_distance('1100', '1000');
|
||||||
SELECT jaccard_distance('10101010101010101010', '01010101010101010101');
|
SELECT jaccard_distance('10101010101010101010', '01010101010101010101');
|
||||||
|
SELECT jaccard_distance('101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', '101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101');
|
||||||
|
SELECT jaccard_distance('101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', '010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010');
|
||||||
|
SELECT jaccard_distance('110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011', '100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001');
|
||||||
SELECT jaccard_distance('', '');
|
SELECT jaccard_distance('', '');
|
||||||
SELECT jaccard_distance('1111', '000');
|
SELECT jaccard_distance('1111', '000');
|
||||||
SELECT jaccard_distance('1111', '0000'::varbit(5));
|
SELECT jaccard_distance('1111', '0000'::varbit(5));
|
||||||
|
|||||||
Reference in New Issue
Block a user