12.6. Dicionários #

12.6.1. Palavras de parada
12.6.2. Dicionário simples
12.6.3. Dicionário de sinônimos
12.6.4. Dicionário Thesaurus
12.6.5. Dicionário Ispell
12.6.6. Dicionário Snowball
12.6.7. Exemplos do tradutor

Os dicionários são usados para eliminar palavras que não devem ser consideradas em uma procura (palavras de parada / stop words), e para normalizar palavras para que diferentes formas derivadas da mesma palavra também correspondam. Uma palavra normalizada com sucesso é chamada de lexema. Além de melhorar a qualidade da procura, a normalização e a remoção de palavras de parada reduzem o tamanho da representação tsvector de um documento, melhorando assim o desempenho. A normalização nem sempre tem significado linguístico, e geralmente depende da semântica da aplicação.

Alguns exemplos de normalização:

Um dicionário é um programa que aceita um token como entrada e retorna:

O PostgreSQL fornece dicionários predefinidos para muitos idiomas. Existem, também, vários modelos predefinidos que podem ser usados para criar dicionários com parâmetros personalizados. Cada modelo de dicionário predefinido está descrito abaixo. Se nenhum modelo existente for adequado, é possível criar modelos; veja a área contrib/ da distribuição do PostgreSQL para obter exemplos.

Uma configuração de procura de texto vincula um analisador a um conjunto de dicionários para processar os tokens de saída do analisador. Para cada tipo de token que o analisador pode retornar, uma lista separada de dicionários é especificada pela configuração. Quando um token de um determinado tipo é encontrado pelo analisador, cada dicionário da lista é consultado por sua vez, até que algum dicionário reconheça o token como palavra conhecida. Se o token for identificado como palavra de parada, ou se nenhum dicionário reconhecer o token, ele será descartado e não será indexado ou procurado. Normalmente, o primeiro dicionário que retorna uma saída não nula determina o resultado, e quaisquer dicionários restantes não são consultados; mas um dicionário de filtragem pode substituir a palavra original por uma palavra modificada, que é então passada para os dicionários subsequentes.

A regra geral para configurar a lista de dicionários é colocar primeiro o dicionário mais restrito e específico, depois os dicionários mais gerais, terminando com um dicionário muito geral, como o lematizador Snowball, ou o simple, que reconhece tudo. Por exemplo, para uma procura específica de astronomia (configuração astro_en), pode-se vincular o tipo de token asciiword (palavra ASCII) a um dicionário de sinônimos de termos astronômicos, um dicionário geral de inglês, e um lematizador de inglês Snowball:

ALTER TEXT SEARCH CONFIGURATION astro_en
    ADD MAPPING FOR asciiword WITH astrosyn, english_ispell, english_stem;

Um dicionário de filtragem pode ser colocado em qualquer lugar da lista, exceto no final, onde seria inútil. Os dicionários de filtragem são úteis para normalizar parcialmente as palavras, para simplificar a tarefa dos dicionários posteriores. Por exemplo, um dicionário de filtragem pode ser usado para remover os acentos das letras acentuadas, como é feito pelo módulo unaccent.

12.6.1. Palavras de parada #

As palavras de parada são palavras muito comuns, que aparecem em quase todos os documentos, e não têm valor de diferenciação. Portanto, podem ser ignoradas no contexto de procura de texto completo. Por exemplo, todo texto em inglês contém palavras como a e the, então é inútil armazená-las em um índice. Entretanto, as palavras de parada afetam as posições em tsvector, que por sua vez afetam a pontuação:

SELECT to_tsvector('english', 'in the list of stop words');

        to_tsvector
----------------------------
 'list':3 'stop':5 'word':6

-- Exemplo do tradutor abaixo

SELECT to_tsvector('portuguese', 'na lista de palavras de parada');

         to_tsvector
-----------------------------
 'list':2 'palavr':4 'par':6

As posições faltantes 1, 2 e 4 no exemplo em inglês, e 1, 3 e 5 no exemplo em português, se deve às palavras de parada. As pontuações calculadas para documentos com e sem palavras de parada são bem diferentes:

SELECT ts_rank_cd (
    to_tsvector('english', 'in the list of stop words'),
    to_tsquery('list & stop'));

 ts_rank_cd
------------
       0.05

SELECT ts_rank_cd (
    to_tsvector('english', 'list stop words'),
    to_tsquery('list & stop'));

 ts_rank_cd
