rev |
line source |
jbe@0
|
1
|
jbe@0
|
2 CREATE EXTENSION latlon;
|
jbe@0
|
3
|
jbe@0
|
4 CREATE TABLE "test" (
|
jbe@0
|
5 "id" SERIAL4 PRIMARY KEY,
|
jbe@0
|
6 "location" EPOINT NOT NULL,
|
jbe@10
|
7 "surrounding" ECIRCLE NOT NULL,
|
jbe@10
|
8 "multipoint" ECLUSTER NOT NULL,
|
jbe@46
|
9 "triangle" ECLUSTER NOT NULL,
|
jbe@46
|
10 "votes" INT4 NOT NULL );
|
jbe@0
|
11
|
jbe@10
|
12 CREATE INDEX "test_location_key" ON "test" USING gist ("location");
|
jbe@10
|
13 CREATE INDEX "test_surrounding_key" ON "test" USING gist ("surrounding");
|
jbe@10
|
14 CREATE INDEX "test_multipoint_key" ON "test" USING gist ("multipoint");
|
jbe@10
|
15 CREATE INDEX "test_triangle_key" ON "test" USING gist ("triangle");
|
jbe@46
|
16 CREATE INDEX "test_vote_key" ON "test" ("votes");
|
jbe@0
|
17
|
jbe@46
|
18
|
jbe@46
|
19 -- Below follows an example of how to perform a nearest-neighbor search with
|
jbe@46
|
20 -- weighted geometric objects (distance scaled anti-proportionally through
|
jbe@46
|
21 -- "votes" column).
|
jbe@46
|
22 --
|
jbe@46
|
23 -- NOTE: The approach may be speeded up by providing new data types like
|
jbe@46
|
24 -- "weighted_ecluster" with corresponding GiST index support in future
|
jbe@46
|
25 -- versions of pgLatLon.
|
jbe@46
|
26
|
jbe@46
|
27 CREATE TYPE "test_with_relevance" AS (
|
jbe@46
|
28 "id" INT4,
|
jbe@46
|
29 "location" EPOINT,
|
jbe@46
|
30 "surrounding" ECIRCLE,
|
jbe@46
|
31 "multipoint" ECLUSTER,
|
jbe@46
|
32 "triangle" ECLUSTER,
|
jbe@46
|
33 "votes" INT4,
|
jbe@46
|
34 "relevance" FLOAT8 );
|
jbe@46
|
35
|
jbe@46
|
36 CREATE FUNCTION "get_by_relevance" (epoint, int4 = 1, int4 = 10000)
|
jbe@46
|
37 RETURNS SETOF "test_with_relevance"
|
jbe@46
|
38 LANGUAGE plpgsql STABLE AS $$
|
jbe@46
|
39 DECLARE
|
jbe@46
|
40 "max_votes" INT4;
|
jbe@46
|
41 "tries" INT4 = 2;
|
jbe@46
|
42 "all" INT4;
|
jbe@46
|
43 "matches" INT4;
|
jbe@46
|
44 BEGIN
|
jbe@46
|
45 SELECT "votes" INTO "max_votes" FROM "test" ORDER BY "votes" DESC LIMIT 1;
|
jbe@46
|
46 IF "max_votes" > 0 THEN
|
jbe@46
|
47 LOOP
|
jbe@46
|
48 RAISE DEBUG 'Considering % entries', "tries";
|
jbe@46
|
49 SELECT
|
jbe@46
|
50 count(1),
|
jbe@46
|
51 count(CASE WHEN "relevance" < "worst_case" THEN 1 ELSE NULL END)
|
jbe@46
|
52 INTO "all", "matches"
|
jbe@46
|
53 FROM (
|
jbe@46
|
54 SELECT
|
jbe@46
|
55 CASE
|
jbe@46
|
56 WHEN "votes" = 0
|
jbe@46
|
57 THEN 'inf'::FLOAT8
|
jbe@46
|
58 ELSE "fair_distance" / "votes"
|
jbe@46
|
59 END AS "relevance",
|
jbe@46
|
60 max("fair_distance") OVER () / "max_votes" AS "worst_case"
|
jbe@46
|
61 FROM (
|
jbe@46
|
62 SELECT fair_distance("triangle", $1, $3), "votes" FROM "test"
|
jbe@46
|
63 ORDER BY fair_distance
|
jbe@46
|
64 LIMIT "tries"
|
jbe@46
|
65 ) AS "subquery1"
|
jbe@46
|
66 ) AS "subquery2";
|
jbe@46
|
67 EXIT WHEN "matches" >= $2 OR "all" < "tries";
|
jbe@46
|
68 "tries" := "tries" * 2;
|
jbe@46
|
69 END LOOP;
|
jbe@46
|
70 RETURN QUERY SELECT * FROM (
|
jbe@46
|
71 SELECT
|
jbe@46
|
72 *,
|
jbe@46
|
73 CASE
|
jbe@46
|
74 WHEN "votes" = 0
|
jbe@46
|
75 THEN 'inf'::FLOAT8
|
jbe@46
|
76 ELSE fair_distance("triangle", $1, $3) / "votes"
|
jbe@46
|
77 END AS "relevance"
|
jbe@46
|
78 FROM "test" ORDER BY fair_distance("triangle", $1, $3) LIMIT "tries"
|
jbe@46
|
79 ) AS "subquery" ORDER BY "relevance", "id" LIMIT $2;
|
jbe@46
|
80 ELSE
|
jbe@46
|
81 RETURN QUERY SELECT * FROM "test" ORDER BY "id" LIMIT $2;
|
jbe@46
|
82 END IF;
|
jbe@46
|
83 RETURN;
|
jbe@46
|
84 END;
|
jbe@46
|
85 $$;
|
jbe@46
|
86
|