PostgreSQL: как обойти ограничения размера ts_vector?

Я создаю поиск внутри приложения Rails, используя функцию pg_search gem. Однако в одной из таблиц есть поле типа данных Text, и его содержимое немного больше, чем обычно.

Теперь, когда мне нужно настроить tsvector column для столбцов text, я сталкиваюсь с некоторыми ограничениями, связанными с размером текстового поля и размером tsvector.

ERROR: string is too long for tsvector (5068741 bytes, max 1048575 bytes)

Есть ли способ определить условие для пропуска больших полей Text при создании столбца tsvector в триггере SQL, чтобы сделать что-то вроде этого:

псевдокод:

execute(<<-TRIGGERSQL)
CREATE OR REPLACE FUNCTION public.essays_before_insert_update_row_tr()
 RETURNS trigger
 LANGUAGE plpgsql
AS $function$
BEGIN
    If (SELECT LEN(body_text) FROM essays) <= 1048575
      new.tsv_body_text := to_tsvector('pg_catalog.english', coalesce(new.body_text,''));
      RETURN NEW;
    End
END;
$function$
  TRIGGERSQL

  # no candidate create_trigger statement could be found, creating an adapter-specific one
  execute("CREATE TRIGGER essays_before_insert_update_row_tr BEFORE INSERT OR UPDATE ON \"essays\" FOR EACH ROW EXECUTE PROCEDURE essays_before_insert_update_row_tr()")

связанный вопрос, который я нашел без ответа:

Postgresql — преобразование текста в ts_vector


person 0bserver07    schedule 26.05.2015    source источник


Ответы (1)


Простой обходной путь — просто вызвать to_tsvector() с усеченным текстовым значением. Например, используя пример запуска из руководство Postgres в качестве отправной точки этот подход выглядит так:

CREATE FUNCTION essays_tsv_trigger_fn() RETURNS trigger AS $$
begin
    new.tsv_body_text := to_tsvector('english', left(new.body_text, 4*1024*1024));
    return new;
end
$$ LANGUAGE plpgsql;

CREATE TRIGGER essays_tsv_trigger BEFORE INSERT OR UPDATE
    ON essays FOR EACH ROW EXECUTE FUNCTION essays_tsv_trigger_fn();

Это усекает содержимое документа до 4 МБ, что должно быть достаточно полезно для многих коллекций документов. Вместо того, чтобы просто игнорировать «слишком» длинные документы, вы включаете хотя бы их части. По моему опыту, 4 МБ хорошо подходят для технической документации на английском языке. В зависимости от размера фактически используемого словаря вы можете даже добиться успеха при усечении с большим значением, например 10 МБ.

Если вы действительно хотите игнорировать слишком длинные документы, вы можете защитить присваивание to_tsvector() оператором if следующим образом:

CREATE FUNCTION essays_tsv_trigger_fn() RETURNS trigger AS $$
begin
    if length(new.body_text) <= 4*1024*1024 then
        new.tsv_body_text := to_tsvector('english', new.body_text);
    end if;
  return new;
end
$$ LANGUAGE plpgsql;
person maxschlepzig    schedule 10.08.2019