1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

Add support for nearest-neighbor (KNN) searches to SP-GiST

Currently, KNN searches were supported only by GiST.  SP-GiST also capable to
support them.  This commit implements that support.  SP-GiST scan stack is
replaced with queue, which serves as stack if no ordering is specified.  KNN
support is provided for three SP-GIST opclasses: quad_point_ops, kd_point_ops
and poly_ops (catversion is bumped).  Some common parts between GiST and SP-GiST
KNNs are extracted into separate functions.

Discussion: https://postgr.es/m/570825e8-47d0-4732-2bf6-88d67d2d51c8%40postgrespro.ru
Author: Nikita Glukhov, Alexander Korotkov based on GSoC work by Vlad Sterzhanov
Review: Andrey Borodin, Alexander Korotkov
This commit is contained in:
Alexander Korotkov
2018-09-19 01:54:10 +03:00
parent d0cfc3d6a4
commit 2a6368343f
29 changed files with 1681 additions and 428 deletions

View File

@ -14,9 +14,9 @@
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/gist_private.h"
#include "access/relscan.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "storage/lmgr.h"
#include "storage/predicate.h"
@ -543,7 +543,6 @@ getNextNearest(IndexScanDesc scan)
{
GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
bool res = false;
int i;
if (scan->xs_hitup)
{
@ -564,45 +563,10 @@ getNextNearest(IndexScanDesc scan)
/* found a heap item at currently minimal distance */
scan->xs_ctup.t_self = item->data.heap.heapPtr;
scan->xs_recheck = item->data.heap.recheck;
scan->xs_recheckorderby = item->data.heap.recheckDistances;
for (i = 0; i < scan->numberOfOrderBys; i++)
{
if (so->orderByTypes[i] == FLOAT8OID)
{
#ifndef USE_FLOAT8_BYVAL
/* must free any old value to avoid memory leakage */
if (!scan->xs_orderbynulls[i])
pfree(DatumGetPointer(scan->xs_orderbyvals[i]));
#endif
scan->xs_orderbyvals[i] = Float8GetDatum(item->distances[i]);
scan->xs_orderbynulls[i] = false;
}
else if (so->orderByTypes[i] == FLOAT4OID)
{
/* convert distance function's result to ORDER BY type */
#ifndef USE_FLOAT4_BYVAL
/* must free any old value to avoid memory leakage */
if (!scan->xs_orderbynulls[i])
pfree(DatumGetPointer(scan->xs_orderbyvals[i]));
#endif
scan->xs_orderbyvals[i] = Float4GetDatum((float4) item->distances[i]);
scan->xs_orderbynulls[i] = false;
}
else
{
/*
* If the ordering operator's return value is anything
* else, we don't know how to convert the float8 bound
* calculated by the distance function to that. The
* executor won't actually need the order by values we
* return here, if there are no lossy results, so only
* insist on converting if the *recheck flag is set.
*/
if (scan->xs_recheckorderby)
elog(ERROR, "GiST operator family's FOR ORDER BY operator must return float8 or float4 if the distance function is lossy");
scan->xs_orderbynulls[i] = true;
}
}
index_store_float8_orderby_distances(scan, so->orderByTypes,
item->distances,
item->data.heap.recheckDistances);
/* in an index-only scan, also return the reconstructed tuple. */
if (scan->xs_want_itup)

View File

@ -23,6 +23,7 @@
#include "storage/lmgr.h"
#include "utils/float.h"
#include "utils/syscache.h"
#include "utils/lsyscache.h"
/*
@ -871,12 +872,6 @@ gistproperty(Oid index_oid, int attno,
IndexAMProperty prop, const char *propname,
bool *res, bool *isnull)
{
HeapTuple tuple;
Form_pg_index rd_index PG_USED_FOR_ASSERTS_ONLY;
Form_pg_opclass rd_opclass;
Datum datum;
bool disnull;
oidvector *indclass;
Oid opclass,
opfamily,
opcintype;
@ -910,41 +905,19 @@ gistproperty(Oid index_oid, int attno,
}
/* First we need to know the column's opclass. */
tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
if (!HeapTupleIsValid(tuple))
opclass = get_index_column_opclass(index_oid, attno);
if (!OidIsValid(opclass))
{
*isnull = true;
return true;
}
rd_index = (Form_pg_index) GETSTRUCT(tuple);
/* caller is supposed to guarantee this */
Assert(attno > 0 && attno <= rd_index->indnatts);
datum = SysCacheGetAttr(INDEXRELID, tuple,
Anum_pg_index_indclass, &disnull);
Assert(!disnull);
indclass = ((oidvector *) DatumGetPointer(datum));
opclass = indclass->values[attno - 1];
ReleaseSysCache(tuple);
/* Now look up the opclass family and input datatype. */
tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
if (!HeapTupleIsValid(tuple))
if (!get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
{
*isnull = true;
return true;
}
rd_opclass = (Form_pg_opclass) GETSTRUCT(tuple);
opfamily = rd_opclass->opcfamily;
opcintype = rd_opclass->opcintype;
ReleaseSysCache(tuple);
/* And now we can check whether the function is provided. */
@ -967,6 +940,8 @@ gistproperty(Oid index_oid, int attno,
Int16GetDatum(GIST_COMPRESS_PROC));
}
*isnull = false;
return true;
}