jbe@0: jbe@0: CREATE EXTENSION latlon; jbe@0: jbe@0: CREATE TABLE "test" ( jbe@0: "id" SERIAL4 PRIMARY KEY, jbe@0: "location" EPOINT NOT NULL, jbe@10: "surrounding" ECIRCLE NOT NULL, jbe@10: "multipoint" ECLUSTER NOT NULL, jbe@46: "triangle" ECLUSTER NOT NULL, jbe@46: "votes" INT4 NOT NULL ); jbe@0: jbe@10: CREATE INDEX "test_location_key" ON "test" USING gist ("location"); jbe@10: CREATE INDEX "test_surrounding_key" ON "test" USING gist ("surrounding"); jbe@10: CREATE INDEX "test_multipoint_key" ON "test" USING gist ("multipoint"); jbe@10: CREATE INDEX "test_triangle_key" ON "test" USING gist ("triangle"); jbe@46: CREATE INDEX "test_vote_key" ON "test" ("votes"); jbe@0: jbe@46: jbe@46: -- Below follows an example of how to perform a nearest-neighbor search with jbe@46: -- weighted geometric objects (distance scaled anti-proportionally through jbe@46: -- "votes" column). jbe@46: -- jbe@46: -- NOTE: The approach may be speeded up by providing new data types like jbe@46: -- "weighted_ecluster" with corresponding GiST index support in future jbe@46: -- versions of pgLatLon. jbe@46: jbe@46: CREATE TYPE "test_with_relevance" AS ( jbe@46: "id" INT4, jbe@46: "location" EPOINT, jbe@46: "surrounding" ECIRCLE, jbe@46: "multipoint" ECLUSTER, jbe@46: "triangle" ECLUSTER, jbe@46: "votes" INT4, jbe@46: "relevance" FLOAT8 ); jbe@46: jbe@46: CREATE FUNCTION "get_by_relevance" (epoint, int4 = 1, int4 = 10000) jbe@46: RETURNS SETOF "test_with_relevance" jbe@46: LANGUAGE plpgsql STABLE AS $$ jbe@46: DECLARE jbe@46: "max_votes" INT4; jbe@46: "tries" INT4 = 2; jbe@46: "all" INT4; jbe@46: "matches" INT4; jbe@46: BEGIN jbe@46: SELECT "votes" INTO "max_votes" FROM "test" ORDER BY "votes" DESC LIMIT 1; jbe@46: IF "max_votes" > 0 THEN jbe@46: LOOP jbe@46: RAISE DEBUG 'Considering % entries', "tries"; jbe@46: SELECT jbe@46: count(1), jbe@46: count(CASE WHEN "relevance" < "worst_case" THEN 1 ELSE NULL END) jbe@46: INTO "all", "matches" jbe@46: FROM ( jbe@46: SELECT jbe@46: CASE jbe@46: WHEN "votes" = 0 jbe@46: THEN 'inf'::FLOAT8 jbe@46: ELSE "fair_distance" / "votes" jbe@46: END AS "relevance", jbe@46: max("fair_distance") OVER () / "max_votes" AS "worst_case" jbe@46: FROM ( jbe@46: SELECT fair_distance("triangle", $1, $3), "votes" FROM "test" jbe@46: ORDER BY fair_distance jbe@46: LIMIT "tries" jbe@46: ) AS "subquery1" jbe@46: ) AS "subquery2"; jbe@46: EXIT WHEN "matches" >= $2 OR "all" < "tries"; jbe@46: "tries" := "tries" * 2; jbe@46: END LOOP; jbe@46: RETURN QUERY SELECT * FROM ( jbe@46: SELECT jbe@46: *, jbe@46: CASE jbe@46: WHEN "votes" = 0 jbe@46: THEN 'inf'::FLOAT8 jbe@46: ELSE fair_distance("triangle", $1, $3) / "votes" jbe@46: END AS "relevance" jbe@46: FROM "test" ORDER BY fair_distance("triangle", $1, $3) LIMIT "tries" jbe@46: ) AS "subquery" ORDER BY "relevance", "id" LIMIT $2; jbe@46: ELSE jbe@46: RETURN QUERY SELECT * FROM "test" ORDER BY "id" LIMIT $2; jbe@46: END IF; jbe@46: RETURN; jbe@46: END; jbe@46: $$; jbe@46: