12.2. Tabelas e índices #

12.2.1. Procura em tabela
12.2.2. Criação de índices

Os exemplos da seção anterior mostraram a correspondência de texto completo usando constantes cadeias de caracteres simples. Esta seção mostra como procurar dados em tabela, opcionalmente usando índices.

12.2.2. Criação de índices #

Pode ser criado um índice GIN (Seção 12.9) para acelerar procuras de texto:

CREATE INDEX pgweb_idx ON pgweb USING GIN (to_tsvector('english', body));

Note que está sendo usada a versão de 2 argumentos da função to_tsvector. Em índices de expressão, somente podem ser usadas as funções de procura de texto completo que especificam o nome da configuração (Seção 11.7). Isto acontece, porque o conteúdo do índice não deve ser afetado pelo parâmetro default_text_search_config. Se os índices forem afetados, o conteúdo do índice pode se tornar inconsistente, porque diferentes entradas podem conter tsvectors que foram criados com diferentes configurações de procura de texto, e não haveria como adivinhar qual é qual. Seria impossível salvar e recuperar este índice corretamente.

Como foi usada a versão de dois argumentos da função to_tsvector no índice acima, apenas uma referência de consulta que usa a versão de dois argumentos de to_tsvector com o mesmo nome de configuração usará este índice. Ou seja, WHERE to_tsvector('english', body) @@ 'a & b' pode usar o índice, mas WHERE to_tsvector(body) @@ 'a & b' não pode. Isto garante que o índice será usado apenas com a mesma configuração usada para criar as entradas do índice.

É possível configurar índices de expressão mais complexos, onde o nome da configuração é especificado por outra coluna como, por exemplo,

CREATE INDEX pgweb_idx ON pgweb USING GIN (to_tsvector(config_name, body));

onde config_name é uma coluna da tabela pgweb. Isto permite configurações mistas no mesmo índice, porque salva qual configuração foi usada para cada entrada do índice. Seria útil, por exemplo, se a coleção de documentos contivesse documentos em diferentes idiomas. Novamente, as consultas destinadas a usar um índice devem ser escritas para corresponder ao índice, como, por exemplo, WHERE to_tsvector(config_name, body) @@ 'a & b'.

Os índices podem até mesmo concatenar colunas:

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

Outra abordagem é criar uma coluna tsvector separada para armazenar a saída da função to_tsvector. Para manter esta coluna atualizada automaticamente com seus dados de origem, deve ser usada uma coluna gerada armazenada. Este exemplo é uma concatenação dos campos title e body usando a função coalesce para garantir que um campo ainda será indexado quando o outro for NULL:

ALTER TABLE pgweb
    ADD COLUMN textsearchable_index_col tsvector
               GENERATED ALWAYS AS
               (to_tsvector('english', coalesce(title, '') || ' '
               || coalesce(body, ''))) STORED;

Em seguida, é criado um índice GIN para acelerar a procura:

CREATE INDEX textsearch_idx ON pgweb USING GIN (textsearchable_index_col);

Agora estamos prontos para realizar uma procura de texto completo rápida:

SELECT title
FROM pgweb
WHERE textsearchable_index_col @@ to_tsquery('create & table')
ORDER BY last_mod_date DESC
LIMIT 10;

Uma vantagem da abordagem de coluna separada sobre um índice de expressão, é não ser necessário especificar explicitamente a configuração de procura de texto nas consultas para usar o índice. Conforme mostrado no exemplo acima, a consulta pode depender de default_text_search_config. Outra vantagem, é que as procuras serão mais rápidas, porque não será necessário refazer as chamadas à função to_tsvector para verificar correspondências de índice. (Isto é mais importante ao usar um índice GiST do que um índice GIN; veja a Seção 12.9.) Entretanto, a abordagem de índice de expressão é mais fácil de configurar, e requer menos espaço em disco, porque a representação tsvector não é fisicamente armazenada.