------------
        0.1

-- Exemplos do tradutor abaixo

SELECT ts_rank_cd (
    to_tsvector('portuguese', 'na lista de palavras de parada'),
    to_tsquery('lista & parada'));

 ts_rank_cd
------------
      0.025

SELECT ts_rank_cd (
    to_tsvector('portuguese', 'lista palavras parada'),
    to_tsquery('lista & parada'));

 ts_rank_cd
------------
       0.05

Cabe ao dicionário específico determinar como as palavras de parada são tratadas. Por exemplo, os dicionários Ispell primeiro normalizam as palavras, e depois examinam a lista de palavras de parada, enquanto os lematizadores Snowball primeiro verificam a lista de palavras de parada. A razão para o comportamento diferente é uma tentativa de diminuir o ruído.

12.6.2. Dicionário simples #

O modelo de dicionário simple opera convertendo o token de entrada em letras minúsculas, e verificando-o em um arquivo de palavras de parada. Se for encontrado no arquivo, é retornada uma matriz vazia, fazendo com que o token seja descartado. Caso contrário, é retornada a forma em letras minúsculas da palavra como o lexema normalizado. Como alternativa, o dicionário pode ser configurado para relatar palavras que não são palavras de parada como não reconhecidas, permitindo que sejam passadas para o próximo dicionário na lista.

Abaixo está um exemplo de definição de dicionário usando o modelo simple:

CREATE TEXT SEARCH DICTIONARY public.simple_dict (
    TEMPLATE = pg_catalog.simple,
    STOPWORDS = english
);

Nesta definição, english é o nome base do arquivo de palavras de parada. O nome completo do arquivo será $SHAREDIR/tsearch_data/english.stop, onde $SHAREDIR representa o diretório de dados compartilhados da instalação do PostgreSQL, que é nesta versão /usr/share/postgresql/18 (use o comando pg_config --sharedir para conhecer o valor a ser atribuído a $SHAREDIR, se for outra versão ou não tiver sido atribuído ainda). O formato do arquivo é apenas uma lista de palavras, uma por linha. As linhas em branco e os espaços à direita são ignorados, e as letras maiúsculas são convertidas em minúsculas, mas nenhum outro processamento é feito no conteúdo do arquivo. (Veja o Exemplo 12.3.)

Agora podemos testar o nosso dicionário:

SELECT ts_lexize('public.simple_dict', 'YeS');

 ts_lexize
-----------
 {yes}

SELECT ts_lexize('public.simple_dict', 'The');

 ts_lexize
-----------
 {}

Também podemos optar por retornar NULL, em vez de retornar a palavra em letras minúsculas, se a palavra não for encontrada no arquivo de palavras de parada. Esse comportamento é selecionado definindo o parâmetro Accept do dicionário como false. Continuando o exemplo:

ALTER TEXT SEARCH DICTIONARY public.simple_dict ( Accept = false );
ALTER TEXT SEARCH DICTIONARY
\pset null "(nulo)"
A exibição de nulos é ""(nulo)"".
SELECT ts_lexize('public.simple_dict', 'YeS');

 ts_lexize
-----------
 "(nulo)"

SELECT ts_lexize('public.simple_dict', 'The');

 ts_lexize
-----------
 {}

Com a configuração padrão Accept = true, só é útil colocar o dicionário simple no final da lista de dicionários, porque nunca passará nenhum token para o dicionário seguinte. Ao contrário, Accept = false só é útil quando existe pelo menos um dicionário depois.

Cuidado

A maioria dos tipos de dicionários depende de arquivos de configuração, como arquivos de palavras de parada. Esses arquivos devem ser armazenados na codificação UTF-8. Os arquivos serão traduzidos para a codificação do banco de dados, caso seja diferente, quando forem lidos no servidor.

Cuidado

Normalmente, uma sessão de banco de dados lerá o arquivo de configuração de dicionário apenas uma vez, quando for usado pela primeira vez na sessão. Se o arquivo de configuração for modificado, e se quiser forçar as sessões existentes a ler o novo conteúdo, deve ser executado o comando ALTER TEXT SEARCH DICTIONARY no dicionário. Essa pode ser uma atualização dummy, que não altera nenhum valor de parâmetro.

12.6.3. Dicionário de sinônimos #

