Postgres полнотекстовый поиск с несколькими столбцами, почему Concat в индексе, а не во время выполнения?


10

В последние несколько дней я сталкивался с полнотекстовым поиском в postgres, и меня немного смущает индексация при поиске по нескольким столбцам.

В Postgres документах говорить о создании ts_vectorиндекса на сцепленных столбцах, например , так:

CREATE INDEX pgweb_idx ON pgweb 
    USING gin(to_tsvector('english', title || ' ' || body));

который я могу искать так:

... WHERE 
      (to_tsvector('english', title||' '||body) @@ to_tsquery('english', 'foo'))

Однако, если бы я хотел иногда искать только заголовок, иногда просто тело, а иногда и то и другое, мне потребовалось бы 3 отдельных индекса. И если я добавлю в третий столбец, это может быть 6 индексов и так далее.

Альтернатива, которую я не видел в документах, - это просто индексировать два столбца по отдельности, а затем просто использовать обычный WHERE...ORзапрос:

... WHERE
      (to_tsvector('english', title) @@ to_tsquery('english','foo'))
    OR
      (to_tsvector('english', body) @@ to_tsquery('english','foo'))

Сравнительный анализ двух строк на ~ 1 миллион строк, по-видимому, практически не имеет различий в производительности.

Итак, мой вопрос:

Почему я хотел бы объединить индексы, как это, а не просто индексировать столбцы по отдельности? Каковы преимущества / недостатки обоих?

Мое лучшее предположение состоит в том, что если бы я знал заранее, я бы хотел когда-либо искать оба столбца (никогда не один за раз), мне понадобился бы только один индекс, объединяющий, которые используют меньше памяти.


Я не совсем уверен, как объединить titleв bodyи затем индексирование, которое даст большую ценность, хотя я открыт для исправления. Я бы, наверное, просто занялся их индексацией по отдельности. Кроме того, если это был какой-то дурацкий случай, который почему-то требовал от вас объединения, то, я думаю, вы могли бы просто выполнить запрос ad-hoc.
swasheck

Вы правы в своем предположении. Я бы посоветовал вам ответить самому себе, если никто больше этого не делает, стиль «Опасность» здесь.
Jcolebrand

Ответы:


3

Нет, вам не нужны отдельные индексы. Используйте функцию весов. Это просто ярлык, к которому вы можете обратиться. Вы можете иметь до четырех меток для запроса (AD).

--search any "field" for quick:
select 'quick:1A brown:2B quick:3C'::tsvector @@ 'quick'::tsquery; --true

--search B "field" for quick:
select 'quick:1A brown:2B quick:3C'::tsvector @@ 'quick:B'::tsquery; --false

--search B or C "fields" for quick:
select 'quick:1A brown:2B quick:3C'::tsvector @@ 'quick:BC'::tsquery; --true

Возможно, вы захотите объединить tsvector, так что вы можете отдельно применить веса к ним, а затем сложить их вместе:

select
  setweight( name_column::tsvector, 'A') || setweight( phone_column::tsvector, 'B');

2

На самом деле альтернативой было бы использовать где с OR , а не AND .

Если у вас есть указатель на tsvector (тело + заголовок), и вы ищете в нем, искомые слова могут быть в заголовке ИЛИ в теле.

Также - при тестировании убедитесь, что у вас есть разумное количество строк в таблице.

Простейший случай, который должен показать хорошую разницу: найти два слова - одно из которых, скорее всего, будет в заголовке. а другой - это очень вероятно, чтобы быть в организме. Но убедитесь, что не так много строк, которые соответствуют обоим критериям. Например, у вас может быть 30% слова «depesz» в теле. У вас также есть ~ 30% шанс иметь "mysql" в заголовке. Но наличие «depesz and mysql» в любом из полей в одном ряду очень маловероятно. А потом проверь производительность с такими показателями.


Ха, хорошее место, на ИЛИ против И я обновлю вопрос. Я сделал это с 1 миллионами строк - не мог быть обеспокоен, ожидая больше, чтобы вставить :)
latentflip

1
Спасибо, что заглянули в depesz - в наши дни у нас довольно много вопросов postgres, поэтому я надеюсь, что вы останетесь без
внимания

@Jack: не уверен, что буду - я нашел сайты для обмена стеками все менее и менее пригодными для использования. Я обычно пытаюсь получить RSS, но на сайтах stackexchange rss в значительной степени бесполезен - так много загрязнений от издания старых вопросов.

Я создал RSS-канал для вас здесь - вы готовы попробовать? Я рад приложить усилия к тому, чтобы отфильтровать то, что вас вряд ли заинтересует, чтобы получить шанс привлечь вас к участию в сайте :-),
говорит Джек, попробуйте topanswers.xyz

Джек :) Я укушу - подписался.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.