Eu gostaria de fazer pesquisa de texto completo em documentos XML.
No entanto, não consigo obter correspondências para valores de atributo (obtenho um erro de sintaxe se fornecer o valor de atributo completo, incluindo os caracteres :
e /
no exemplo abaixo). Além disso, não sei como especificar meus próprios delimitadores para o analisador.
Abaixo está o SSCCE:
Eu gostaria de ser capaz de selecionar o último componente do atributo value: attributevalue
e para o analisador reconhecer :
e /
como delimitadores e assim produzir boo1
, boo2
e some
como attributevalue
lexemas.
DROP TABLE IF EXISTS xmldocument;
CREATE TABLE IF NOT EXISTS xmldocument (
i SERIAL NOT NULL,
content XML NOT NULL
);
ALTER TABLE xmldocument ADD PRIMARY KEY (i);
INSERT INTO xmldocument (content) VALUES
('<a>foo</a>')
,('<a boo=''boo1:boo2:boo3/boo4/some/attributevalue''>foo</a>')
;
-- matches both records as expected
SELECT * FROM xmldocument WHERE to_tsvector(CAST (content AS VARCHAR))@@'foo';
-- no match
SELECT * FROM xmldocument WHERE to_tsvector(CAST (content AS VARCHAR))@@'attributevalue';
-- no match
SELECT * FROM xmldocument WHERE to_tsvector(CAST (content AS VARCHAR))@@'boo2';
-- no match
SELECT * FROM xmldocument WHERE to_tsvector(CAST (content AS VARCHAR))@@'boo4';
Quanto ao motivo de não usar apenas ILIKE %
etc. O motivo é que preciso otimizar usando um índice GIN e não acho que seja possível ou significativo criar um índice com valores VARCHAR simples.
*atualize após aceitar a resposta*
Com base na resposta aceita, todas as consultas a seguir funcionam conforme o esperado:
SELECT * FROM fts.xmldocument WHERE
to_tsvector(regexp_replace(content::text,'[<>/]',' ','g')) @@ to_tsquery('foo');
SELECT * FROM fts.xmldocument WHERE
to_tsvector(regexp_replace(content::text,'[<>/]',' ','g')) @@ to_tsquery('attributevalue');
SELECT * FROM fts.xmldocument WHERE
to_tsvector(regexp_replace(content::text,'[<>/]',' ','g')) @@ to_tsquery('boo2');
SELECT * FROM fts.xmldocument WHERE
to_tsvector(regexp_replace(content::text,'[<>/]',' ','g')) @@ to_tsquery('boo4');
Se você não quiser escrever seu próprio analisador, a solução rápida e suja seria substituir
<
e>
por alguma outra pontuação, para que os analisadores existentes não decidam descartá-los como tags html.Se você usar a
pg_trgm
extensão, poderá criar um índice gin nos valores VARCHAR que otimizará as consultas ILIKE. Sua eficácia depende do tamanho de seus documentos indexados e do tamanho de sua consulta. Eu recomendo tentar e ver como funciona para você.A versão 1.2 do pg_trgm (a ser incluída no PostgreSQL 9.6, mas é bastante fácil fazer back-port para 9.4 e 9.5 se você estiver disposto a compilar algum código) será muito mais eficaz com consultas grandes.