Este modelo de dicionário é usado para criar dicionários que substituem uma palavra por um sinônimo. Não há suporte para frases (deve ser usado o modelo thesaurus para isso, veja a Seção 12.6.4). O dicionário de sinônimos pode ser usado para superar problemas linguísticos, como, por exemplo, evitar que um dicionário lematizador de inglês reduza a palavra Paris para pari. Para isso, basta haver a linha Paris paris no dicionário de sinônimos, e colocá-lo antes do dicionário english_stem. (Veja o Exemplo 12.4.) Por exemplo:

SELECT * FROM ts_debug('english', 'Paris');

   alias   |   description   | token |  dictionaries  |  dictionary  | lexemes
-----------+-----------------+-------+----------------+--------------+---------
 asciiword | Word, all ASCII | Paris | {english_stem} | english_stem | {pari}

-- Primeiro o arquivo 'my_synonyms.syn' precisa ser criado e editado,
-- sudo nano  $SHAREDIR/tsearch_data/my_synonyms.syn"
-- adicionando a linha paris tabulação paris
-- para, depois, ser executado o comando abaixo. (N. T.)

postgres=# CREATE TEXT SEARCH DICTIONARY my_synonym (
    TEMPLATE = synonym,
    SYNONYMS = my_synonyms
);

-- É necessário ser um superusuário para executar o comando abaixo.
-- Esta alteração só atinge o banco de dados onde é executada,
-- não se aplicando aos demais bancos de dados (N. T.)

postgres=# ALTER TEXT SEARCH CONFIGURATION english
    ALTER MAPPING FOR asciiword
    WITH my_synonym, english_stem;
ALTER TEXT SEARCH CONFIGURATION
postgres=# SELECT * FROM ts_debug('english', 'Paris');

   alias   |   description   | token |       dictionaries        | dictionary | lexemes
-----------+-----------------+-------+---------------------------+------------+---------
 asciiword | Word, all ASCII | Paris | {my_synonym,english_stem} | my_synonym | {paris}

O único parâmetro requerido pelo modelo synonym é SYNONYMS, que é o nome base do arquivo de configuração — my_synonyms no exemplo acima. O nome completo do arquivo será $SHAREDIR/tsearch_data/my_synonyms.syn (onde $SHAREDIR representa o diretório de dados compartilhados da instalação do PostgreSQL). O formato do arquivo é apenas uma linha por palavra a ser substituída, com a palavra seguida de seu sinônimo, separada por espaço em branco. Linhas em branco e espaços à direita são ignorados.

O modelo synonym também tem o parâmetro opcional CaseSensitive, que o padrão é false. Quando CaseSensitive for false, as palavras no arquivo de sinônimos serão convertidas para letras minúsculas, assim como os tokens de entrada. Quando for true, as palavras e os tokens não serão convertidos para letras minúsculas, e serão comparados como estão.

Pode ser colocado um asterisco (*) no final de um sinônimo no arquivo de configuração. Isto indica que o sinônimo é um prefixo. O asterisco é ignorado quando a entrada é usada em to_tsvector(), mas quando é usada em to_tsquery() o resultado será um item de consulta com o marcador de correspondência de prefixo (veja a Seção 12.3.2). Por exemplo, suponha que temos estas entradas em $SHAREDIR/tsearch_data​/synonym_sample.syn:

postgres        pgsql
postgresql      pgsql
postgre pgsql
gogle   googl
indices index*

Então vamos obter estes resultados:

CREATE TEXT SEARCH DICTIONARY syn (template=synonym, synonyms='synonym_sample');
CREATE TEXT SEARCH DICTIONARY
SELECT ts_lexize('syn', 'indices');

 ts_lexize
-----------
 {index}

CREATE TEXT SEARCH CONFIGURATION tst (copy=simple);
ALTER TEXT SEARCH CONFIGURATION tst ALTER MAPPING FOR asciiword WITH syn;
ALTER TEXT SEARCH CONFIGURATION
SELECT to_tsvector('tst', 'indices');

 to_tsvector
-------------
 'index':1

SELECT to_tsquery('tst', 'indices');

 to_tsquery
------------
 'index':*

SELECT 'indexes are very useful'::tsvector;

            tsvector
---------------------------------
 'are' 'indexes' 'useful' 'very'

SELECT 'indexes are very useful'::tsvector @@ to_tsquery('tst', 'indices');

 ?column?
----------
 t

