O problemaQuase sempre vemos um formulario de busca interna em sites que publicam conteudos com frequencia. Este formulario, assim como a navegacao por categorias ou por tags, ajuda muito os visitantes a encontrarem o que procuram. Mas desenvolvedores iniciantes - ou nem tao iniciantes assim - ainda implementam esse mecanismo de busca de uma forma "crua".Geralmente e um simples formulario, com metodo GET, um campo de texto e um botao de OK. Ate ai, sem problemas. No front end e isso mesmo. Mas no back end, geralmente a implementacao que vemos e algo assim:<?php$terms = explode(' ', $_GET);$query = "SELECT * FROM table WHERE conteudo LIKE ";foreach ($terms as $term) { $query .= "%" . $term . "% OR LIKE";}... // roda a query, pega resultados, mostra?>Pois bem, esta abordagem, apesar de funcional, nao e elegante, nem tem a precisao desejavel. Se voce buscar por "um cone" pode encontrar "a colecao de icones do Humberto". Isso sem falar da performance das queries, que e seriamente afetada quanto mais registros no banco e mais termos sao procurados.A solucao? Um recurso que os principais RDBMS tem chamado Full-Text Search. Vou ensinar aqui como implementar e usar estes recursos na pratica (no MySQL e no PostgreSQL).MySQLNOTA: o recurso de Full-Text Search so esta disponivel para tabelas MyISAM.Vamos supor que voce tenha uma tabela de posts ou artigos com a estrutura parecida com a seguinte:id titulointroconteudoautortagspublishdateEm primeiro lugar vamos precisar adicionar um indice, que e composto pelos campos que desejamos que sejam buscados. Rode isso pelo seu programa de administracao do MySQL (MySQL Admin, phpMyAdmin).ALTER TABLE posts ADD FULLTEXT (titulo, intro, conteudo, tags);Depois disso, basta reescrever a query no PHP:SELECT * FROM postsWHERE MATCH (titulo, intro, conteudo, tags)AGAINST (". $_GET .");A busca sera mais rapida e os resultados com menos falsos positivos. Sem contar que o codigo fica mais limpo e elegante.PostgreSQLO PostgreSQL da um pouco mais de trabalho para fazer a implementacao.Pelo seu programa de administracao, rode as seguintes queries.ALTER TABLE posts ADD COLUMN postsfts tsvector;UPDATE posts SET postsfts = setweight(to_tsvector('pg_catalog.portuguese', coalesce(titulo,'')), 'A') || setweight(to_tsvector('pg_catalog.portuguese', coalesce(intro,'')), 'B') || setweight(to_tsvector('pg_catalog.portuguese', coalesce(conteudo,'')), 'C');CREATE INDEX postsfts_idx ON posts USING gin(postsfts);CREATE TRIGGER postsfts_tg BEFORE INSERT OR UPDATE ON posts FOR EACH ROW EXECUTE PROCEDURE tsvector_update_trigger('postsfts', 'pg_catalog.portuguese', 'titlulo', 'intro', 'conteudo');Entendendo o que foi feito.A primeira query adiciona um outro campo a tabela, onde o vetor de busca ficara armazenado (isso aumenta de forma significativa a performance).A segunda query define quais campos farao parte do full-text search. Note que no PostgreSQL voce pode definir o peso de cada campo - A, B, C ou D, sendo A o campo mais importante, D o menos importante. Ah, e claro definimos a linguagem para portugues.Na terceira query, construimos um index sobre o campo que acabamos de criar.Por ultimo, criamos um trigger que vai atualizar o campo que criamos, sempre que o o conteudo da tabela for atualizado.Com isto feito, podemos transformar as queries no PHP para:SELECT * FROM posts, to_tsquery(' . $_GET . ') query WHERE query @@ postsfts;No PostgreSQL o operador "@@" funciona como o MATCH AGAINST do MySQL. E precisamos converter