Добавление нескольких фраз вместе в фразу

Я успешно смог объединить массивы отдельных слов в строки для to_tsquery, но фразу tototstsery в postgres 9.6 допускает только одну ключевую фразу. Кто-нибудь знает решение для запроса tsvector (будь то в Sql или функции полнотекстового поиска) таким образом, чтобы я мог (ИЛИ / И) динамическое количество фраз в запросе. Все выбранные блоки - это массивы текста.

Первые попытки:

SELECT to_tsvector('english','Try not to become a man of successful companies, but rather try to become a man of value')
   @@ (to_tsquery('english','man & become')
       && phraseto_tsquery('english','man of value')
       && phraseto_tsquery('english','company')
       || phraseto_tsquery('english', 'company | man of value')
   );

Пример реальной проблемы поиска животных:

-- with statements here of opp_tsv and tp
SELECT
  tp.id,
  tp.keywords, --['giraffes','lions', 'monkeys']
  tp.phrase_keywords, --['pygmy marmocet','African Lion']
  tp.neg_keywords, --['aliens', 'spaceships', 'space']
  tp.neg_phrase_keywords --['Andromedan Alien', 'Nibiru Reptilian']
FROM tp, opp_tsv,
  -- string logic for ts_query
      concat(array_to_string(tp.keywords, ' | ')) AS kws_concat,
      concat(array_to_string(tp.neg_keywords, ' | ')) AS     neg_kws_concat,
      to_tsquery('english', kws_concat) query,
      to_tsquery('english', concat(neg_kws_concat)) neg_query
  -- Case logic for phrase queries

  -- .... -> phrase_query,
      phraseto_tsquery('phrase to search | Need this phrase too')
  -- .... -> phrase_neg_query,

WHERE
  (
    opp_tsv.doc @@ query --pos
    OR
    opp_tsv.doc @@ phrase_query --pos
  )
  AND NOT (
    opp_tsv.doc @@ neg_query --neg
    OR
    opp_tsv.doc @@ phrase_neg_query --neg
  )
ORDER BY rank_cd DESC;

Мысли: генерировать динамически в соответствии с длиной массива

opp_tsv.doc @@ (phrase_query || phrase_query2)

или как-то добиться этого

opp_tsv.doc @@ phraseto_tsquery('big messy phrase | more messy wordphrases')

РЕДАКТИРОВАТЬ:SELECT phraseto_tsquery('phrase to search | Need this phrase too')результат = 'phrase' <-> 'to' <-> 'search' <-> 'need' <-> 'this' <-> 'phrase' <-> 'too'То, что я ищу, является результатом 'phrase<->to<->search' | 'need<->this<->phrase<->too'

1 ответ

Решение

Вы можете определить свою собственную совокупность по tsqueryили||) оператор:

CREATE AGGREGATE tsquery_or_agg(tsquery) (
  SFUNC = tsquery_or,
  STYPE = tsquery
);

Примечание: совокупность выше опирается на тот факт, что tsquery"s || Оператор поддерживается tsquery_or(tsquery, tsquery) функция. Вы можете проверить это с помощью:

SELECT *
FROM   pg_operator
WHERE  oprname  = '||'
AND    oprleft  = regtype 'tsquery'
AND    oprright = regtype 'tsquery';

Если вы не хотите полагаться на имя этой (недокументированной) функции (даже если оно вряд ли будет изменено), вы можете создать свою собственную функцию, которая будет служить базовой функцией (SFUNC) для вашего агрегата:

CREATE FUNCTION my_tsquery_or(tsquery, tsquery)
  RETURNS tsquery
  LANGUAGE sql
  IMMUTABLE
  STRICT
  AS 'SELECT $1 || $2';

После этого ваш запрос будет выглядеть примерно так:

WITH tp(id, keywords, phrase_keywords, neg_keywords, neg_phrase_keywords ) AS (
  VALUES (42, ARRAY['giraffes', 'lions', 'monkeys']::text[],
              ARRAY['pygmy marmocet', 'African Lion']::text[],
              ARRAY['aliens', 'spaceships', 'space']::text[],
              ARRAY['Andromedan Alien', 'Nibiru Reptilian']::text[])
),
tq(id, query) AS (
  SELECT   tp.id,
           (((SELECT tsquery_or_agg(plainto_tsquery(kw)) FROM unnest(keywords) kw) ||
             (SELECT tsquery_or_agg(phraseto_tsquery(pk)) FROM unnest(phrase_keywords) pk)) &&
             !!((SELECT tsquery_or_agg(plainto_tsquery(nk)) FROM unnest(neg_keywords) nk) ||
                (SELECT tsquery_or_agg(phraseto_tsquery(np)) FROM unnest(neg_phrase_keywords) np)))
  FROM     tp
),
opp_tsv(doc) AS (
  VALUES (to_tsvector('Earth''s African Lions')),
         (to_tsvector('Andromedan Alien''s space monkeys'))
)
SELECT   tp.id,
         tp.keywords,
         tp.phrase_keywords,
         tp.neg_keywords,
         tp.neg_phrase_keywords,
         opp_tsv.doc
FROM     opp_tsv, tp
JOIN     tq USING (id)
WHERE    opp_tsv.doc @@ tq.query
ORDER BY ts_rank_cd(opp_tsv.doc, tq.query) DESC;

Кроме того, если поля в tp может содержать такие фразы, как 'big messy phrase | more messy wordphrases', то, во-первых, вы неправильно разбили свой ввод. Вы можете разделить такие фразы / ключевые слова с помощью regexp_split_to_table() функция. С этим, tq CTE должен выглядеть примерно так:

tq(id, query) AS (
  SELECT   tp.id,
           (((SELECT tsquery_or_agg(plainto_tsquery(kw)) FROM unnest(keywords) kwb, regexp_split_to_table(kwb, '\|') kw) ||
             (SELECT tsquery_or_agg(phraseto_tsquery(pk)) FROM unnest(phrase_keywords) pkb, regexp_split_to_table(pkb, '\|') pk)) &&
             !!((SELECT tsquery_or_agg(plainto_tsquery(nk)) FROM unnest(neg_keywords) nkb, regexp_split_to_table(nkb, '\|') nk) ||
                (SELECT tsquery_or_agg(phraseto_tsquery(np)) FROM unnest(neg_phrase_keywords) npb, regexp_split_to_table(npb, '\|') np)))
  FROM     tp
),
Другие вопросы по тегам