12.6.4. Dicionário Thesaurus #

O dicionário thesaurus (às vezes abreviado como TZ), é uma coleção de palavras que inclui informações sobre as relações entre palavras e frases, ou seja, termos mais amplos ( broader terms, BT), termos mais restritos (narrower terms, NT), termos preferidos, termos não preferidos, termos relacionados, etc.

Basicamente, o dicionário thesaurus substitui todos os termos não preferidos por um termo preferido e, opcionalmente, preserva os termos originais para serem indexados também. A implementação corrente do dicionário thesaurus no PostgreSQL, é uma extensão do dicionário de sinônimos com suporte adicionado a frase. O dicionário thesaurus requer um arquivo de configuração com o seguinte formato:

# Isto é um comentário
palavra(s) de amostra: palavra(s) indexada(s)
mais palavra(s) de amostra: mais palavra(s) indexada(s)
...

onde o caractere dois pontos (:) atua como delimitador entre a frase e sua substituição.

O dicionário thesaurus usa um sub-dicionário (especificado na configuração do dicionário) para normalizar o texto de entrada antes de verificar as correspondências de frase. Só é possível selecionar um sub-dicionário. Se o sub-dicionário não reconhecer a palavra, é informado erro. Nesse caso, o uso da palavra deve ser suprimido, ou ser informado ao sub-dicionário sobre ela. Pode ser colocado um asterisco (*) no início de uma palavra indexada, para suprimir a aplicação do sub-dicionário nela, mas todas as palavras de amostra devem ser conhecidas pelo sub-dicionário.

O dicionário thesaurus escolhe a correspondência mais longa, se houver várias frases que correspondam à entrada, e os empates são resolvidos usando a última definição.

Não podem ser especificadas palavras de parada reconhecidas pelo sub-dicionário; no lugar delas, deve ser usado o ponto de interrogação (?) para marcar o local onde alguma palavra de parada possa aparecer. Por exemplo, assumindo que a e the são palavras de parada segundo o sub-dicionário:

? one ? two : swsw

corresponde a a one the two e a the one a two; os dois seriam substituídos por swsw.

Como o dicionário thesaurus consegue reconhecer frases, ele deve lembrar seu estado e interagir com o analisador. O dicionário thesaurus usa essas atribuições para verificar se deve lidar com a próxima palavra, ou parar a acumulação. O dicionário thesaurus deve ser configurado com cuidado. Por exemplo, se o dicionário thesaurus for destinado a lidar apenas com token asciiword, uma definição de dicionário thesaurus como um 7 não vai funcionar, porque o tipo de token uint não está atribuído ao dicionário thesaurus.

Cuidado

Os thesaurus são usados durante a indexação, portanto, qualquer alteração nos parâmetros do dicionário thesaurus requer a reindexação. Para a maioria dos outros tipos de dicionário, pequenas alterações, como adicionar ou remover palavras de parada, não obrigam a reindexação.

12.6.4.1. Configuração do Thesaurus #

Para definir um novo dicionário de sinônimos thesaurus é usado o modelo thesaurus. Por exemplo:

CREATE TEXT SEARCH DICTIONARY thesaurus_simple (
    TEMPLATE = thesaurus,
    DictFile = thesaurus_sample,
    Dictionary = pg_catalog.english_stem
);

Onde:

  • thesaurus_simple é o nome do novo dicionário

  • thesaurus_sample é o nome base do arquivo de configuração do dicionário de sinônimos thesaurus. (O nome completo é $SHAREDIR/tsearch_data​/thesaurus_sample.ths, onde $SHAREDIR representa o diretório de dados compartilhados da instalação.) [100].

  • pg_catalog.english_stem é o sub-dicionário (neste caso o Snowball English stemmer / lematizador de inglês Snowball), a ser usado para a normalização do thesaurus. Note que o sub-dicionário terá sua própria configuração (por exemplo, palavras de parada), que não é mostrada aqui.

Agora é possível vincular o dicionário thesaurus_simple, aos tipos de token desejados em uma configuração. Por exemplo:

ALTER TEXT SEARCH CONFIGURATION danish
    ALTER MAPPING FOR asciiword, asciihword, hword_asciipart
    WITH thesaurus_simple;

12.6.4.2. Exemplo de Thesaurus #

Considere o thesaurus astronômico simples thesaurus_astro [101], que contém algumas combinações de palavras astronômicas:

supernovae stars : sn
crab nebulae : crab

Abaixo é criado o dicionário thesaurus_astro, usando o modelo thesaurus, vinculando alguns tipos de token ao thesaurus de sinônimos astronômicos thesaurus_astro, e usando o lematizador de inglês english_stem:

postgres=# CREATE TEXT SEARCH DICTIONARY thesaurus_astro (
    TEMPLATE = thesaurus,
    DictFile = thesaurus_astro,
    Dictionary = english_stem
);
CREATE TEXT SEARCH DICTIONARY
postgres=# ALTER TEXT SEARCH CONFIGURATION danish
    ALTER MAPPING FOR asciiword, asciihword, hword_asciipart
    WITH thesaurus_astro, english_stem;
ALTER TEXT SEARCH CONFIGURATION

Agora podemos ver como funciona. A função ts_lexize não é muito útil para testar um thesaurus, porque trata sua entrada como um único token. Em vez disso, podemos usar as funções plainto_tsquery e to_tsvector, que quebram suas cadeias de caracteres de entrada em vários tokens:

postgres=# SELECT plainto_tsquery('danish', 'supernova star');

 plainto_tsquery
-----------------
 'sn'

postgres=# SELECT to_tsvector('danish', 'supernova star');

 to_tsvector
-------------
 'sn':1

A princípio a função to_tsquery pode ser usada, se o argumento for delimitado:

postgres=# SELECT to_tsquery('danish', '''supernova star''');

 to_tsquery
------------
 'sn'

ou

postgres=# SELECT to_tsquery('danish', $$'supernova star'$$);

 to_tsquery
------------
 'sn'

Note que supernova star corresponde a supernovae stars no thesaurus_astro, porque foi especificado o lematizador english_stem na definição do thesaurus. O lematizador removeu o e e o s.

Para indexar a frase original e também a substituta, basta incluir a frase original na parte direita da definição editando o arquivo thesaurus_astro.ths.

supernovae stars : sn supernovae stars

-- Recarregar thesaurus_astro

postgres=# ALTER TEXT SEARCH DICTIONARY thesaurus_astro ( dummy );
ALTER TEXT SEARCH DICTIONARY
postgres=# SELECT plainto_tsquery('danish', 'supernova star');

       plainto_tsquery
-----------------------------
 'sn' & 'supernova' & 'star'

12.6.5. Dicionário Ispell #

O modelo de dicionário Ispell oferece suporte a dicionários morfológicos, que podem normalizar muitas formas linguísticas diferentes de uma palavra no mesmo lexema. Por exemplo, o dicionário Ispell em inglês pode corresponder a todas as declinações e conjugações do termo de procura bank, ou seja, banking, banked, banks, banks' e bank's.

A distribuição padrão do PostgreSQL não inclui nenhum arquivo de configuração do Ispell. Dicionários para um grande número de idiomas estão disponíveis em Ispell. Além disso, há suporte para alguns formatos de arquivo de dicionário mais modernos — MySpell (OO < 2.0.1) e Hunspell (OO >= 2.0.2). Uma grande lista de dicionários está disponível no OpenOffice Wiki.

Para criar o dicionário Ispell devem ser executadas as seguintes etapas:

  • baixar os arquivos de configuração do dicionário. Os arquivos de extensão do OpenOffice possuem a extensão .oxt [102]. É necessário extrair os arquivos .aff e .dic, mudar as extensões para .affix e .dict. Para alguns arquivos de dicionário também é necessário converter os caracteres para a codificação UTF-8 usando os comandos (por exemplo, para um dicionário de idioma norueguês):

    iconv -f ISO_8859-1 -t UTF-8 -o nn_no.affix nn_NO.aff
    iconv -f ISO_8859-1 -t UTF-8 -o nn_no.dict nn_NO.dic
    

  • copiar os arquivos para o diretório $SHAREDIR/tsearch_data

  • carregar os arquivos no PostgreSQL com o seguinte comando:

    CREATE TEXT SEARCH DICTIONARY english_hunspell (
        TEMPLATE = ispell,
        DictFile = en_us,
        AffFile = en_us,
        Stopwords = english);
    

No comando acima, DictFile, AffFile e StopWords especificam os nomes base dos arquivos de dicionário, afixos e palavras de parada. O arquivo de palavras de parada tem o mesmo formato explicado acima para o tipo de dicionário simple. O formato dos outros arquivos não é especificado aqui, mas está disponível nos sites mencionados acima.

