mirror of
https://github.com/postgres/postgres.git
synced 2025-06-10 09:21:54 +03:00
Code and docs review for cube kNN support.
Commit 33bd250f6c
could have done with
some more review:
Adjust coding so that compilers unfamiliar with elog/ereport don't complain
about uninitialized values.
Fix misuse of PG_GETARG_INT16 to retrieve arguments declared as "integer"
at the SQL level. (This was evidently copied from cube_ll_coord and
cube_ur_coord, but those were wrong too.)
Fix non-style-guide-conforming error messages.
Fix underparenthesized if statements, which pgindent would have made a
hash of, and remove some unnecessary parens elsewhere.
Run pgindent over new code.
Revise documentation: repeated accretion of more operators without any
rethinking of the text already there had left things in a bit of a mess.
Merge all the cube operators into one table and adjust surrounding text
appropriately.
David Rowley and Tom Lane
This commit is contained in:
@ -1275,6 +1275,7 @@ distance_taxicab(PG_FUNCTION_ARGS)
|
|||||||
if (DIM(a) < DIM(b))
|
if (DIM(a) < DIM(b))
|
||||||
{
|
{
|
||||||
NDBOX *tmp = b;
|
NDBOX *tmp = b;
|
||||||
|
|
||||||
b = a;
|
b = a;
|
||||||
a = tmp;
|
a = tmp;
|
||||||
swapped = true;
|
swapped = true;
|
||||||
@ -1283,11 +1284,13 @@ distance_taxicab(PG_FUNCTION_ARGS)
|
|||||||
distance = 0.0;
|
distance = 0.0;
|
||||||
/* compute within the dimensions of (b) */
|
/* compute within the dimensions of (b) */
|
||||||
for (i = 0; i < DIM(b); i++)
|
for (i = 0; i < DIM(b); i++)
|
||||||
distance += fabs(distance_1D(LL_COORD(a,i), UR_COORD(a,i), LL_COORD(b,i), UR_COORD(b,i)));
|
distance += fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
|
||||||
|
LL_COORD(b, i), UR_COORD(b, i)));
|
||||||
|
|
||||||
/* compute distance to zero for those dimensions in (a) absent in (b) */
|
/* compute distance to zero for those dimensions in (a) absent in (b) */
|
||||||
for (i = DIM(b); i < DIM(a); i++)
|
for (i = DIM(b); i < DIM(a); i++)
|
||||||
distance += fabs(distance_1D(LL_COORD(a,i), UR_COORD(a,i), 0.0, 0.0));
|
distance += fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
|
||||||
|
0.0, 0.0));
|
||||||
|
|
||||||
if (swapped)
|
if (swapped)
|
||||||
{
|
{
|
||||||
@ -1309,13 +1312,15 @@ distance_chebyshev(PG_FUNCTION_ARGS)
|
|||||||
NDBOX *a = PG_GETARG_NDBOX(0),
|
NDBOX *a = PG_GETARG_NDBOX(0),
|
||||||
*b = PG_GETARG_NDBOX(1);
|
*b = PG_GETARG_NDBOX(1);
|
||||||
bool swapped = false;
|
bool swapped = false;
|
||||||
double d, distance;
|
double d,
|
||||||
|
distance;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* swap the box pointers if needed */
|
/* swap the box pointers if needed */
|
||||||
if (DIM(a) < DIM(b))
|
if (DIM(a) < DIM(b))
|
||||||
{
|
{
|
||||||
NDBOX *tmp = b;
|
NDBOX *tmp = b;
|
||||||
|
|
||||||
b = a;
|
b = a;
|
||||||
a = tmp;
|
a = tmp;
|
||||||
swapped = true;
|
swapped = true;
|
||||||
@ -1325,7 +1330,8 @@ distance_chebyshev(PG_FUNCTION_ARGS)
|
|||||||
/* compute within the dimensions of (b) */
|
/* compute within the dimensions of (b) */
|
||||||
for (i = 0; i < DIM(b); i++)
|
for (i = 0; i < DIM(b); i++)
|
||||||
{
|
{
|
||||||
d = fabs(distance_1D(LL_COORD(a,i), UR_COORD(a,i), LL_COORD(b,i), UR_COORD(b,i)));
|
d = fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
|
||||||
|
LL_COORD(b, i), UR_COORD(b, i)));
|
||||||
if (d > distance)
|
if (d > distance)
|
||||||
distance = d;
|
distance = d;
|
||||||
}
|
}
|
||||||
@ -1333,7 +1339,7 @@ distance_chebyshev(PG_FUNCTION_ARGS)
|
|||||||
/* compute distance to zero for those dimensions in (a) absent in (b) */
|
/* compute distance to zero for those dimensions in (a) absent in (b) */
|
||||||
for (i = DIM(b); i < DIM(a); i++)
|
for (i = DIM(b); i < DIM(a); i++)
|
||||||
{
|
{
|
||||||
d = fabs(distance_1D(LL_COORD(a,i), UR_COORD(a,i), 0.0, 0.0));
|
d = fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i), 0.0, 0.0));
|
||||||
if (d > distance)
|
if (d > distance)
|
||||||
distance = d;
|
distance = d;
|
||||||
}
|
}
|
||||||
@ -1357,44 +1363,41 @@ g_cube_distance(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
||||||
NDBOX *cube = DatumGetNDBOX(entry->key);
|
NDBOX *cube = DatumGetNDBOX(entry->key);
|
||||||
double retval;
|
double retval;
|
||||||
|
|
||||||
if (strategy == CubeKNNDistanceCoord)
|
if (strategy == CubeKNNDistanceCoord)
|
||||||
{
|
{
|
||||||
int coord = PG_GETARG_INT32(1);
|
int coord = PG_GETARG_INT32(1);
|
||||||
|
|
||||||
if IS_POINT(cube)
|
if (IS_POINT(cube))
|
||||||
{
|
retval = cube->x[(coord - 1) % DIM(cube)];
|
||||||
retval = (cube)->x[(coord-1)%DIM(cube)];
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
retval = Min(cube->x[(coord - 1) % DIM(cube)],
|
||||||
retval = Min(
|
cube->x[(coord - 1) % DIM(cube) + DIM(cube)]);
|
||||||
(cube)->x[(coord-1)%DIM(cube)],
|
|
||||||
(cube)->x[(coord-1)%DIM(cube) + DIM(cube)]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NDBOX *query = PG_GETARG_NDBOX(1);
|
NDBOX *query = PG_GETARG_NDBOX(1);
|
||||||
switch(strategy)
|
|
||||||
|
switch (strategy)
|
||||||
{
|
{
|
||||||
case CubeKNNDistanceTaxicab:
|
case CubeKNNDistanceTaxicab:
|
||||||
retval = DatumGetFloat8(DirectFunctionCall2(distance_taxicab,
|
retval = DatumGetFloat8(DirectFunctionCall2(distance_taxicab,
|
||||||
PointerGetDatum(cube), PointerGetDatum(query)));
|
PointerGetDatum(cube), PointerGetDatum(query)));
|
||||||
break;
|
break;
|
||||||
case CubeKNNDistanceEuclid:
|
case CubeKNNDistanceEuclid:
|
||||||
retval = DatumGetFloat8(DirectFunctionCall2(cube_distance,
|
retval = DatumGetFloat8(DirectFunctionCall2(cube_distance,
|
||||||
PointerGetDatum(cube), PointerGetDatum(query)));
|
PointerGetDatum(cube), PointerGetDatum(query)));
|
||||||
break;
|
break;
|
||||||
case CubeKNNDistanceChebyshev:
|
case CubeKNNDistanceChebyshev:
|
||||||
retval = DatumGetFloat8(DirectFunctionCall2(distance_chebyshev,
|
retval = DatumGetFloat8(DirectFunctionCall2(distance_chebyshev,
|
||||||
PointerGetDatum(cube), PointerGetDatum(query)));
|
PointerGetDatum(cube), PointerGetDatum(query)));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "Cube: unknown strategy number.");
|
elog(ERROR, "unrecognized cube strategy number: %d", strategy);
|
||||||
|
retval = 0; /* keep compiler quiet */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PG_RETURN_FLOAT8(retval);
|
PG_RETURN_FLOAT8(retval);
|
||||||
@ -1466,7 +1469,7 @@ Datum
|
|||||||
cube_ll_coord(PG_FUNCTION_ARGS)
|
cube_ll_coord(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
NDBOX *c = PG_GETARG_NDBOX(0);
|
NDBOX *c = PG_GETARG_NDBOX(0);
|
||||||
int n = PG_GETARG_INT16(1);
|
int n = PG_GETARG_INT32(1);
|
||||||
double result;
|
double result;
|
||||||
|
|
||||||
if (DIM(c) >= n && n > 0)
|
if (DIM(c) >= n && n > 0)
|
||||||
@ -1483,7 +1486,7 @@ Datum
|
|||||||
cube_ur_coord(PG_FUNCTION_ARGS)
|
cube_ur_coord(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
NDBOX *c = PG_GETARG_NDBOX(0);
|
NDBOX *c = PG_GETARG_NDBOX(0);
|
||||||
int n = PG_GETARG_INT16(1);
|
int n = PG_GETARG_INT32(1);
|
||||||
double result;
|
double result;
|
||||||
|
|
||||||
if (DIM(c) >= n && n > 0)
|
if (DIM(c) >= n && n > 0)
|
||||||
@ -1504,21 +1507,17 @@ Datum
|
|||||||
cube_coord(PG_FUNCTION_ARGS)
|
cube_coord(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
NDBOX *cube = PG_GETARG_NDBOX(0);
|
NDBOX *cube = PG_GETARG_NDBOX(0);
|
||||||
int coord = PG_GETARG_INT16(1);
|
int coord = PG_GETARG_INT32(1);
|
||||||
|
|
||||||
if ((coord > 0) && (coord <= 2*DIM(cube)))
|
if (coord <= 0 || coord > 2 * DIM(cube))
|
||||||
{
|
|
||||||
if IS_POINT(cube)
|
|
||||||
PG_RETURN_FLOAT8( (cube)->x[(coord-1)%DIM(cube)] );
|
|
||||||
else
|
|
||||||
PG_RETURN_FLOAT8( (cube)->x[coord-1] );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
|
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
|
||||||
errmsg("Cube index out of bounds")));
|
errmsg("cube index %d is out of bounds", coord)));
|
||||||
}
|
|
||||||
|
if (IS_POINT(cube))
|
||||||
|
PG_RETURN_FLOAT8(cube->x[(coord - 1) % DIM(cube)]);
|
||||||
|
else
|
||||||
|
PG_RETURN_FLOAT8(cube->x[coord - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1536,27 +1535,28 @@ Datum
|
|||||||
cube_coord_llur(PG_FUNCTION_ARGS)
|
cube_coord_llur(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
NDBOX *cube = PG_GETARG_NDBOX(0);
|
NDBOX *cube = PG_GETARG_NDBOX(0);
|
||||||
int coord = PG_GETARG_INT16(1);
|
int coord = PG_GETARG_INT32(1);
|
||||||
|
|
||||||
if ((coord > 0) && (coord <= DIM(cube)))
|
if (coord <= 0 || coord > 2 * DIM(cube))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
|
||||||
|
errmsg("cube index %d is out of bounds", coord)));
|
||||||
|
|
||||||
|
if (coord <= DIM(cube))
|
||||||
{
|
{
|
||||||
if IS_POINT(cube)
|
if (IS_POINT(cube))
|
||||||
PG_RETURN_FLOAT8( (cube)->x[coord-1] );
|
PG_RETURN_FLOAT8(cube->x[coord - 1]);
|
||||||
else
|
else
|
||||||
PG_RETURN_FLOAT8( Min((cube)->x[coord-1], (cube)->x[coord-1+DIM(cube)]) );
|
PG_RETURN_FLOAT8(Min(cube->x[coord - 1],
|
||||||
}
|
cube->x[coord - 1 + DIM(cube)]));
|
||||||
else if ((coord > DIM(cube)) && (coord <= 2*DIM(cube)))
|
|
||||||
{
|
|
||||||
if IS_POINT(cube)
|
|
||||||
PG_RETURN_FLOAT8( (cube)->x[(coord-1)%DIM(cube)] );
|
|
||||||
else
|
|
||||||
PG_RETURN_FLOAT8( Max((cube)->x[coord-1], (cube)->x[coord-1-DIM(cube)]) );
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
if (IS_POINT(cube))
|
||||||
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
|
PG_RETURN_FLOAT8(cube->x[(coord - 1) % DIM(cube)]);
|
||||||
errmsg("Cube index out of bounds")));
|
else
|
||||||
|
PG_RETURN_FLOAT8(Max(cube->x[coord - 1],
|
||||||
|
cube->x[coord - 1 - DIM(cube)]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1458,13 +1458,13 @@ SELECT cube(array[10,20,30], array[40,50,60])->6;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])->0;
|
SELECT cube(array[10,20,30], array[40,50,60])->0;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index 0 is out of bounds
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])->7;
|
SELECT cube(array[10,20,30], array[40,50,60])->7;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index 7 is out of bounds
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])->-1;
|
SELECT cube(array[10,20,30], array[40,50,60])->-1;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index -1 is out of bounds
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])->-6;
|
SELECT cube(array[10,20,30], array[40,50,60])->-6;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index -6 is out of bounds
|
||||||
SELECT cube(array[10,20,30])->3;
|
SELECT cube(array[10,20,30])->3;
|
||||||
?column?
|
?column?
|
||||||
----------
|
----------
|
||||||
@ -1478,7 +1478,7 @@ SELECT cube(array[10,20,30])->6;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT cube(array[10,20,30])->-6;
|
SELECT cube(array[10,20,30])->-6;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index -6 is out of bounds
|
||||||
-- "normalized" coordinate access
|
-- "normalized" coordinate access
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])~>1;
|
SELECT cube(array[10,20,30], array[40,50,60])~>1;
|
||||||
?column?
|
?column?
|
||||||
@ -1517,7 +1517,7 @@ SELECT cube(array[40,50,60], array[10,20,30])~>3;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT cube(array[40,50,60], array[10,20,30])~>0;
|
SELECT cube(array[40,50,60], array[10,20,30])~>0;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index 0 is out of bounds
|
||||||
SELECT cube(array[40,50,60], array[10,20,30])~>4;
|
SELECT cube(array[40,50,60], array[10,20,30])~>4;
|
||||||
?column?
|
?column?
|
||||||
----------
|
----------
|
||||||
@ -1525,7 +1525,7 @@ SELECT cube(array[40,50,60], array[10,20,30])~>4;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT cube(array[40,50,60], array[10,20,30])~>(-1);
|
SELECT cube(array[40,50,60], array[10,20,30])~>(-1);
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index -1 is out of bounds
|
||||||
-- Load some example data and build the index
|
-- Load some example data and build the index
|
||||||
--
|
--
|
||||||
CREATE TABLE test_cube (c cube);
|
CREATE TABLE test_cube (c cube);
|
||||||
|
@ -1458,13 +1458,13 @@ SELECT cube(array[10,20,30], array[40,50,60])->6;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])->0;
|
SELECT cube(array[10,20,30], array[40,50,60])->0;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index 0 is out of bounds
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])->7;
|
SELECT cube(array[10,20,30], array[40,50,60])->7;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index 7 is out of bounds
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])->-1;
|
SELECT cube(array[10,20,30], array[40,50,60])->-1;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index -1 is out of bounds
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])->-6;
|
SELECT cube(array[10,20,30], array[40,50,60])->-6;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index -6 is out of bounds
|
||||||
SELECT cube(array[10,20,30])->3;
|
SELECT cube(array[10,20,30])->3;
|
||||||
?column?
|
?column?
|
||||||
----------
|
----------
|
||||||
@ -1478,7 +1478,7 @@ SELECT cube(array[10,20,30])->6;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT cube(array[10,20,30])->-6;
|
SELECT cube(array[10,20,30])->-6;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index -6 is out of bounds
|
||||||
-- "normalized" coordinate access
|
-- "normalized" coordinate access
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])~>1;
|
SELECT cube(array[10,20,30], array[40,50,60])~>1;
|
||||||
?column?
|
?column?
|
||||||
@ -1517,7 +1517,7 @@ SELECT cube(array[40,50,60], array[10,20,30])~>3;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT cube(array[40,50,60], array[10,20,30])~>0;
|
SELECT cube(array[40,50,60], array[10,20,30])~>0;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index 0 is out of bounds
|
||||||
SELECT cube(array[40,50,60], array[10,20,30])~>4;
|
SELECT cube(array[40,50,60], array[10,20,30])~>4;
|
||||||
?column?
|
?column?
|
||||||
----------
|
----------
|
||||||
@ -1525,7 +1525,7 @@ SELECT cube(array[40,50,60], array[10,20,30])~>4;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT cube(array[40,50,60], array[10,20,30])~>(-1);
|
SELECT cube(array[40,50,60], array[10,20,30])~>(-1);
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index -1 is out of bounds
|
||||||
-- Load some example data and build the index
|
-- Load some example data and build the index
|
||||||
--
|
--
|
||||||
CREATE TABLE test_cube (c cube);
|
CREATE TABLE test_cube (c cube);
|
||||||
|
@ -1458,13 +1458,13 @@ SELECT cube(array[10,20,30], array[40,50,60])->6;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])->0;
|
SELECT cube(array[10,20,30], array[40,50,60])->0;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index 0 is out of bounds
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])->7;
|
SELECT cube(array[10,20,30], array[40,50,60])->7;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index 7 is out of bounds
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])->-1;
|
SELECT cube(array[10,20,30], array[40,50,60])->-1;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index -1 is out of bounds
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])->-6;
|
SELECT cube(array[10,20,30], array[40,50,60])->-6;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index -6 is out of bounds
|
||||||
SELECT cube(array[10,20,30])->3;
|
SELECT cube(array[10,20,30])->3;
|
||||||
?column?
|
?column?
|
||||||
----------
|
----------
|
||||||
@ -1478,7 +1478,7 @@ SELECT cube(array[10,20,30])->6;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT cube(array[10,20,30])->-6;
|
SELECT cube(array[10,20,30])->-6;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index -6 is out of bounds
|
||||||
-- "normalized" coordinate access
|
-- "normalized" coordinate access
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])~>1;
|
SELECT cube(array[10,20,30], array[40,50,60])~>1;
|
||||||
?column?
|
?column?
|
||||||
@ -1517,7 +1517,7 @@ SELECT cube(array[40,50,60], array[10,20,30])~>3;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT cube(array[40,50,60], array[10,20,30])~>0;
|
SELECT cube(array[40,50,60], array[10,20,30])~>0;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index 0 is out of bounds
|
||||||
SELECT cube(array[40,50,60], array[10,20,30])~>4;
|
SELECT cube(array[40,50,60], array[10,20,30])~>4;
|
||||||
?column?
|
?column?
|
||||||
----------
|
----------
|
||||||
@ -1525,7 +1525,7 @@ SELECT cube(array[40,50,60], array[10,20,30])~>4;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT cube(array[40,50,60], array[10,20,30])~>(-1);
|
SELECT cube(array[40,50,60], array[10,20,30])~>(-1);
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index -1 is out of bounds
|
||||||
-- Load some example data and build the index
|
-- Load some example data and build the index
|
||||||
--
|
--
|
||||||
CREATE TABLE test_cube (c cube);
|
CREATE TABLE test_cube (c cube);
|
||||||
|
@ -1458,13 +1458,13 @@ SELECT cube(array[10,20,30], array[40,50,60])->6;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])->0;
|
SELECT cube(array[10,20,30], array[40,50,60])->0;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index 0 is out of bounds
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])->7;
|
SELECT cube(array[10,20,30], array[40,50,60])->7;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index 7 is out of bounds
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])->-1;
|
SELECT cube(array[10,20,30], array[40,50,60])->-1;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index -1 is out of bounds
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])->-6;
|
SELECT cube(array[10,20,30], array[40,50,60])->-6;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index -6 is out of bounds
|
||||||
SELECT cube(array[10,20,30])->3;
|
SELECT cube(array[10,20,30])->3;
|
||||||
?column?
|
?column?
|
||||||
----------
|
----------
|
||||||
@ -1478,7 +1478,7 @@ SELECT cube(array[10,20,30])->6;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT cube(array[10,20,30])->-6;
|
SELECT cube(array[10,20,30])->-6;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index -6 is out of bounds
|
||||||
-- "normalized" coordinate access
|
-- "normalized" coordinate access
|
||||||
SELECT cube(array[10,20,30], array[40,50,60])~>1;
|
SELECT cube(array[10,20,30], array[40,50,60])~>1;
|
||||||
?column?
|
?column?
|
||||||
@ -1517,7 +1517,7 @@ SELECT cube(array[40,50,60], array[10,20,30])~>3;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT cube(array[40,50,60], array[10,20,30])~>0;
|
SELECT cube(array[40,50,60], array[10,20,30])~>0;
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index 0 is out of bounds
|
||||||
SELECT cube(array[40,50,60], array[10,20,30])~>4;
|
SELECT cube(array[40,50,60], array[10,20,30])~>4;
|
||||||
?column?
|
?column?
|
||||||
----------
|
----------
|
||||||
@ -1525,7 +1525,7 @@ SELECT cube(array[40,50,60], array[10,20,30])~>4;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT cube(array[40,50,60], array[10,20,30])~>(-1);
|
SELECT cube(array[40,50,60], array[10,20,30])~>(-1);
|
||||||
ERROR: Cube index out of bounds
|
ERROR: cube index -1 is out of bounds
|
||||||
-- Load some example data and build the index
|
-- Load some example data and build the index
|
||||||
--
|
--
|
||||||
CREATE TABLE test_cube (c cube);
|
CREATE TABLE test_cube (c cube);
|
||||||
|
@ -75,8 +75,8 @@
|
|||||||
entered in. The <type>cube</> functions
|
entered in. The <type>cube</> functions
|
||||||
automatically swap values if needed to create a uniform
|
automatically swap values if needed to create a uniform
|
||||||
<quote>lower left — upper right</> internal representation.
|
<quote>lower left — upper right</> internal representation.
|
||||||
When corners coincide cube stores only one corner along with a
|
When the corners coincide, <type>cube</> stores only one corner
|
||||||
special flag in order to reduce size wasted.
|
along with an <quote>is point</> flag to avoid wasting space.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -98,17 +98,17 @@
|
|||||||
<title>Usage</title>
|
<title>Usage</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The <filename>cube</> module includes a GiST index operator class for
|
<xref linkend="cube-operators"> shows the operators provided for type
|
||||||
<type>cube</> values.
|
<type>cube</>.
|
||||||
The operators supported by the GiST operator class are shown in <xref linkend="cube-gist-operators">.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<table id="cube-gist-operators">
|
<table id="cube-operators">
|
||||||
<title>Cube GiST Operators</title>
|
<title>Cube Operators</title>
|
||||||
<tgroup cols="2">
|
<tgroup cols="3">
|
||||||
<thead>
|
<thead>
|
||||||
<row>
|
<row>
|
||||||
<entry>Operator</entry>
|
<entry>Operator</entry>
|
||||||
|
<entry>Result</entry>
|
||||||
<entry>Description</entry>
|
<entry>Description</entry>
|
||||||
</row>
|
</row>
|
||||||
</thead>
|
</thead>
|
||||||
@ -116,36 +116,93 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<row>
|
<row>
|
||||||
<entry><literal>a = b</></entry>
|
<entry><literal>a = b</></entry>
|
||||||
|
<entry><type>boolean</></entry>
|
||||||
<entry>The cubes a and b are identical.</entry>
|
<entry>The cubes a and b are identical.</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><literal>a && b</></entry>
|
<entry><literal>a && b</></entry>
|
||||||
|
<entry><type>boolean</></entry>
|
||||||
<entry>The cubes a and b overlap.</entry>
|
<entry>The cubes a and b overlap.</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><literal>a @> b</></entry>
|
<entry><literal>a @> b</></entry>
|
||||||
|
<entry><type>boolean</></entry>
|
||||||
<entry>The cube a contains the cube b.</entry>
|
<entry>The cube a contains the cube b.</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><literal>a <@ b</></entry>
|
<entry><literal>a <@ b</></entry>
|
||||||
|
<entry><type>boolean</></entry>
|
||||||
<entry>The cube a is contained in the cube b.</entry>
|
<entry>The cube a is contained in the cube b.</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><literal>a < b</></entry>
|
||||||
|
<entry><type>boolean</></entry>
|
||||||
|
<entry>The cube a is less than the cube b.</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><literal>a <= b</></entry>
|
||||||
|
<entry><type>boolean</></entry>
|
||||||
|
<entry>The cube a is less than or equal to the cube b.</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><literal>a > b</></entry>
|
||||||
|
<entry><type>boolean</></entry>
|
||||||
|
<entry>The cube a is greater than the cube b.</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><literal>a >= b</></entry>
|
||||||
|
<entry><type>boolean</></entry>
|
||||||
|
<entry>The cube a is greater than or equal to the cube b.</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><literal>a <> b</></entry>
|
||||||
|
<entry><type>boolean</></entry>
|
||||||
|
<entry>The cube a is not equal to the cube b.</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><literal>a -> n</></entry>
|
<entry><literal>a -> n</></entry>
|
||||||
<entry>Get n-th coordinate of cube.</entry>
|
<entry><type>float8</></entry>
|
||||||
|
<entry>Get <replaceable>n</>-th coordinate of cube (counting from 1).</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><literal>a ~> n</></entry>
|
<entry><literal>a ~> n</></entry>
|
||||||
|
<entry><type>float8</></entry>
|
||||||
<entry>
|
<entry>
|
||||||
Get n-th coordinate in 'normalized' cube representation. Noramlization
|
Get <replaceable>n</>-th coordinate in <quote>normalized</> cube
|
||||||
means coordinate rearrangement to form (lower left, upper right).
|
representation, in which the coordinates have been rearranged into
|
||||||
|
the form <quote>lower left — upper right</>; that is, the
|
||||||
|
smaller endpoint along each dimension appears first.
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><literal>a <-> b</></entry>
|
||||||
|
<entry><type>float8</></entry>
|
||||||
|
<entry>Euclidean distance between a and b.</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><literal>a <#> b</></entry>
|
||||||
|
<entry><type>float8</></entry>
|
||||||
|
<entry>Taxicab (L-1 metric) distance between a and b.</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><literal>a <=> b</></entry>
|
||||||
|
<entry><type>float8</></entry>
|
||||||
|
<entry>Chebyshev (L-inf metric) distance between a and b.</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</table>
|
||||||
@ -159,117 +216,49 @@
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
GiST index can be used to retrieve nearest neighbours via several metric
|
The scalar ordering operators (<literal><</>, <literal>>=</>, etc)
|
||||||
operators. As always any of them can be used as ordinary function.
|
do not make a lot of sense for any practical purpose but sorting. These
|
||||||
|
operators first compare the first coordinates, and if those are equal,
|
||||||
|
compare the second coordinates, etc. They exist mainly to support the
|
||||||
|
b-tree index operator class for <type>cube</>, which can be useful for
|
||||||
|
example if you would like a UNIQUE constraint on a <type>cube</> column.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<table id="cube-gistknn-operators">
|
|
||||||
<title>Cube GiST-kNN Operators</title>
|
|
||||||
<tgroup cols="2">
|
|
||||||
<thead>
|
|
||||||
<row>
|
|
||||||
<entry>Operator</entry>
|
|
||||||
<entry>Description</entry>
|
|
||||||
</row>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<row>
|
|
||||||
<entry><literal>a <-> b</></entry>
|
|
||||||
<entry>Euclidean distance between a and b</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><literal>a <#> b</></entry>
|
|
||||||
<entry>Taxicab (L-1 metric) distance between a and b</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><literal>a <=> b</></entry>
|
|
||||||
<entry>Chebyshev (L-inf metric) distance between a and b</entry>
|
|
||||||
</row>
|
|
||||||
</tbody>
|
|
||||||
</tgroup>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Selection of nearing neigbours can be done in the following way:
|
The <filename>cube</> module also provides a GiST index operator class for
|
||||||
|
<type>cube</> values.
|
||||||
|
A <type>cube</> GiST index can be used to search for values using the
|
||||||
|
<literal>=</>, <literal>&&</>, <literal>@></>, and
|
||||||
|
<literal><@</> operators in <literal>WHERE</> clauses.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
In addition, a <type>cube</> GiST index can be used to find nearest
|
||||||
|
neighbors using the metric operators
|
||||||
|
<literal><-></>, <literal><#></>, and
|
||||||
|
<literal><=></> in <literal>ORDER BY</> clauses.
|
||||||
|
For example, the nearest neighbor of the 3-D point (0.5, 0.5, 0.5)
|
||||||
|
could be found efficiently with:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
SELECT c FROM test
|
SELECT c FROM test
|
||||||
ORDER BY cube(array[0.5,0.5,0.5])<->c
|
ORDER BY cube(array[0.5,0.5,0.5]) <-> c
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Also kNN framework allows us to cheat with metrics in order to get results
|
The <literal>~></> operator can also be used in this way to
|
||||||
sorted by selected coodinate directly from the index without extra sorting
|
efficiently retrieve the first few values sorted by a selected coordinate.
|
||||||
step. That technique significantly faster on small values of LIMIT, however
|
For example, to get the first few cubes ordered by the first coordinate
|
||||||
with bigger values of LIMIT planner will switch automatically to standart
|
(lower left corner) ascending one could use the following query:
|
||||||
index scan and sort.
|
|
||||||
That behavior can be achieved using coordinate operator
|
|
||||||
(cube c)~>(int offset).
|
|
||||||
</para>
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
=> select cube(array[0.41,0.42,0.43])~>2 as coord;
|
SELECT c FROM test ORDER BY c ~> 1 LIMIT 5;
|
||||||
coord
|
|
||||||
-------
|
|
||||||
0.42
|
|
||||||
(1 row)
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
And to get 2-D cubes ordered by the first coordinate of the upper right
|
||||||
<para>
|
corner descending:
|
||||||
So using that operator as kNN metric we can obtain cubes sorted by it's
|
|
||||||
coordinate.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
To get cubes ordered by first coordinate of lower left corner ascending
|
|
||||||
one can use the following query:
|
|
||||||
</para>
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
SELECT c FROM test ORDER BY c~>1 LIMIT 5;
|
SELECT c FROM test ORDER BY c ~> 3 DESC LIMIT 5;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
<para>
|
|
||||||
And to get cubes descending by first coordinate of upper right corner
|
|
||||||
of 2d-cube:
|
|
||||||
</para>
|
|
||||||
<programlisting>
|
|
||||||
SELECT c FROM test ORDER BY c~>3 DESC LIMIT 5;
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The standard B-tree operators are also provided, for example
|
|
||||||
|
|
||||||
<informaltable>
|
|
||||||
<tgroup cols="2">
|
|
||||||
<thead>
|
|
||||||
<row>
|
|
||||||
<entry>Operator</entry>
|
|
||||||
<entry>Description</entry>
|
|
||||||
</row>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
|
||||||
<row>
|
|
||||||
<entry><literal>[a, b] < [c, d]</literal></entry>
|
|
||||||
<entry>Less than</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><literal>[a, b] > [c, d]</literal></entry>
|
|
||||||
<entry>Greater than</entry>
|
|
||||||
</row>
|
|
||||||
</tbody>
|
|
||||||
</tgroup>
|
|
||||||
</informaltable>
|
|
||||||
|
|
||||||
These operators do not make a lot of sense for any practical
|
|
||||||
purpose but sorting. These operators first compare (a) to (c),
|
|
||||||
and if these are equal, compare (b) to (d). That results in
|
|
||||||
reasonably good sorting in most cases, which is useful if
|
|
||||||
you want to use ORDER BY with this type.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
Reference in New Issue
Block a user