mirror of
https://github.com/postgres/postgres.git
synced 2025-09-11 00:12:06 +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:
88
src/backend/access/spgist/spgproc.c
Normal file
88
src/backend/access/spgist/spgproc.c
Normal file
@@ -0,0 +1,88 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* spgproc.c
|
||||
* Common supporting procedures for SP-GiST opclasses.
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/backend/access/spgist/spgproc.c
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "access/spgist_private.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/float.h"
|
||||
#include "utils/geo_decls.h"
|
||||
|
||||
#define point_point_distance(p1,p2) \
|
||||
DatumGetFloat8(DirectFunctionCall2(point_distance, \
|
||||
PointPGetDatum(p1), PointPGetDatum(p2)))
|
||||
|
||||
/* Point-box distance in the assumption that box is aligned by axis */
|
||||
static double
|
||||
point_box_distance(Point *point, BOX *box)
|
||||
{
|
||||
double dx,
|
||||
dy;
|
||||
|
||||
if (isnan(point->x) || isnan(box->low.x) ||
|
||||
isnan(point->y) || isnan(box->low.y))
|
||||
return get_float8_nan();
|
||||
|
||||
if (point->x < box->low.x)
|
||||
dx = box->low.x - point->x;
|
||||
else if (point->x > box->high.x)
|
||||
dx = point->x - box->high.x;
|
||||
else
|
||||
dx = 0.0;
|
||||
|
||||
if (point->y < box->low.y)
|
||||
dy = box->low.y - point->y;
|
||||
else if (point->y > box->high.y)
|
||||
dy = point->y - box->high.y;
|
||||
else
|
||||
dy = 0.0;
|
||||
|
||||
return HYPOT(dx, dy);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns distances from given key to array of ordering scan keys. Leaf key
|
||||
* is expected to be point, non-leaf key is expected to be box. Scan key
|
||||
* arguments are expected to be points.
|
||||
*/
|
||||
double *
|
||||
spg_key_orderbys_distances(Datum key, bool isLeaf,
|
||||
ScanKey orderbys, int norderbys)
|
||||
{
|
||||
int sk_num;
|
||||
double *distances = (double *) palloc(norderbys * sizeof(double)),
|
||||
*distance = distances;
|
||||
|
||||
for (sk_num = 0; sk_num < norderbys; ++sk_num, ++orderbys, ++distance)
|
||||
{
|
||||
Point *point = DatumGetPointP(orderbys->sk_argument);
|
||||
|
||||
*distance = isLeaf ? point_point_distance(point, DatumGetPointP(key))
|
||||
: point_box_distance(point, DatumGetBoxP(key));
|
||||
}
|
||||
|
||||
return distances;
|
||||
}
|
||||
|
||||
BOX *
|
||||
box_copy(BOX *orig)
|
||||
{
|
||||
BOX *result = palloc(sizeof(BOX));
|
||||
|
||||
*result = *orig;
|
||||
return result;
|
||||
}
|
Reference in New Issue
Block a user