Os dicionários Ispell geralmente reconhecem um conjunto limitado de palavras, e por isso devem ser seguidos por outro dicionário mais amplo; por exemplo, um dicionário Snowball, que reconhece tudo.

O arquivo .affix do Ispell possui a seguinte estrutura:

prefixes
flag *A:
    .           >   RE      # As in enter > reenter
suffixes
flag T:
    E           >   ST      # As in late > latest
    [^AEIOU]Y   >   -Y,IEST # As in dirty > dirtiest
    [AEIOU]Y    >   EST     # As in gray > grayest
    [^EY]       >   EST     # As in small > smallest

E o arquivo .dict possui a seguinte estrutura:

lapse/ADGRS
lard/DGRS
large/PRTY
lark/MRS

O formato do arquivo .dict é:

basic_form/affix_class_name

No arquivo .affix, cada sinalizador de afixo é descrito no seguinte formato:

condition > [-stripping_letters,] adding_affix

Aqui, a condição tem um formato semelhante ao formato das expressões regulares. Pode usar agrupamentos [...] e [^...]. Por exemplo, [AEIOU]Y significa que a última letra da palavra é "y" e a penúltima letra é "a", "e", "i", "o" ou "u". [^EY] significa que a última letra não é nem "e" nem "y".

Os dicionários Ispell dão suporte para dividir palavras compostas; uma funcionalidade útil. Note que o arquivo de afixo deve especificar um sinalizador especial usando a instrução compoundwords controlled, que marca as palavras do dicionário que podem participar da formação composta:

compoundwords  controlled z

Aqui estão alguns exemplos para o idioma norueguês:

SELECT ts_lexize('norwegian_ispell', 'overbuljongterningpakkmesterassistent');
   {over,buljong,terning,pakk,mester,assistent}
SELECT ts_lexize('norwegian_ispell', 'sjokoladefabrikk');
   {sjokoladefabrikk,sjokolade,fabrikk}

O formato MySpell é um subconjunto de Hunspell. O arquivo .affix do Hunspell possui a seguinte estrutura:

PFX A Y 1
PFX A   0     re         .
SFX T N 4
SFX T   0     st         e
SFX T   y     iest       [^aeiou]y
SFX T   0     est        [aeiou]y
SFX T   0     est        [^ey]

A primeira linha de uma classe de afixo é o cabeçalho. Os campos de uma regra de afixo são listados após o cabeçalho:

  • nome do parâmetro (PFX ou SFX)

  • sinalizador (nome da classe de afixo)

  • caracteres retirados do início (no prefixo) ou do final (no sufixo) da palavra

  • adicionar afixo

  • condição com um formato semelhante ao formato de expressões regulares.

O arquivo .dict se parece com o arquivo .dict do Ispell:

larder/M
lardy/RT
large/RSPMYT
largehearted

Nota

MySpell não oferece suporte a palavras compostas. Hunspell oferece um suporte sofisticado para palavras compostas. No momento, o PostgreSQL implementa apenas as operações básicas de palavras compostas do Hunspell.

12.6.6. Dicionário Snowball #

O modelo de dicionário Snowball é baseado em um projeto de Martin Porter, inventor do popular algoritmo de derivação de Porter para o idioma inglês. O Snowball agora fornece algoritmos de lematização para muitos idiomas (veja o site do Snowball para obter mais informações). Cada algoritmo sabe como reduzir as formas variantes comuns das palavras a uma base, ou radical, relativa ao idioma. O dicionário Snowball requer o parâmetro language para identificar o lematizador a ser usado e, opcionalmente, um nome de arquivo stopword que fornece a lista de palavras a serem eliminadas. (As listas de palavras de parada padrão do PostgreSQL também são fornecidas pelo projeto Snowball.) Por exemplo, existe uma definição nativa equivalente a

CREATE TEXT SEARCH DICTIONARY english_stem (
    TEMPLATE = snowball,
    Language = english,
    StopWords = english
);

O formato do arquivo de palavras de parada é o mesmo já explicado.

O dicionário Snowball reconhece tudo, consiga ou não simplificar a palavra, devendo por isso ser colocado no final da lista de dicionários. É inútil tê-lo antes de qualquer outro dicionário, porque ele nunca passará um token para o próximo dicionário.

