Context
Я создаю расширение Postgres, которое добавляет возможность задавать нечеткие запросы с лингвистическими переменными. Например:
SELECT age~=('age'|>'adult') FROM people;
вернет достоверность того факта, что человек является взрослым (взрослый определяется как трапециевидная функция 30/40~60\65
.
Задача
Я сделал функцию, которая позволяет возвращать лингвистическое имя для указанного значения и лингвистической переменной:
SELECT age, age~>'age' FROM people;
возвращает
age | age~>'age'
-----+--------------
20 | young adult
10 | child
45 | adult
60 | old
Источник этой функции и оператор выглядит так:
CREATE FUNCTION get_fuzzy_name(
input FLOAT8,
type_name VARCHAR(64)
) RETURNS VARCHAR(64) AS $$
DECLARE
type_id fuzzy.types.id%TYPE;
deg FLOAT8;
result_name VARCHAR(64);
BEGIN
type_id := get_fuzzy_type(type_name); -- returns type's id based on it's name
SELECT
degree(input, fun) AS d, name
INTO
deg, result_name
FROM fuzzy.functions
WHERE type=type_id
ORDER BY d DESC LIMIT 1;
IF deg=0 THEN
RETURN NULL;
END IF;
RETURN result_name;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT;
CREATE OPERATOR ~> (
PROCEDURE = get_fuzzy_name,
LEFTARG = FLOAT8,
RIGHTARG = VARCHAR(64)
);
Проблема в том, что для каждой строки указанная выше функция запрашивает нечеткий тип и выполняет функции снова и снова. Итак, я придумал это как основу для улучшений (нечеткие функции хранятся в переменной):
CREATE TYPE FUZZY_TYPE_FUNCTION AS (
func TRAPEZOIDAL_FUNCTION,
range_name VARCHAR(64)
);
CREATE FUNCTION get_fuzzy_name(
input FLOAT8,
type_name VARCHAR(64)
) RETURNS VARCHAR(64) AS $$
DECLARE
f FUZZY_TYPE_FUNCTION;
_type_functions FUZZY_TYPE_FUNCTION[] := array(SELECT (fun, name) FROM fuzzy.functions WHERE fuzzy.functions.type=type_name);
_deg_tmp FLOAT8;
_deg FLOAT8;
_result_name VARCHAR(64);
BEGIN
_deg := 0;
FOREACH f IN array(_type_functions) LOOP
_deg_tmp := degree(input, f.func);
RAISE NOTICE '% && % = %', f, input, _deg_tmp;
IF _deg<_deg_tmp THEN
_deg := _deg_tmp;
_result_name := f.range_name;
EXIT WHEN _deg=1;
END IF;
END LOOP;
IF _deg=0 THEN
RETURN NULL;
END IF;
RETURN _result_name;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT;
Есть ли способ получить значение таблицы функций только один раз для каждого запроса и кэшировать его, чтобы его можно было повторно использовать и значительно ускорить весь запрос?
Дополнительная информация
По запросу это таблицы:
CREATE SCHEMA IF NOT EXISTS fuzzy;
CREATE TABLE IF NOT EXISTS fuzzy.types (
id SERIAL PRIMARY KEY,
name VARCHAR(64) UNIQUE
);
CREATE TABLE IF NOT EXISTS fuzzy.functions (
type INT NOT NULL,
fun TRAPEZOIDAL_FUNCTION NOT NULL,
name VARCHAR(64),
FOREIGN KEY (type) REFERENCES fuzzy.types (id) ON DELETE CASCADE,
UNIQUE (type, name)
);
fuzzy.types
, вероятно, будет содержать несколько строк, которые являются парами id-name,
fuzzy.functions
, скорее всего, будет содержать 3-10 строк для каждого типа, что в тяжелых случаях может составлять около 500 строк (я полагаю).