diff --git a/contrib/cube/cube--1.0.sql b/contrib/cube/cube--1.0.sql index 0307811..97258dd 100644 --- a/contrib/cube/cube--1.0.sql +++ b/contrib/cube/cube--1.0.sql @@ -135,8 +135,24 @@ LANGUAGE C IMMUTABLE STRICT; -- proximity routines +CREATE FUNCTION distance_taxicab(cube, cube) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION distance_euclid(cube, cube) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +-- Alias for backword compatibility CREATE FUNCTION cube_distance(cube, cube) RETURNS float8 +AS 'MODULE_PATHNAME', 'distance_euclid' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION distance_chebyshev(cube, cube) +RETURNS float8 AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; @@ -157,6 +173,11 @@ RETURNS float8 AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cube_coord(cube, int4) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + CREATE FUNCTION cube(float8) RETURNS cube AS 'MODULE_PATHNAME', 'cube_f8' LANGUAGE C IMMUTABLE STRICT; @@ -246,6 +267,25 @@ CREATE OPERATOR <@ ( RESTRICT = contsel, JOIN = contjoinsel ); +CREATE OPERATOR -> ( + LEFTARG = cube, RIGHTARG = int, PROCEDURE = cube_coord +); + +CREATE OPERATOR <#> ( + LEFTARG = cube, RIGHTARG = cube, PROCEDURE = distance_taxicab, + COMMUTATOR = '<#>' +); + +CREATE OPERATOR <-> ( + LEFTARG = cube, RIGHTARG = cube, PROCEDURE = distance_euclid, + COMMUTATOR = '<->' +); + +CREATE OPERATOR <=> ( + LEFTARG = cube, RIGHTARG = cube, PROCEDURE = distance_chebyshev, + COMMUTATOR = '<=>' +); + -- these are obsolete/deprecated: CREATE OPERATOR @ ( LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_contains, @@ -296,6 +336,10 @@ RETURNS internal AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION g_cube_distance (internal, cube, smallint, oid) +RETURNS internal +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; -- Create the operator classes for indexing @@ -316,10 +360,17 @@ CREATE OPERATOR CLASS gist_cube_ops OPERATOR 8 <@ , OPERATOR 13 @ , OPERATOR 14 ~ , + OPERATOR 15 -> (cube, int) FOR ORDER BY float_ops, + OPERATOR 16 <#> (cube, cube) FOR ORDER BY float_ops, + OPERATOR 17 <-> (cube, cube) FOR ORDER BY float_ops, + OPERATOR 18 <=> (cube, cube) FOR ORDER BY float_ops, + FUNCTION 1 g_cube_consistent (internal, cube, int, oid, internal), FUNCTION 2 g_cube_union (internal, internal), FUNCTION 3 g_cube_compress (internal), FUNCTION 4 g_cube_decompress (internal), FUNCTION 5 g_cube_penalty (internal, internal, internal), FUNCTION 6 g_cube_picksplit (internal, internal), - FUNCTION 7 g_cube_same (cube, cube, internal); + FUNCTION 7 g_cube_same (cube, cube, internal), + FUNCTION 8 g_cube_distance (internal, cube, smallint, oid); + diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c index 9524943..fce4955 100644 --- a/contrib/cube/cube.c +++ b/contrib/cube/cube.c @@ -45,6 +45,7 @@ PG_FUNCTION_INFO_V1(cube_c_f8_f8); PG_FUNCTION_INFO_V1(cube_dim); PG_FUNCTION_INFO_V1(cube_ll_coord); PG_FUNCTION_INFO_V1(cube_ur_coord); +PG_FUNCTION_INFO_V1(cube_coord); PG_FUNCTION_INFO_V1(cube_subset); Datum cube_in(PG_FUNCTION_ARGS); @@ -58,6 +59,7 @@ Datum cube_c_f8_f8(PG_FUNCTION_ARGS); Datum cube_dim(PG_FUNCTION_ARGS); Datum cube_ll_coord(PG_FUNCTION_ARGS); Datum cube_ur_coord(PG_FUNCTION_ARGS); +Datum cube_coord(PG_FUNCTION_ARGS); Datum cube_subset(PG_FUNCTION_ARGS); /* @@ -71,6 +73,7 @@ PG_FUNCTION_INFO_V1(g_cube_penalty); PG_FUNCTION_INFO_V1(g_cube_picksplit); PG_FUNCTION_INFO_V1(g_cube_union); PG_FUNCTION_INFO_V1(g_cube_same); +PG_FUNCTION_INFO_V1(g_cube_distance); Datum g_cube_consistent(PG_FUNCTION_ARGS); Datum g_cube_compress(PG_FUNCTION_ARGS); @@ -79,6 +82,7 @@ Datum g_cube_penalty(PG_FUNCTION_ARGS); Datum g_cube_picksplit(PG_FUNCTION_ARGS); Datum g_cube_union(PG_FUNCTION_ARGS); Datum g_cube_same(PG_FUNCTION_ARGS); +Datum g_cube_distance(PG_FUNCTION_ARGS); /* ** B-tree support functions @@ -120,11 +124,15 @@ Datum cube_size(PG_FUNCTION_ARGS); /* ** miscellaneous */ -PG_FUNCTION_INFO_V1(cube_distance); +PG_FUNCTION_INFO_V1(distance_taxicab); +PG_FUNCTION_INFO_V1(distance_euclid); +PG_FUNCTION_INFO_V1(distance_chebyshev); PG_FUNCTION_INFO_V1(cube_is_point); PG_FUNCTION_INFO_V1(cube_enlarge); -Datum cube_distance(PG_FUNCTION_ARGS); +Datum distance_taxicab(PG_FUNCTION_ARGS); +Datum distance_euclid(PG_FUNCTION_ARGS); +Datum distance_chebyshev(PG_FUNCTION_ARGS); Datum cube_is_point(PG_FUNCTION_ARGS); Datum cube_enlarge(PG_FUNCTION_ARGS); @@ -1246,14 +1254,13 @@ cube_overlap(PG_FUNCTION_ARGS) PG_RETURN_BOOL(res); } - /* Distance */ /* The distance is computed as a per axis sum of the squared distances between 1D projections of the boxes onto Cartesian axes. Assuming zero distance between overlapping projections, this metric coincides with the "common sense" geometric distance */ Datum -cube_distance(PG_FUNCTION_ARGS) +distance_euclid(PG_FUNCTION_ARGS) { NDBOX *a = PG_GETARG_NDBOX(0), *b = PG_GETARG_NDBOX(1); @@ -1301,6 +1308,151 @@ cube_distance(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(sqrt(distance)); } +Datum +distance_taxicab(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX(0), + *b = PG_GETARG_NDBOX(1); + bool swapped = false; + double distance; + int i; + + /* swap the box pointers if needed */ + if (DIM(a) < DIM(b)) + { + NDBOX *tmp = b; + b = a; + a = tmp; + swapped = true; + } + + distance = 0.0; + /* compute within the dimensions of (b) */ + for (i = 0; i < DIM(b); i++) + distance += abs(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) */ + for (i = DIM(b); i < DIM(a); i++) + distance += abs(distance_1D(LL_COORD(a,i), UR_COORD(a,i), 0.0, 0.0)); + + if (swapped) + { + PG_FREE_IF_COPY(b, 0); + PG_FREE_IF_COPY(a, 1); + } + else + { + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + } + + PG_RETURN_FLOAT8(distance); +} + +Datum +distance_chebyshev(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX(0), + *b = PG_GETARG_NDBOX(1); + bool swapped = false; + double d, distance; + int i; + + /* swap the box pointers if needed */ + if (DIM(a) < DIM(b)) + { + NDBOX *tmp = b; + b = a; + a = tmp; + swapped = true; + } + + distance = 0.0; + /* compute within the dimensions of (b) */ + for (i = 0; i < DIM(b); i++) + { + d = abs(distance_1D(LL_COORD(a,i), UR_COORD(a,i), LL_COORD(b,i), UR_COORD(b,i))); + if (d > distance) + distance = d; + } + + /* compute distance to zero for those dimensions in (a) absent in (b) */ + for (i = DIM(b); i < DIM(a); i++) + { + d = abs(distance_1D(LL_COORD(a,i), UR_COORD(a,i), 0.0, 0.0)); + if (d > distance) + distance = d; + } + + if (swapped) + { + PG_FREE_IF_COPY(b, 0); + PG_FREE_IF_COPY(a, 1); + } + else + { + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + } + + PG_RETURN_FLOAT8(distance); +} + +Datum +g_cube_distance(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); + NDBOX *cube = DatumGetNDBOX(entry->key); + double retval; + + if (strategy == 15) + { + int coord = PG_GETARG_INT32(1); + + if(coord > 0) + if IS_POINT(cube) + retval = (cube)->x[(coord-1)%DIM(cube)]; + else + /* This is for right traversal of non-leaf elements */ + retval = Min( + (cube)->x[(coord-1)%DIM(cube)], + (cube)->x[(coord-1)%DIM(cube) + DIM(cube)] + ); + + /* negative coordinate user for descending sort */ + else + if IS_POINT(cube) + retval = -(cube)->x[(-coord-1)%DIM(cube)]; + else + /* This is for right traversal of non-leaf elements */ + retval = Min( + -(cube)->x[(-coord-1)%DIM(cube)], + -(cube)->x[(-coord-1)%DIM(cube) + DIM(cube)] + ); + } + else + { + NDBOX *query = PG_GETARG_NDBOX(1); + switch(strategy) + { + case 16: + retval = DatumGetFloat8(DirectFunctionCall2(distance_taxicab, + PointerGetDatum(cube), PointerGetDatum(query))); + break; + case 17: + retval = DatumGetFloat8(DirectFunctionCall2(distance_euclid, + PointerGetDatum(cube), PointerGetDatum(query))); + break; + case 18: + retval = DatumGetFloat8(DirectFunctionCall2(distance_chebyshev, + PointerGetDatum(cube), PointerGetDatum(query))); + break; + } + } + PG_RETURN_FLOAT8(retval); +} + static double distance_1D(double a1, double a2, double b1, double b2) { @@ -1395,6 +1547,38 @@ cube_ur_coord(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(result); } +/* + * Function returns cube coordinate. + * Numbers from 1 to DIM denotes Lower Left corner coordinates. + * Numbers from DIM+1 to 2*DIM denotes Upper Right cube corner coordinates. + * If negative number passed to function it is treated as it's absolut value, + * but resulting coordinate will be returned with changed sign. This + * convention useful for descending sort by this coordinate. + */ +Datum +cube_coord(PG_FUNCTION_ARGS) +{ + NDBOX *cube = PG_GETARG_NDBOX(0); + int coord = PG_GETARG_INT16(1); + + if ((0 < coord) && (coord <= 2*DIM(cube))) + if IS_POINT(cube) + PG_RETURN_FLOAT8( (cube)->x[(-1+coord)%DIM(cube)] ); + else + PG_RETURN_FLOAT8( (cube)->x[-1+coord] ); + + else if ((-2*DIM(cube) <= coord) && (coord < 0)) + if IS_POINT(cube) + PG_RETURN_FLOAT8( -(cube)->x[(-1-coord)%DIM(cube)] ); + else + PG_RETURN_FLOAT8( -(cube)->x[-1-coord] ); + + else + ereport(ERROR, + (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), + errmsg("Index out of bounds"))); +} + /* Increase or decrease box size by a radius in at least n dimensions. */ Datum cube_enlarge(PG_FUNCTION_ARGS) diff --git a/contrib/cube/expected/cube.out b/contrib/cube/expected/cube.out index ca9555e..a3db4f7 100644 --- a/contrib/cube/expected/cube.out +++ b/contrib/cube/expected/cube.out @@ -1381,6 +1381,110 @@ SELECT cube_size('(42,137)'::cube); 0 (1 row) +-- Test of distances +-- +SELECT distance_euclid('(1,1)'::cube, '(4,5)'::cube); + distance_euclid +----------------- + 5 +(1 row) + +SELECT '(1,1)'::cube <-> '(4,5)'::cube as d_e; + d_e +----- + 5 +(1 row) + +SELECT distance_chebyshev('(1,1)'::cube, '(4,5)'::cube); + distance_chebyshev +-------------------- + 4 +(1 row) + +SELECT '(1,1)'::cube <=> '(4,5)'::cube as d_c; + d_c +----- + 4 +(1 row) + +SELECT distance_taxicab('(1,1)'::cube, '(4,5)'::cube); + distance_taxicab +------------------ + 7 +(1 row) + +SELECT '(1,1)'::cube <#> '(4,5)'::cube as d_t; + d_t +----- + 7 +(1 row) + +-- zero for overlapping +SELECT distance_euclid('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); + distance_euclid +----------------- + 0 +(1 row) + +SELECT distance_chebyshev('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); + distance_chebyshev +-------------------- + 0 +(1 row) + +SELECT distance_taxicab('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); + distance_taxicab +------------------ + 0 +(1 row) + +-- coordinate access +SELECT cube(array[10,20,30], array[40,50,60])->1; + ?column? +---------- + 10 +(1 row) + +SELECT cube(array[10,20,30], array[40,50,60])->6; + ?column? +---------- + 60 +(1 row) + +SELECT cube(array[10,20,30], array[40,50,60])->0; +ERROR: Index out of bounds +SELECT cube(array[10,20,30], array[40,50,60])->7; +ERROR: Index out of bounds +SELECT cube(array[10,20,30], array[40,50,60])->-1; + ?column? +---------- + -10 +(1 row) + +SELECT cube(array[10,20,30], array[40,50,60])->-6; + ?column? +---------- + -60 +(1 row) + +SELECT cube(array[10,20,30])->3; + ?column? +---------- + 30 +(1 row) + +SELECT cube(array[10,20,30])->6; + ?column? +---------- + 30 +(1 row) + +SELECT cube(array[10,20,30])->-6; + ?column? +---------- + -30 +(1 row) + -- Load some example data and build the index -- CREATE TABLE test_cube (c cube); @@ -1407,3 +1511,199 @@ SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c; (2424, 160),(2424, 81) (5 rows) +-- kNN with index +SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist +-------------------------+------------------ + (337, 455),(240, 359) | 0 + (759, 187),(662, 163) | 162 + (948, 1201),(907, 1156) | 772.000647668122 + (1444, 403),(1346, 344) | 846 + (369, 1457),(278, 1409) | 909 +(5 rows) + +SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist +-------------------------+------ + (337, 455),(240, 359) | 0 + (759, 187),(662, 163) | 162 + (948, 1201),(907, 1156) | 656 + (1444, 403),(1346, 344) | 846 + (369, 1457),(278, 1409) | 909 +(5 rows) + +SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist +-------------------------+------ + (337, 455),(240, 359) | 0 + (759, 187),(662, 163) | 162 + (1444, 403),(1346, 344) | 846 + (369, 1457),(278, 1409) | 909 + (948, 1201),(907, 1156) | 1063 +(5 rows) + +-- kNN-based sorting +SELECT * FROM test_cube ORDER BY c->1 LIMIT 15; -- ascending by 1st coordinate + c +--------------------------- + (54, 38679),(3, 38602) + (83, 10271),(15, 10265) + (122, 46832),(64, 46762) + (167, 17214),(92, 17184) + (161, 24465),(107, 24374) + (162, 26040),(120, 25963) + (154, 4019),(138, 3990) + (259, 1850),(175, 1820) + (207, 40886),(179, 40879) + (288, 49588),(204, 49571) + (270, 32616),(226, 32607) + (318, 31489),(235, 31404) + (337, 455),(240, 359) + (270, 29508),(264, 29440) + (369, 1457),(278, 1409) +(15 rows) + +SELECT * FROM test_cube ORDER BY c->4 LIMIT 15; -- ascending by 4th coordinate + c +--------------------------- + (30333, 50),(30273, 6) + (43301, 75),(43227, 43) + (19650, 142),(19630, 51) + (2424, 160),(2424, 81) + (3449, 171),(3354, 108) + (18037, 155),(17941, 109) + (28511, 208),(28479, 114) + (19946, 217),(19941, 118) + (16906, 191),(16816, 139) + (759, 187),(662, 163) + (22684, 266),(22656, 181) + (24423, 255),(24360, 213) + (45989, 249),(45910, 222) + (11399, 377),(11360, 294) + (12162, 389),(12103, 309) +(15 rows) + +SELECT * FROM test_cube ORDER BY c->-1 LIMIT 15; -- descending by 1st coordinate + c +------------------------------- + (50027, 49230),(49951, 49214) + (49999, 27218),(49908, 27176) + (49985, 6436),(49927, 6338) + (49981, 34876),(49898, 34786) + (49980, 35004),(49937, 34963) + (49957, 43390),(49897, 43384) + (49954, 1340),(49905, 1294) + (49944, 25163),(49902, 25153) + (49907, 30225),(49810, 30158) + (49902, 41752),(49818, 41746) + (49887, 24274),(49805, 24184) + (49853, 18504),(49848, 18503) + (49847, 7128),(49798, 7067) + (49843, 5175),(49808, 5145) + (49836, 35965),(49757, 35871) +(15 rows) + +SELECT * FROM test_cube ORDER BY c->-4 LIMIT 15; -- descending by 4th coordinate + c +------------------------------- + (36311, 50073),(36258, 49987) + (30746, 50040),(30727, 49992) + (2168, 50012),(2108, 49914) + (21551, 49983),(21492, 49885) + (17954, 49975),(17865, 49915) + (3531, 49962),(3463, 49934) + (19128, 49932),(19112, 49849) + (31287, 49923),(31236, 49913) + (43925, 49912),(43888, 49878) + (29261, 49910),(29247, 49818) + (14913, 49873),(14849, 49836) + (20007, 49858),(19921, 49778) + (38266, 49852),(38233, 49844) + (37595, 49849),(37581, 49834) + (46151, 49848),(46058, 49830) +(15 rows) + +-- same thing for index with points +CREATE TABLE test_point(c cube); +INSERT INTO test_point(SELECT cube(array[c->1,c->2,c->3,c->4]) FROM test_cube); +CREATE INDEX ON test_point USING gist(c); +SELECT * FROM test_point ORDER BY c->1 LIMIT 15; -- ascending by 1st coordinate + c +-------------------------- + (54, 38679, 3, 38602) + (83, 10271, 15, 10265) + (122, 46832, 64, 46762) + (154, 4019, 138, 3990) + (161, 24465, 107, 24374) + (162, 26040, 120, 25963) + (167, 17214, 92, 17184) + (207, 40886, 179, 40879) + (259, 1850, 175, 1820) + (270, 32616, 226, 32607) + (270, 29508, 264, 29440) + (288, 49588, 204, 49571) + (318, 31489, 235, 31404) + (326, 18837, 285, 18817) + (337, 455, 240, 359) +(15 rows) + +SELECT * FROM test_point ORDER BY c->5 LIMIT 15; -- should be the same as previous + c +-------------------------- + (54, 38679, 3, 38602) + (83, 10271, 15, 10265) + (122, 46832, 64, 46762) + (154, 4019, 138, 3990) + (161, 24465, 107, 24374) + (162, 26040, 120, 25963) + (167, 17214, 92, 17184) + (207, 40886, 179, 40879) + (259, 1850, 175, 1820) + (270, 32616, 226, 32607) + (270, 29508, 264, 29440) + (288, 49588, 204, 49571) + (318, 31489, 235, 31404) + (326, 18837, 285, 18817) + (337, 455, 240, 359) +(15 rows) + +SELECT * FROM test_point ORDER BY c->-1 LIMIT 15; -- descending by 1st coordinate + c +------------------------------ + (50027, 49230, 49951, 49214) + (49999, 27218, 49908, 27176) + (49985, 6436, 49927, 6338) + (49981, 34876, 49898, 34786) + (49980, 35004, 49937, 34963) + (49957, 43390, 49897, 43384) + (49954, 1340, 49905, 1294) + (49944, 25163, 49902, 25153) + (49907, 30225, 49810, 30158) + (49902, 41752, 49818, 41746) + (49887, 24274, 49805, 24184) + (49853, 18504, 49848, 18503) + (49847, 7128, 49798, 7067) + (49843, 5175, 49808, 5145) + (49836, 35965, 49757, 35871) +(15 rows) + +SELECT * FROM test_point ORDER BY c->-5 LIMIT 15; -- should be the same as previous + c +------------------------------ + (50027, 49230, 49951, 49214) + (49999, 27218, 49908, 27176) + (49985, 6436, 49927, 6338) + (49981, 34876, 49898, 34786) + (49980, 35004, 49937, 34963) + (49957, 43390, 49897, 43384) + (49954, 1340, 49905, 1294) + (49944, 25163, 49902, 25153) + (49907, 30225, 49810, 30158) + (49902, 41752, 49818, 41746) + (49887, 24274, 49805, 24184) + (49853, 18504, 49848, 18503) + (49847, 7128, 49798, 7067) + (49843, 5175, 49808, 5145) + (49836, 35965, 49757, 35871) +(15 rows) + diff --git a/contrib/cube/expected/cube_1.out b/contrib/cube/expected/cube_1.out index c07d61d..b7acc5e 100644 --- a/contrib/cube/expected/cube_1.out +++ b/contrib/cube/expected/cube_1.out @@ -1381,6 +1381,110 @@ SELECT cube_size('(42,137)'::cube); 0 (1 row) +-- Test of distances +-- +SELECT distance_euclid('(1,1)'::cube, '(4,5)'::cube); + distance_euclid +----------------- + 5 +(1 row) + +SELECT '(1,1)'::cube <-> '(4,5)'::cube as d_e; + d_e +----- + 5 +(1 row) + +SELECT distance_chebyshev('(1,1)'::cube, '(4,5)'::cube); + distance_chebyshev +-------------------- + 4 +(1 row) + +SELECT '(1,1)'::cube <=> '(4,5)'::cube as d_c; + d_c +----- + 4 +(1 row) + +SELECT distance_taxicab('(1,1)'::cube, '(4,5)'::cube); + distance_taxicab +------------------ + 7 +(1 row) + +SELECT '(1,1)'::cube <#> '(4,5)'::cube as d_t; + d_t +----- + 7 +(1 row) + +-- zero for overlapping +SELECT distance_euclid('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); + distance_euclid +----------------- + 0 +(1 row) + +SELECT distance_chebyshev('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); + distance_chebyshev +-------------------- + 0 +(1 row) + +SELECT distance_taxicab('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); + distance_taxicab +------------------ + 0 +(1 row) + +-- coordinate access +SELECT cube(array[10,20,30], array[40,50,60])->1; + ?column? +---------- + 10 +(1 row) + +SELECT cube(array[10,20,30], array[40,50,60])->6; + ?column? +---------- + 60 +(1 row) + +SELECT cube(array[10,20,30], array[40,50,60])->0; +ERROR: Index out of bounds +SELECT cube(array[10,20,30], array[40,50,60])->7; +ERROR: Index out of bounds +SELECT cube(array[10,20,30], array[40,50,60])->-1; + ?column? +---------- + -10 +(1 row) + +SELECT cube(array[10,20,30], array[40,50,60])->-6; + ?column? +---------- + -60 +(1 row) + +SELECT cube(array[10,20,30])->3; + ?column? +---------- + 30 +(1 row) + +SELECT cube(array[10,20,30])->6; + ?column? +---------- + 30 +(1 row) + +SELECT cube(array[10,20,30])->-6; + ?column? +---------- + -30 +(1 row) + -- Load some example data and build the index -- CREATE TABLE test_cube (c cube); @@ -1407,3 +1511,199 @@ SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c; (2424, 160),(2424, 81) (5 rows) +-- kNN with index +SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist +-------------------------+------------------ + (337, 455),(240, 359) | 0 + (759, 187),(662, 163) | 162 + (948, 1201),(907, 1156) | 772.000647668122 + (1444, 403),(1346, 344) | 846 + (369, 1457),(278, 1409) | 909 +(5 rows) + +SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist +-------------------------+------ + (337, 455),(240, 359) | 0 + (759, 187),(662, 163) | 162 + (948, 1201),(907, 1156) | 656 + (1444, 403),(1346, 344) | 846 + (369, 1457),(278, 1409) | 909 +(5 rows) + +SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist +-------------------------+------ + (337, 455),(240, 359) | 0 + (759, 187),(662, 163) | 162 + (1444, 403),(1346, 344) | 846 + (369, 1457),(278, 1409) | 909 + (948, 1201),(907, 1156) | 1063 +(5 rows) + +-- kNN-based sorting +SELECT * FROM test_cube ORDER BY c->1 LIMIT 15; -- ascending by 1st coordinate + c +--------------------------- + (54, 38679),(3, 38602) + (83, 10271),(15, 10265) + (122, 46832),(64, 46762) + (167, 17214),(92, 17184) + (161, 24465),(107, 24374) + (162, 26040),(120, 25963) + (154, 4019),(138, 3990) + (259, 1850),(175, 1820) + (207, 40886),(179, 40879) + (288, 49588),(204, 49571) + (270, 32616),(226, 32607) + (318, 31489),(235, 31404) + (337, 455),(240, 359) + (270, 29508),(264, 29440) + (369, 1457),(278, 1409) +(15 rows) + +SELECT * FROM test_cube ORDER BY c->4 LIMIT 15; -- ascending by 4th coordinate + c +--------------------------- + (30333, 50),(30273, 6) + (43301, 75),(43227, 43) + (19650, 142),(19630, 51) + (2424, 160),(2424, 81) + (3449, 171),(3354, 108) + (18037, 155),(17941, 109) + (28511, 208),(28479, 114) + (19946, 217),(19941, 118) + (16906, 191),(16816, 139) + (759, 187),(662, 163) + (22684, 266),(22656, 181) + (24423, 255),(24360, 213) + (45989, 249),(45910, 222) + (11399, 377),(11360, 294) + (12162, 389),(12103, 309) +(15 rows) + +SELECT * FROM test_cube ORDER BY c->-1 LIMIT 15; -- descending by 1st coordinate + c +------------------------------- + (50027, 49230),(49951, 49214) + (49999, 27218),(49908, 27176) + (49985, 6436),(49927, 6338) + (49981, 34876),(49898, 34786) + (49980, 35004),(49937, 34963) + (49957, 43390),(49897, 43384) + (49954, 1340),(49905, 1294) + (49944, 25163),(49902, 25153) + (49907, 30225),(49810, 30158) + (49902, 41752),(49818, 41746) + (49887, 24274),(49805, 24184) + (49853, 18504),(49848, 18503) + (49847, 7128),(49798, 7067) + (49843, 5175),(49808, 5145) + (49836, 35965),(49757, 35871) +(15 rows) + +SELECT * FROM test_cube ORDER BY c->-4 LIMIT 15; -- descending by 4th coordinate + c +------------------------------- + (36311, 50073),(36258, 49987) + (30746, 50040),(30727, 49992) + (2168, 50012),(2108, 49914) + (21551, 49983),(21492, 49885) + (17954, 49975),(17865, 49915) + (3531, 49962),(3463, 49934) + (19128, 49932),(19112, 49849) + (31287, 49923),(31236, 49913) + (43925, 49912),(43888, 49878) + (29261, 49910),(29247, 49818) + (14913, 49873),(14849, 49836) + (20007, 49858),(19921, 49778) + (38266, 49852),(38233, 49844) + (37595, 49849),(37581, 49834) + (46151, 49848),(46058, 49830) +(15 rows) + +-- same thing for index with points +CREATE TABLE test_point(c cube); +INSERT INTO test_point(SELECT cube(array[c->1,c->2,c->3,c->4]) FROM test_cube); +CREATE INDEX ON test_point USING gist(c); +SELECT * FROM test_point ORDER BY c->1 LIMIT 15; -- ascending by 1st coordinate + c +-------------------------- + (54, 38679, 3, 38602) + (83, 10271, 15, 10265) + (122, 46832, 64, 46762) + (154, 4019, 138, 3990) + (161, 24465, 107, 24374) + (162, 26040, 120, 25963) + (167, 17214, 92, 17184) + (207, 40886, 179, 40879) + (259, 1850, 175, 1820) + (270, 32616, 226, 32607) + (270, 29508, 264, 29440) + (288, 49588, 204, 49571) + (318, 31489, 235, 31404) + (326, 18837, 285, 18817) + (337, 455, 240, 359) +(15 rows) + +SELECT * FROM test_point ORDER BY c->5 LIMIT 15; -- should be the same as previous + c +-------------------------- + (54, 38679, 3, 38602) + (83, 10271, 15, 10265) + (122, 46832, 64, 46762) + (154, 4019, 138, 3990) + (161, 24465, 107, 24374) + (162, 26040, 120, 25963) + (167, 17214, 92, 17184) + (207, 40886, 179, 40879) + (259, 1850, 175, 1820) + (270, 32616, 226, 32607) + (270, 29508, 264, 29440) + (288, 49588, 204, 49571) + (318, 31489, 235, 31404) + (326, 18837, 285, 18817) + (337, 455, 240, 359) +(15 rows) + +SELECT * FROM test_point ORDER BY c->-1 LIMIT 15; -- descending by 1st coordinate + c +------------------------------ + (50027, 49230, 49951, 49214) + (49999, 27218, 49908, 27176) + (49985, 6436, 49927, 6338) + (49981, 34876, 49898, 34786) + (49980, 35004, 49937, 34963) + (49957, 43390, 49897, 43384) + (49954, 1340, 49905, 1294) + (49944, 25163, 49902, 25153) + (49907, 30225, 49810, 30158) + (49902, 41752, 49818, 41746) + (49887, 24274, 49805, 24184) + (49853, 18504, 49848, 18503) + (49847, 7128, 49798, 7067) + (49843, 5175, 49808, 5145) + (49836, 35965, 49757, 35871) +(15 rows) + +SELECT * FROM test_point ORDER BY c->-5 LIMIT 15; -- should be the same as previous + c +------------------------------ + (50027, 49230, 49951, 49214) + (49999, 27218, 49908, 27176) + (49985, 6436, 49927, 6338) + (49981, 34876, 49898, 34786) + (49980, 35004, 49937, 34963) + (49957, 43390, 49897, 43384) + (49954, 1340, 49905, 1294) + (49944, 25163, 49902, 25153) + (49907, 30225, 49810, 30158) + (49902, 41752, 49818, 41746) + (49887, 24274, 49805, 24184) + (49853, 18504, 49848, 18503) + (49847, 7128, 49798, 7067) + (49843, 5175, 49808, 5145) + (49836, 35965, 49757, 35871) +(15 rows) + diff --git a/contrib/cube/expected/cube_2.out b/contrib/cube/expected/cube_2.out index 3767d0e..964dc6b 100644 --- a/contrib/cube/expected/cube_2.out +++ b/contrib/cube/expected/cube_2.out @@ -1381,6 +1381,110 @@ SELECT cube_size('(42,137)'::cube); 0 (1 row) +-- Test of distances +-- +SELECT distance_euclid('(1,1)'::cube, '(4,5)'::cube); + distance_euclid +----------------- + 5 +(1 row) + +SELECT '(1,1)'::cube <-> '(4,5)'::cube as d_e; + d_e +----- + 5 +(1 row) + +SELECT distance_chebyshev('(1,1)'::cube, '(4,5)'::cube); + distance_chebyshev +-------------------- + 4 +(1 row) + +SELECT '(1,1)'::cube <=> '(4,5)'::cube as d_c; + d_c +----- + 4 +(1 row) + +SELECT distance_taxicab('(1,1)'::cube, '(4,5)'::cube); + distance_taxicab +------------------ + 7 +(1 row) + +SELECT '(1,1)'::cube <#> '(4,5)'::cube as d_t; + d_t +----- + 7 +(1 row) + +-- zero for overlapping +SELECT distance_euclid('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); + distance_euclid +----------------- + 0 +(1 row) + +SELECT distance_chebyshev('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); + distance_chebyshev +-------------------- + 0 +(1 row) + +SELECT distance_taxicab('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); + distance_taxicab +------------------ + 0 +(1 row) + +-- coordinate access +SELECT cube(array[10,20,30], array[40,50,60])->1; + ?column? +---------- + 10 +(1 row) + +SELECT cube(array[10,20,30], array[40,50,60])->6; + ?column? +---------- + 60 +(1 row) + +SELECT cube(array[10,20,30], array[40,50,60])->0; +ERROR: Index out of bounds +SELECT cube(array[10,20,30], array[40,50,60])->7; +ERROR: Index out of bounds +SELECT cube(array[10,20,30], array[40,50,60])->-1; + ?column? +---------- + -10 +(1 row) + +SELECT cube(array[10,20,30], array[40,50,60])->-6; + ?column? +---------- + -60 +(1 row) + +SELECT cube(array[10,20,30])->3; + ?column? +---------- + 30 +(1 row) + +SELECT cube(array[10,20,30])->6; + ?column? +---------- + 30 +(1 row) + +SELECT cube(array[10,20,30])->-6; + ?column? +---------- + -30 +(1 row) + -- Load some example data and build the index -- CREATE TABLE test_cube (c cube); @@ -1407,3 +1511,199 @@ SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c; (2424, 160),(2424, 81) (5 rows) +-- kNN with index +SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist +-------------------------+------------------ + (337, 455),(240, 359) | 0 + (759, 187),(662, 163) | 162 + (948, 1201),(907, 1156) | 772.000647668122 + (1444, 403),(1346, 344) | 846 + (369, 1457),(278, 1409) | 909 +(5 rows) + +SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist +-------------------------+------ + (337, 455),(240, 359) | 0 + (759, 187),(662, 163) | 162 + (948, 1201),(907, 1156) | 656 + (1444, 403),(1346, 344) | 846 + (369, 1457),(278, 1409) | 909 +(5 rows) + +SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist +-------------------------+------ + (337, 455),(240, 359) | 0 + (759, 187),(662, 163) | 162 + (1444, 403),(1346, 344) | 846 + (369, 1457),(278, 1409) | 909 + (948, 1201),(907, 1156) | 1063 +(5 rows) + +-- kNN-based sorting +SELECT * FROM test_cube ORDER BY c->1 LIMIT 15; -- ascending by 1st coordinate + c +--------------------------- + (54, 38679),(3, 38602) + (83, 10271),(15, 10265) + (122, 46832),(64, 46762) + (167, 17214),(92, 17184) + (161, 24465),(107, 24374) + (162, 26040),(120, 25963) + (154, 4019),(138, 3990) + (259, 1850),(175, 1820) + (207, 40886),(179, 40879) + (288, 49588),(204, 49571) + (270, 32616),(226, 32607) + (318, 31489),(235, 31404) + (337, 455),(240, 359) + (270, 29508),(264, 29440) + (369, 1457),(278, 1409) +(15 rows) + +SELECT * FROM test_cube ORDER BY c->4 LIMIT 15; -- ascending by 4th coordinate + c +--------------------------- + (30333, 50),(30273, 6) + (43301, 75),(43227, 43) + (19650, 142),(19630, 51) + (2424, 160),(2424, 81) + (3449, 171),(3354, 108) + (18037, 155),(17941, 109) + (28511, 208),(28479, 114) + (19946, 217),(19941, 118) + (16906, 191),(16816, 139) + (759, 187),(662, 163) + (22684, 266),(22656, 181) + (24423, 255),(24360, 213) + (45989, 249),(45910, 222) + (11399, 377),(11360, 294) + (12162, 389),(12103, 309) +(15 rows) + +SELECT * FROM test_cube ORDER BY c->-1 LIMIT 15; -- descending by 1st coordinate + c +------------------------------- + (50027, 49230),(49951, 49214) + (49999, 27218),(49908, 27176) + (49985, 6436),(49927, 6338) + (49981, 34876),(49898, 34786) + (49980, 35004),(49937, 34963) + (49957, 43390),(49897, 43384) + (49954, 1340),(49905, 1294) + (49944, 25163),(49902, 25153) + (49907, 30225),(49810, 30158) + (49902, 41752),(49818, 41746) + (49887, 24274),(49805, 24184) + (49853, 18504),(49848, 18503) + (49847, 7128),(49798, 7067) + (49843, 5175),(49808, 5145) + (49836, 35965),(49757, 35871) +(15 rows) + +SELECT * FROM test_cube ORDER BY c->-4 LIMIT 15; -- descending by 4th coordinate + c +------------------------------- + (36311, 50073),(36258, 49987) + (30746, 50040),(30727, 49992) + (2168, 50012),(2108, 49914) + (21551, 49983),(21492, 49885) + (17954, 49975),(17865, 49915) + (3531, 49962),(3463, 49934) + (19128, 49932),(19112, 49849) + (31287, 49923),(31236, 49913) + (43925, 49912),(43888, 49878) + (29261, 49910),(29247, 49818) + (14913, 49873),(14849, 49836) + (20007, 49858),(19921, 49778) + (38266, 49852),(38233, 49844) + (37595, 49849),(37581, 49834) + (46151, 49848),(46058, 49830) +(15 rows) + +-- same thing for index with points +CREATE TABLE test_point(c cube); +INSERT INTO test_point(SELECT cube(array[c->1,c->2,c->3,c->4]) FROM test_cube); +CREATE INDEX ON test_point USING gist(c); +SELECT * FROM test_point ORDER BY c->1 LIMIT 15; -- ascending by 1st coordinate + c +-------------------------- + (54, 38679, 3, 38602) + (83, 10271, 15, 10265) + (122, 46832, 64, 46762) + (154, 4019, 138, 3990) + (161, 24465, 107, 24374) + (162, 26040, 120, 25963) + (167, 17214, 92, 17184) + (207, 40886, 179, 40879) + (259, 1850, 175, 1820) + (270, 32616, 226, 32607) + (270, 29508, 264, 29440) + (288, 49588, 204, 49571) + (318, 31489, 235, 31404) + (326, 18837, 285, 18817) + (337, 455, 240, 359) +(15 rows) + +SELECT * FROM test_point ORDER BY c->5 LIMIT 15; -- should be the same as previous + c +-------------------------- + (54, 38679, 3, 38602) + (83, 10271, 15, 10265) + (122, 46832, 64, 46762) + (154, 4019, 138, 3990) + (161, 24465, 107, 24374) + (162, 26040, 120, 25963) + (167, 17214, 92, 17184) + (207, 40886, 179, 40879) + (259, 1850, 175, 1820) + (270, 32616, 226, 32607) + (270, 29508, 264, 29440) + (288, 49588, 204, 49571) + (318, 31489, 235, 31404) + (326, 18837, 285, 18817) + (337, 455, 240, 359) +(15 rows) + +SELECT * FROM test_point ORDER BY c->-1 LIMIT 15; -- descending by 1st coordinate + c +------------------------------ + (50027, 49230, 49951, 49214) + (49999, 27218, 49908, 27176) + (49985, 6436, 49927, 6338) + (49981, 34876, 49898, 34786) + (49980, 35004, 49937, 34963) + (49957, 43390, 49897, 43384) + (49954, 1340, 49905, 1294) + (49944, 25163, 49902, 25153) + (49907, 30225, 49810, 30158) + (49902, 41752, 49818, 41746) + (49887, 24274, 49805, 24184) + (49853, 18504, 49848, 18503) + (49847, 7128, 49798, 7067) + (49843, 5175, 49808, 5145) + (49836, 35965, 49757, 35871) +(15 rows) + +SELECT * FROM test_point ORDER BY c->-5 LIMIT 15; -- should be the same as previous + c +------------------------------ + (50027, 49230, 49951, 49214) + (49999, 27218, 49908, 27176) + (49985, 6436, 49927, 6338) + (49981, 34876, 49898, 34786) + (49980, 35004, 49937, 34963) + (49957, 43390, 49897, 43384) + (49954, 1340, 49905, 1294) + (49944, 25163, 49902, 25153) + (49907, 30225, 49810, 30158) + (49902, 41752, 49818, 41746) + (49887, 24274, 49805, 24184) + (49853, 18504, 49848, 18503) + (49847, 7128, 49798, 7067) + (49843, 5175, 49808, 5145) + (49836, 35965, 49757, 35871) +(15 rows) + diff --git a/contrib/cube/expected/cube_3.out b/contrib/cube/expected/cube_3.out index 2aa42be..7868514 100644 --- a/contrib/cube/expected/cube_3.out +++ b/contrib/cube/expected/cube_3.out @@ -1381,6 +1381,110 @@ SELECT cube_size('(42,137)'::cube); 0 (1 row) +-- Test of distances +-- +SELECT distance_euclid('(1,1)'::cube, '(4,5)'::cube); + distance_euclid +----------------- + 5 +(1 row) + +SELECT '(1,1)'::cube <-> '(4,5)'::cube as d_e; + d_e +----- + 5 +(1 row) + +SELECT distance_chebyshev('(1,1)'::cube, '(4,5)'::cube); + distance_chebyshev +-------------------- + 4 +(1 row) + +SELECT '(1,1)'::cube <=> '(4,5)'::cube as d_c; + d_c +----- + 4 +(1 row) + +SELECT distance_taxicab('(1,1)'::cube, '(4,5)'::cube); + distance_taxicab +------------------ + 7 +(1 row) + +SELECT '(1,1)'::cube <#> '(4,5)'::cube as d_t; + d_t +----- + 7 +(1 row) + +-- zero for overlapping +SELECT distance_euclid('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); + distance_euclid +----------------- + 0 +(1 row) + +SELECT distance_chebyshev('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); + distance_chebyshev +-------------------- + 0 +(1 row) + +SELECT distance_taxicab('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); + distance_taxicab +------------------ + 0 +(1 row) + +-- coordinate access +SELECT cube(array[10,20,30], array[40,50,60])->1; + ?column? +---------- + 10 +(1 row) + +SELECT cube(array[10,20,30], array[40,50,60])->6; + ?column? +---------- + 60 +(1 row) + +SELECT cube(array[10,20,30], array[40,50,60])->0; +ERROR: Index out of bounds +SELECT cube(array[10,20,30], array[40,50,60])->7; +ERROR: Index out of bounds +SELECT cube(array[10,20,30], array[40,50,60])->-1; + ?column? +---------- + -10 +(1 row) + +SELECT cube(array[10,20,30], array[40,50,60])->-6; + ?column? +---------- + -60 +(1 row) + +SELECT cube(array[10,20,30])->3; + ?column? +---------- + 30 +(1 row) + +SELECT cube(array[10,20,30])->6; + ?column? +---------- + 30 +(1 row) + +SELECT cube(array[10,20,30])->-6; + ?column? +---------- + -30 +(1 row) + -- Load some example data and build the index -- CREATE TABLE test_cube (c cube); @@ -1407,3 +1511,199 @@ SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c; (2424, 160),(2424, 81) (5 rows) +-- kNN with index +SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist +-------------------------+------------------ + (337, 455),(240, 359) | 0 + (759, 187),(662, 163) | 162 + (948, 1201),(907, 1156) | 772.000647668122 + (1444, 403),(1346, 344) | 846 + (369, 1457),(278, 1409) | 909 +(5 rows) + +SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist +-------------------------+------ + (337, 455),(240, 359) | 0 + (759, 187),(662, 163) | 162 + (948, 1201),(907, 1156) | 656 + (1444, 403),(1346, 344) | 846 + (369, 1457),(278, 1409) | 909 +(5 rows) + +SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist +-------------------------+------ + (337, 455),(240, 359) | 0 + (759, 187),(662, 163) | 162 + (1444, 403),(1346, 344) | 846 + (369, 1457),(278, 1409) | 909 + (948, 1201),(907, 1156) | 1063 +(5 rows) + +-- kNN-based sorting +SELECT * FROM test_cube ORDER BY c->1 LIMIT 15; -- ascending by 1st coordinate + c +--------------------------- + (54, 38679),(3, 38602) + (83, 10271),(15, 10265) + (122, 46832),(64, 46762) + (167, 17214),(92, 17184) + (161, 24465),(107, 24374) + (162, 26040),(120, 25963) + (154, 4019),(138, 3990) + (259, 1850),(175, 1820) + (207, 40886),(179, 40879) + (288, 49588),(204, 49571) + (270, 32616),(226, 32607) + (318, 31489),(235, 31404) + (337, 455),(240, 359) + (270, 29508),(264, 29440) + (369, 1457),(278, 1409) +(15 rows) + +SELECT * FROM test_cube ORDER BY c->4 LIMIT 15; -- ascending by 4th coordinate + c +--------------------------- + (30333, 50),(30273, 6) + (43301, 75),(43227, 43) + (19650, 142),(19630, 51) + (2424, 160),(2424, 81) + (3449, 171),(3354, 108) + (18037, 155),(17941, 109) + (28511, 208),(28479, 114) + (19946, 217),(19941, 118) + (16906, 191),(16816, 139) + (759, 187),(662, 163) + (22684, 266),(22656, 181) + (24423, 255),(24360, 213) + (45989, 249),(45910, 222) + (11399, 377),(11360, 294) + (12162, 389),(12103, 309) +(15 rows) + +SELECT * FROM test_cube ORDER BY c->-1 LIMIT 15; -- descending by 1st coordinate + c +------------------------------- + (50027, 49230),(49951, 49214) + (49999, 27218),(49908, 27176) + (49985, 6436),(49927, 6338) + (49981, 34876),(49898, 34786) + (49980, 35004),(49937, 34963) + (49957, 43390),(49897, 43384) + (49954, 1340),(49905, 1294) + (49944, 25163),(49902, 25153) + (49907, 30225),(49810, 30158) + (49902, 41752),(49818, 41746) + (49887, 24274),(49805, 24184) + (49853, 18504),(49848, 18503) + (49847, 7128),(49798, 7067) + (49843, 5175),(49808, 5145) + (49836, 35965),(49757, 35871) +(15 rows) + +SELECT * FROM test_cube ORDER BY c->-4 LIMIT 15; -- descending by 4th coordinate + c +------------------------------- + (36311, 50073),(36258, 49987) + (30746, 50040),(30727, 49992) + (2168, 50012),(2108, 49914) + (21551, 49983),(21492, 49885) + (17954, 49975),(17865, 49915) + (3531, 49962),(3463, 49934) + (19128, 49932),(19112, 49849) + (31287, 49923),(31236, 49913) + (43925, 49912),(43888, 49878) + (29261, 49910),(29247, 49818) + (14913, 49873),(14849, 49836) + (20007, 49858),(19921, 49778) + (38266, 49852),(38233, 49844) + (37595, 49849),(37581, 49834) + (46151, 49848),(46058, 49830) +(15 rows) + +-- same thing for index with points +CREATE TABLE test_point(c cube); +INSERT INTO test_point(SELECT cube(array[c->1,c->2,c->3,c->4]) FROM test_cube); +CREATE INDEX ON test_point USING gist(c); +SELECT * FROM test_point ORDER BY c->1 LIMIT 15; -- ascending by 1st coordinate + c +-------------------------- + (54, 38679, 3, 38602) + (83, 10271, 15, 10265) + (122, 46832, 64, 46762) + (154, 4019, 138, 3990) + (161, 24465, 107, 24374) + (162, 26040, 120, 25963) + (167, 17214, 92, 17184) + (207, 40886, 179, 40879) + (259, 1850, 175, 1820) + (270, 32616, 226, 32607) + (270, 29508, 264, 29440) + (288, 49588, 204, 49571) + (318, 31489, 235, 31404) + (326, 18837, 285, 18817) + (337, 455, 240, 359) +(15 rows) + +SELECT * FROM test_point ORDER BY c->5 LIMIT 15; -- should be the same as previous + c +-------------------------- + (54, 38679, 3, 38602) + (83, 10271, 15, 10265) + (122, 46832, 64, 46762) + (154, 4019, 138, 3990) + (161, 24465, 107, 24374) + (162, 26040, 120, 25963) + (167, 17214, 92, 17184) + (207, 40886, 179, 40879) + (259, 1850, 175, 1820) + (270, 32616, 226, 32607) + (270, 29508, 264, 29440) + (288, 49588, 204, 49571) + (318, 31489, 235, 31404) + (326, 18837, 285, 18817) + (337, 455, 240, 359) +(15 rows) + +SELECT * FROM test_point ORDER BY c->-1 LIMIT 15; -- descending by 1st coordinate + c +------------------------------ + (50027, 49230, 49951, 49214) + (49999, 27218, 49908, 27176) + (49985, 6436, 49927, 6338) + (49981, 34876, 49898, 34786) + (49980, 35004, 49937, 34963) + (49957, 43390, 49897, 43384) + (49954, 1340, 49905, 1294) + (49944, 25163, 49902, 25153) + (49907, 30225, 49810, 30158) + (49902, 41752, 49818, 41746) + (49887, 24274, 49805, 24184) + (49853, 18504, 49848, 18503) + (49847, 7128, 49798, 7067) + (49843, 5175, 49808, 5145) + (49836, 35965, 49757, 35871) +(15 rows) + +SELECT * FROM test_point ORDER BY c->-5 LIMIT 15; -- should be the same as previous + c +------------------------------ + (50027, 49230, 49951, 49214) + (49999, 27218, 49908, 27176) + (49985, 6436, 49927, 6338) + (49981, 34876, 49898, 34786) + (49980, 35004, 49937, 34963) + (49957, 43390, 49897, 43384) + (49954, 1340, 49905, 1294) + (49944, 25163, 49902, 25153) + (49907, 30225, 49810, 30158) + (49902, 41752, 49818, 41746) + (49887, 24274, 49805, 24184) + (49853, 18504, 49848, 18503) + (49847, 7128, 49798, 7067) + (49843, 5175, 49808, 5145) + (49836, 35965, 49757, 35871) +(15 rows) + diff --git a/contrib/cube/sql/cube.sql b/contrib/cube/sql/cube.sql index d58974c..d914f72 100644 --- a/contrib/cube/sql/cube.sql +++ b/contrib/cube/sql/cube.sql @@ -325,6 +325,29 @@ SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args SELECT cube_size('(4,8),(15,16)'::cube); SELECT cube_size('(42,137)'::cube); +-- Test of distances +-- +SELECT distance_euclid('(1,1)'::cube, '(4,5)'::cube); +SELECT '(1,1)'::cube <-> '(4,5)'::cube as d_e; +SELECT distance_chebyshev('(1,1)'::cube, '(4,5)'::cube); +SELECT '(1,1)'::cube <=> '(4,5)'::cube as d_c; +SELECT distance_taxicab('(1,1)'::cube, '(4,5)'::cube); +SELECT '(1,1)'::cube <#> '(4,5)'::cube as d_t; +-- zero for overlapping +SELECT distance_euclid('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); +SELECT distance_chebyshev('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); +SELECT distance_taxicab('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube); +-- coordinate access +SELECT cube(array[10,20,30], array[40,50,60])->1; +SELECT cube(array[10,20,30], array[40,50,60])->6; +SELECT cube(array[10,20,30], array[40,50,60])->0; +SELECT cube(array[10,20,30], array[40,50,60])->7; +SELECT cube(array[10,20,30], array[40,50,60])->-1; +SELECT cube(array[10,20,30], array[40,50,60])->-6; +SELECT cube(array[10,20,30])->3; +SELECT cube(array[10,20,30])->6; +SELECT cube(array[10,20,30])->-6; + -- Load some example data and build the index -- CREATE TABLE test_cube (c cube); @@ -336,3 +359,24 @@ SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' ORDER BY c; -- Test sorting SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c; + +-- kNN with index +SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; +SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5; +SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5; + +-- kNN-based sorting +SELECT * FROM test_cube ORDER BY c->1 LIMIT 15; -- ascending by 1st coordinate +SELECT * FROM test_cube ORDER BY c->4 LIMIT 15; -- ascending by 4th coordinate +SELECT * FROM test_cube ORDER BY c->-1 LIMIT 15; -- descending by 1st coordinate +SELECT * FROM test_cube ORDER BY c->-4 LIMIT 15; -- descending by 4th coordinate + +-- same thing for index with points +CREATE TABLE test_point(c cube); +INSERT INTO test_point(SELECT cube(array[c->1,c->2,c->3,c->4]) FROM test_cube); +CREATE INDEX ON test_point USING gist(c); +SELECT * FROM test_point ORDER BY c->1 LIMIT 15; -- ascending by 1st coordinate +SELECT * FROM test_point ORDER BY c->5 LIMIT 15; -- should be the same as previous +SELECT * FROM test_point ORDER BY c->-1 LIMIT 15; -- descending by 1st coordinate +SELECT * FROM test_point ORDER BY c->-5 LIMIT 15; -- should be the same as previous +