12.6.7. Exemplos do tradutor #

Exemplo 12.3. Arquivo de palavras de parada

Este exemplo mostra a localização dos arquivos de palavras de parada nos idiomas inglês e português, o número de palavras e as cinco primeiras palavras do arquivo de palavras de parada em português, no PostgreSQL instalado no Linux Debian 12. No arquivo em português, a palavra tém aparece como palavra de parada, mas a palavra têm não, como visto abaixo.

$ pg_config --sharedir
/usr/share/postgresql/18
$ SHAREDIR="/usr/share/postgresql/18"
$ # Arquivos de palavras de parada em inglês e português
$ ls $SHAREDIR/tsearch_data/*.stop | grep -E "english|portuguese"
/usr/share/postgresql/18/tsearch_data/english.stop
/usr/share/postgresql/18/tsearch_data/portuguese.stop
$ # Número de palavras de parada no arquivo em  português
$ cat $SHAREDIR/tsearch_data/portuguese.stop | wc -l
203
$ # Primeiras cinco palavras de parada do arquivo em português
$ cat $SHAREDIR/tsearch_data/portuguese.stop | head --lines=5
de
a
o
que
e
$ # 'tém' aparece como palavra de parada no arquivo, mas 'têm' não.
$ psql
SELECT to_tsvector('portuguese', 'tém ou não têm, eis a questão');
        to_tsvector
----------------------------
 'eis':5 'questã':7 'têm':4
-- após editar o arquivo 'portuguese.stop' e incluir a palavra 'têm',
-- vamos definir o dicionário 'public.dic_simples' e usá-lo:
CREATE TEXT SEARCH DICTIONARY public.dic_simples (
    TEMPLATE = pg_catalog.simple,
    STOPWORDS = portuguese
);
CREATE TEXT SEARCH DICTIONARY
SELECT ts_lexize('public.dic_simples', 'tém');
 ts_lexize
-----------
 {}
SELECT ts_lexize('public.dic_simples', 'têm');
 ts_lexize
-----------
 {}
SELECT ts_lexize('public.dic_simples', 'Questão');
 ts_lexize
-----------
 {questão}
# retornar nulo se a palavra não for encontrada no dicionário
ALTER TEXT SEARCH DICTIONARY public.dic_simples ( Accept = false );
ALTER TEXT SEARCH DICTIONARY
\pset null "(nulo)"
A exibição de nulos é ""(nulo)"".
SELECT ts_lexize('public.dic_simples', 'Questão');
 ts_lexize
-----------
 "(nulo)"

Exemplo 12.4. Dicionário de sinônimos

Este exemplo mostra a criação e uso do dicionário de sinônimos sin_ascii_pt.syn, contendo palavras ASCII no idioma português.

postgres=# SELECT * FROM ts_debug('portuguese', 'Paris');
   alias   |   description   | token |   dictionaries    |   dictionary    | lexemes
-----------+-----------------+-------+-------------------+-----------------+---------
 asciiword | Word, all ASCII | Paris | {portuguese_stem} | portuguese_stem | {par}
-- primeiro o arquivo 'sin_ascii_pt.syn' precisa ser criado e editado,
-- e incluída a linha paris tabulação paris
-- (veja pg_config --sharedir)
-- sudo nano $SHAREDIR/tsearch_data/sin_ascii_pt.syn
-- para, depois, ser executado o comando abaixo:

postgres=# CREATE TEXT SEARCH DICTIONARY sin_ascii_pt (
    TEMPLATE = synonym,
    SYNONYMS = sin_ascii_pt
);

-- É necessário ser um superusuário para executar o comando abaixo.
-- Esta alteração só atinge o banco de dados onde é executada,
-- não se aplicando aos demais bancos de dados.

postgres=# ALTER TEXT SEARCH CONFIGURATION portuguese
    ALTER MAPPING FOR asciiword
    WITH sin_ascii_pt, portuguese_stem;

postgres=# SELECT * FROM ts_debug('portuguese', 'Paris');
   alias   |   description   | token |          dictionaries          |  dictionary  | lexemes
-----------+-----------------+-------+--------------------------------+--------------+---------
 asciiword | Word, all ASCII | Paris | {sin_ascii_pt,portuguese_stem} | sin_ascii_pt | {paris}

Exemplo 12.5. Dicionários Natura

O Projecto Natura é um pequeno grupo de investigação em Processamento de Linguagem Natural do Departamento de Informática, da Universidade do Minho. Os dicionários disponíveis destinam-se a uso por corretores ortográficos, ou analisadores morfológicos. Neste exemplo é baixado o dicionário usado pelo OpenOffice e pelo LibreOffice, oo3x-pt-PT, e o dicionário Hunspell, que são adicionados ao diretório $SHAREDIR/tsearch_data. Por fim, são criados os dicionários de procura de texto completo hunspell_portuguese e oo3x_pt_pt e alterada a configuração portuguese de procura de texto completo para usar o dicionário oo3x_pt_pt.

Como pode ser visto na última consulta abaixo, na frase sem sentiddo agrónomo ou agrônomo, fica composto, a palavra agrónomo foi reconhecida pelo dicionário oo3x_pt_pt, mas a palavra agrônomo não, porque é um dicionário de português de Portugal.

$ # Dicionário Hunspell (em UTF-8)
$ wget https://natura.di.uminho.pt/download/sources/Dictionaries/hunspell/↵
       hunspell-pt_PT-preao-20251001.tar.gz
$ tar xzvf hunspell-pt_PT-preao-20251001.tar.gz
$ cd hunspell-pt_PT-preao-20251001/
$ sudo cp pt_PT-preao.aff $SHAREDIR/tsearch_data/hunspell_pt_pt.affix
$ sudo cp pt_PT-preao.dic $SHAREDIR/tsearch_data/hunspell_pt_pt.dict
$ cd ..
$ # Dicionários OOo/LibreOffice (em UTF-8)
$ wget http://natura.di.uminho.pt/download/sources/Dictionaries/libreoffice/↵
       oo3x-pt_PT.oxt
$ 7z x oo3x-pt_PT.oxt
$ cd dictionaries/
$ sudo cp pt_PT.aff $SHAREDIR/tsearch_data/oo3x_pt_pt.affix
$ sudo cp pt_PT.dic $SHAREDIR/tsearch_data/oo3x_pt_pt.dict
$ cd ..
$ psql

postgres=# CREATE TEXT SEARCH DICTIONARY hunspell_portuguese (
    TEMPLATE = ispell,
    DictFile = hunspell_pt_pt,
    AffFile = hunspell_pt_pt,
    Stopwords = portuguese);

postgres=# CREATE TEXT SEARCH DICTIONARY oo3x_pt_pt (
    TEMPLATE = ispell,
    DictFile = oo3x_pt_pt,
    AffFile = oo3x_pt_pt,
    Stopwords = portuguese);

postgres=# ALTER TEXT SEARCH CONFIGURATION portuguese
    ALTER MAPPING FOR asciiword, asciihword, hword_asciipart, word, hword, hword_part
    WITH oo3x_pt_pt, portuguese_stem;

postgres=# SELECT alias, token, dictionaries, dictionary, lexemes
           FROM ts_debug('portuguese', 'agrónomo ou agrônomo, fica composto');
   alias   |  token   |         dictionaries         |   dictionary    |      lexemes
-----------+----------+------------------------------+-----------------+-------------------
 word      | agrónomo | {oo3x_pt_pt,portuguese_stem} | oo3x_pt_pt      | {agrónomo}
 blank     |          | {}                           |                 |
 asciiword | ou       | {oo3x_pt_pt,portuguese_stem} | oo3x_pt_pt      | {}
 blank     |          | {}                           |                 |
 word      | agrônomo | {oo3x_pt_pt,portuguese_stem} | portuguese_stem | {agrônom}
 blank     | ,        | {}                           |                 |
 asciiword | fica     | {oo3x_pt_pt,portuguese_stem} | oo3x_pt_pt      | {ficar}
 blank     |          | {}                           |                 |
 asciiword | composto | {oo3x_pt_pt,portuguese_stem} | oo3x_pt_pt      | {composto,compor}
(9 linhas)



[100] O comando pg_config --sharedir mostra o valor a ser atribuído a $SHAREDIR (SHAREDIR=/usr/share/postgresql/18 nesta versão do PostgreSQL). (N. T.)

[101] Criado usando o comando sudo nano $SHAREDIR/tsearch_data/thesaurus_astro.ths (N. T.)

[102] O arquivo .oxt serve como invólucro para todos os itens de uma extensão do Apache OpenOffice, contendo arquivos que listam e descrevem estes itens. (N. T.)