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:
Linguística — Os dicionários Ispell tentam reduzir as palavras de entrada a uma forma normalizada; os dicionários lematizadores (stemmers) removem terminações de palavras
Endereços de URL podem ser reduzidos à forma canônica, para fazer com que URLs equivalentes correspondam:
http://www.pgsql.ru/db/mw/index.html
http://www.pgsql.ru/db/mw/
http://www.pgsql.ru/db/../db/mw/index.html
Nomes de cores podem ser substituídos por seus valores
hexadecimais. Por exemplo,
vermelho, verde, azul, magenta-> FF0000, 00FF00, 0000FF, FF00FF
Se os números forem indexados, podem ser removidos alguns dígitos fracionários para reduzir o intervalo de números possíveis. Por exemplo, 3.14159265359, 3.1415926 e 3.14 serão o mesmo número após a normalização, se forem mantidos apenas dois dígitos após o ponto decimal.
Um dicionário é um programa que aceita um token como
entrada e retorna:
uma matriz de lexemas, se o token de entrada for
conhecido pelo dicionário (observe que um token
pode produzir mais de um lexema)
um único lexema com o sinalizador TSL_FILTER
definido, para substituir o token original por um
novo token a ser passado para os dicionários
subsequentes (um dicionário que faz isso é chamado de
dicionário de filtragem)
uma matriz vazia, se o dicionário reconhecer o token,
mas for uma palavra de parada
NULL, se o dicionário não reconhecer o
token de entrada
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.
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.
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.
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.
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.
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
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.
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.
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;
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'
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
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.
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.
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.)