Obter correspondência parcial da coluna TSVECTOR indexada por GIN


13

Gostaria de obter resultados consultando este:

SELECT * FROM (
  SELECT id, subject
  FROM mailboxes
  WHERE tsv @@ plainto_tsquery('avail')
) AS t1 ORDER by id DESC;

Isso funciona e retorna linhas com tsvcontendo Available. Mas se eu usar avai(descartado lable), ele não poderá encontrar nada.

Todas as consultas precisam estar no dicionário? Não podemos simplesmente consultar essas cartas? Eu tenho um banco de dados que contém o corpo do email (conteúdo) e gostaria de torná-lo rápido à medida que cresce a cada segundo. Atualmente estou usando

... WHERE content ~* 'letters`

Respostas:


22

Todas as consultas precisam estar no dicionário?

Não. Como apenas as hastes de palavras (de acordo com a configuração de pesquisa de texto usada ) estão no índice para começar. Mas mais importante:

Não . Porque, além disso, a Pesquisa de texto completo também é capaz de correspondência de prefixo :

Isso funcionaria:

SELECT id, subject
FROM   mailboxes
WHERE  tsv @@ to_tsquery('simple', 'avail:*')
ORDER  BY id DESC;

Observe 3 coisas:

  1. Use to_tsquery(), não plainto_tsquery(), neste caso, porque ( citando o manual ):

    ... plainto_tsquerynão reconhecerá tsqueryoperadores, rótulos de peso ou rótulos de correspondência de prefixo em sua entrada

  2. Use a 'simple'configuração de pesquisa de texto para gerar o valor, tsquerypois você obviamente deseja usar a palavra 'avail' como está e não aplicar o stemming.

  3. Anexe :*para torná-lo uma pesquisa de prefixo, ou seja, encontre todos os lexemas começando com 'avail'.

Importante: Esta é uma pesquisa de prefixo em lexemes (palavra derivada) no documento. Uma correspondência de expressão regular sem caracteres curinga ( content ~* 'avail') não é exatamente a mesma! O último não está ancorado à esquerda (no início dos lexemas) e também encontraria 'FOOavail' etc.

Não está claro se você deseja o comportamento descrito em sua consulta ou o equivalente à expressão regular adicionada. Índices de trigramas ( pg_trgm) como @Evan já sugeridos são a ferramenta certa para isso. Existem muitas perguntas relacionadas no dba.SE, tente uma pesquisa .

Visão geral:

Demo

SELECT *
FROM (
   VALUES
     ('Zend has no framework')
   , ('Zend Framework')
   ) sub(t), to_tsvector(t) AS tsv
WHERE tsv @@ to_tsquery('zend <-> fram:*');
 id |       t        |          tsv
----+----------------+------------------------
  2 | Zend Framework | 'framework':2 'zend':1

Resposta relacionada recente (capítulo Abordagem diferente para otimizar a pesquisa ):

Emails?

Como você mencionou e-mails, lembre-se de que o analisador de pesquisa de texto identifica e-mails e não os divide em palavras / lexemes separados. Considerar:

SELECT ts_debug('english', 'xangr@some.domain.com')
(email,"Email address",xangr@some.domain.com,{simple},simple,{xangr@some.domain.com})

Eu substituiria os separadores @e .nos seus emails por space ( ' ') para indexar as palavras contidas.

Além disso, como você está lidando com nomes em emails, não com palavras em inglês (ou em outro idioma) , eu usaria a 'simple'configuração de pesquisa de texto para desativar os recursos de stemming e outros idiomas :

Crie a ts_vectorcoluna com:

SELECT to_tsvector('simple', translate('joe.xangr@some.domain.com', '@.', '  ')) AS tsv;

Estou excluindo minha resposta para isso porque, de qualquer forma, estou claramente errado pela primeira vez e prefiro não ser lembrado. Eu tenho duas perguntas para você 1) onde está :*documentado e 2) uma menção a construir não deve ser to_tsvector('simple'..)acompanhada de instruções que futuras consultas a esse tsv exigirão a configuração "simples" também para o tsquery? Eu acho que você deve esclarecer as implicações de desativar o stemming em um tsvector / tsquery.
Evan Carroll

@EvanCarroll: Não é necessário usar a configuração 'simples' . Evita apenas o surgimento (como "ratos" para "rato") que pode ou não ser desejável. Não é desejável para o exemplo dado. Manual: Adicionei links acima ...
Erwin Brandstetter

4
@EvanCarroll: Além: Pensar que você está errado na primeira vez, seria a segunda vez. E isso seria errado, recursivamente. ;)
Erwin Brandstetter

2
@ ErwinBrandstetter, Uau, seu caminho me deu uma busca em velocidade total. Antes do seu caminho, era 0.380mspreciso obter resultado. Depois do seu caminho 0.079 ms.
Xangr 13/12/16

1
@xangr: Não, o FTS oferece apenas a correspondência de prefixos para lexemas. Para algo mais, veja pg_trgm. O STF é mais rápido (com um índice menor). Você pode até combinar os dois índices ...
Erwin Brandstetter
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.