Lucas Teixeira

@lucastex

Arquivo para a tag ‘Solr’

[GSolr] Beans declarados automagicamente

com 3 comentários

GSolr, é o nome do plugin de solr que estamos fazendo de solr para grails. Para quem quiser acompanhar o trabalho, o repositório está no github: http://github.com/lucastex/gsolr.

Uma coisa que já está feita é a leitura da configuração do gsolr e a declaração mágica de beans, um para cada servidor solr que estiver configurado. Exemplificando, vamos imaginar que a configuração esteja declarando três servidores Solr que serão consultados:

gsolr {
   solr {
      produtos {
         (...)
      }
      noticias {
         (...)
      }
      usuarios {
         (...)
      }
   }
}

Particularmente, achei bem interessante usar o nome da closure para o nome do servidor ao invés de termos um atributo name = produtos :)
A mágica legal mesmo, é que o plugin vai ler esta configuração quando a aplicação for para o ar, e depois disso irá declarar / criar beans spring dinâmicamente, usando a Spring DSL. E os beans vão ter no nome a declaração feita na closure do usuário.

Ou seja, para os servidores solr declarados acima, o plugin irá declarar os Spring Beans produtosGSolr, noticiasGSolr e usuariosGSolr .

Desta maneira, vamos garantir que se você quiser o usar o plugin, o processo como um todo ficará o menos intrusivo possível, e você poderá usar os métodos (de pesquisa e outros) do GSolr apenas injetando o bean do servidor Solr que você quiser.

class PesquisaService {
   def noticiasGSolr

   def pesquisar = {
      (...)
   }
}

Achei no mínimo, muito prático. Tudo isso graças a Spring DSL que temos em groovy. Com um pouco mais de tempo, coloco o procedimento passo a passo para declarar os beans desta maneira. Enquanto isso, conheça um pouco mais sobre a Spring DSL aqui, ou veja o código fonte aqui e também aqui.

Tem alguma idéia ou sugestão para o plugin? Deixe um comentário!

Written by Lucas Teixeira

February 28th, 2010 at 11:18 pm

Postado em GSolr, Grails, Solr

Com as tags , , , ,

Grails e Solr juntos, o melhor dos mundos

com 5 comentários

Tá rolando uma discussão legal na lista “grails-users” sobre Solr.

Estamos levantando alguns pontos que seriam essenciais e interessantes para um plugin grails que cuidasse disso. Se você gosta também de Solr, ou está interessado, acompanhe os e-mails na Grails-Users ou no nabble aqui.

Você usa solr? O que acha interessante nele que deva existir em um plugin grails?

Written by Lucas Teixeira

February 26th, 2010 at 3:11 pm

Postado em Grails, Solr

Com as tags , , ,

Usando JNDI na configuração do DataImportHandler

com um comentário

Quer evitar que suas credenciais (usuário e senha) estejam abertas no seu data-config.xml? A melhor alternativa com certeza é usar um datasource JNDI para isso e manter usuário, senha e url de conexão do banco de dados dentro do cointainer.

Para isso, é só declarar a tag dataSource do data-config.xml desta maneira:

<dataSource user="" password="" jndiName="JndiDoMeuDs"

Sim, os parametros user e password devem ser declados vazios, não se esqueça disso.

Written by Lucas Teixeira

January 18th, 2010 at 9:27 am

Postado em Solr

Com as tags , , , ,

Apache Solr – Recomendação de livro

com um comentário

Pra quem gosta de busca e assuntos relacionados, um ótimo livro que recomendo é este: Solr 1.4 Enterprise Search Server.

Muito legal, bem abrangente, fala um pouco sobre cada coisa, desde implementações básicas necessárias de DataImportHandler, Transformers, Term-Suggest, Types e outros pontos.


Solr 1.4 - Enterprise Search Server

Solr 1.4 - Enterprise Search Server


Foi lançado um pouco antes da versão 1.4 estável sair (por todo aquele problema do último bug do lucene e etc), por 2 dos committers: David Smiley e Eric Pugh.

Está custando $40 diretamente no packetpub: A url para o produto é esta: http://www.packtpub.com/solr-1-4-enterprise-search-server/book.

Recomendo a todos que se interessam pelo assunto, e trabalham com isso, guia de consulta imprescindível :)

Written by Lucas Teixeira

January 15th, 2010 at 2:53 pm

Postado em Livros, Solr

Com as tags , , , , ,

Indexando vários campos com o mesmo conteúdo

com 2 comentários

Durante a definição schema do seu índice SOLR, muitas vezes precisamos armazenar o mesmo valor em diferentes campos (fields). Isto é necessário pelo fato de que cada field tem sua maneira de ser indexado, impactando diretamente no match deste documento em uma busca.

Por exemplo, temos o nome de um livro no nosso índice da biblioteca. Este nome deve ser flexionado no maior número possível de formas para que seja encontrado, seja removendo acentos, usando o snowball, o tokenizando e etc. Porém, ele também será usado em uma feature de “ordenação alfabética”. Neste caso sabemos que o campo deve ser indexado como “string” sem tokenização ou flexão, ou o resultado pode virar uma bagunça.

Grande parte das pessoas, enviam o campo duas vezes para o Solr, em dois fields diferentes, por exemplo: “nome” e “nome_ord”. Com isso, deixamos de usar uma diretriz bem bacana do solr chamada copyField que serve para copiar o conteúdo de um campo para outro.

Imaginando que os campos estejam definidos da seguinte forma:

<field name="nome" type="text" indexed="true" stored="true" />
<field name="nome_ord" type="string" indexed="true" stored="false" />

E usar no fim do documento a instrução copyField

<copyField source="nome" dest="nome_ord" />

Desta forma não adicionamos nenhum overhead de parse de uma nova informação, diminuímos a quantidade de dados enviada para o Solr (muito importante se estiver usando HTTP para indexação) e garantimos que a informação será exatamente a mesma.

Uma outra funcionalidade (esta disponível apenas a partir do Solr 1.4) é o maxChars que pode ser usado para restringir a quantidade de caracteres que serão copiados. Neste meu exemplo poderia ser usado para criar um resumo da introdução desta maneira.

<copyField source="introducao" dest="resumo" maxChars="3000" />

Boa!

Written by Lucas Teixeira

December 15th, 2009 at 4:15 pm

Postado em Solr

Com as tags , , ,

Solr 1.4, mais que pronto

com 6 comentários

Pra quem acompanha a lista de discussões e o andamento do projeto, o Solr 1.4 já está prontinho para ser lançado tem algum tempo. O pessoal de dev estava apenas esperando o lançamento do Lucene 2.9 para oficializar o lançamento.

Quando então foi lançado, o pessoal do Solr empacotou o framework como RC, disponibilizou para download e na hora do lançamento (pra ser mais preciso, um dia antes), dois bugs significativos foram levantados no Lucene 2.9. A equipe do Solr os avaliou com calma, entrou em alinhamento com os devs do Lucene (alguns fazem parte de ambas as equipes) e decidiram por bem aguardar o Lucene 2.9.1 para efetuar o anúncio oficial do Solr 1.4.

Pois bem, com o lançamento oficial do Lucene 2.9.1 hoje a tarde, o pessoal do Solr já correu, e empacotou em uma versão final a release tão esperada, 1.4.

Amanhã, dia 07, será feito o lançamento final do Solr 1.4 sem mais delongas. Pois bem, é só aguardar! Mas se você quiser dar uma olhadinha antes, é só baixar os pacotes antes de serem replicados para o mirror central entrando aqui: http://people.apache.org/~gsingers/solr/1.4.0/.

Eu, em uma olhada muito, mas muito rápida por cima de algumas funcionalidades do Solr 1.4 (direto no wiki), levantei alguns pontos e encaminhei na lista de e-mails dos colaboradores da empresa em que trabalho. Não estão agrupados, muito menos organizados, mas segue como esboço e rascunho de um post que valeria a pena.

  • SolrServer – SolrJ HTTP
    • Configuração
      • Timeout
      • Quantidade de retentativas
    • SolrJ altamente evoluído para criação da queries e integrado aos searchcomponents
  • DataImportHandler
    • Transformers
      • Clob Transformer: Permite pegar dados direto de colunas clob no banco de dados
      • HTML Stripper: Atua em campos com conteúdo HTML, removendo tags e deixando apenas o conteúdo
    • Agora é possível usar o DIH indexando até conteúdos de um ‘datasource’ de e-mail, deixando ele fazer pooling em um e-mail e indexando o que chega.
    • Eventos callback após indexação
  • Replicação
    • Configuração interna a aplicação – Funciona como um RequestHandler
    • Dashboard de administração, permite ver como estão as replicações, qual indice está em cada nó, status do download de novos indices
    • Permite replicação interna, via HTTP, não sendo mais necessário usar apenas rsync
      • Com isso, possibilidade de usar em windows
      • Menos configuração de infra estrutura
      • Maior visibilidade do status da replicação
  • Indexação
    • indexação de grandes quantidades de documentos via streaming
      • conexão é aberta com o master, e permanece assim enquanto necessário.
    • Anotação @Field para poder adicionar um POJO direto ao índice, sem ter que transformar em SolrInputDocument
  • Componentes de busca (alguns presentes no 1.3 completos, outros eram beta, outros nem existiam)
    • Sugestão de busca
    • Spelling
    • Highlight
  • Resposta da busca em vários novos formatos
    • php nativo
    • json (já existia mas não era oficial)
    • xml (normal)
    • ruby

E muito mais…

Written by Lucas Teixeira

November 9th, 2009 at 10:37 pm

Postado em Solr

Com as tags , , , , , ,

Criando um Transformer customizado para o Solr

com 14 comentários

Solr é um framework uma ferramenta para a construção de servidores de indexação e busca on top of índices lucene.

Possui todas as funcionalidades que existem em um sistema moderno de busca, como paginação, highlight de campos, flexão das palavras e etc. Na minha opinião, de tudo que trabalhei nos últimos anos, sem dúvida, formam o conjunto mais poderoso de frameworks.

O Solr abstrai a camada Java do Lucene e disponibiliza uma interface http para a execução da consulta, fazendo com que fique muito fácil a integração com sistemas não-java.

Um dos recursos avançados de indexação com Solr são os Transformers a serem usados juntamente com o DataImportHandler. Com eles, você pode processar o texto antes de ser indexado. (Um outro post sobre configuração básica de Solr e de DIH deve vir em breve).

Semana passada, precisei de um transformer que pudesse retirar todas as tags HTML do texto a ser indexado (malditos editores rich text em javascript). Como o projeto aqui está usando Solr 1.3 não tive a possibilidade de usar o HTMLStripTransformer que virá no Solr 1.4 (e está enroscado pra sair). Então acabei tendo que criar um semelhante para a funcionalidade.

A criação de transformers é muito simples (imho, simplista até demais, fazendo com que as vezes, o desenvolvedor se perca durante a implementação). Deve ser desenvolvida uma classe simples, que implementa um método com a seguinte assinatura:

public Map<String, Object> transformRow(Map<String, Object> aRow, Context context)

Quando disse que é simplista demais, é pelo fato de que, (imho novamente), condições restritivas como esta deveriam estar documentadas em interfaces, mas não, quando necessário, o método é chamado via reflection, tendo certeza que ele está implementado.

No meu caso, eu precisaria além de implementar o Transformer, deixar explícito no arquivo de configuração do DIH (data-config.xml) quais os campos que deveriam receber o tratamento desta tag, fiz isso adicionando a tag removeHtml no nó de cada campo (não, este xml não passa por validação).

<field name="txt" column="texto" removeHtml="true" />

Com isto, estamos deixando claro para o DIH que o valor que retornar da query na coluna texto será repassado ao Solr para indexação no field txt (definido no schema.xml) e terá processamento do meu HtmlTransformer. Ah, não podemos esquecer da declaração do transformer para a entidade:

<entity name="posts" transformer="br.com.lucastex.dih.transformer.HtmlTransformer" />

Pronto, a classe está agora carregada e pronta para ser chamada quando um campo necessitar. Agora, vamos a implementação da classse. No meu caso, ela ficou bem trivial, pois o campo em questão nunca será multivalorado (ou seja, não preciso tratar a possibilidade do argumento ser um List, mas apenas uma String.

package br.com.lucastex.dih.transformer;

import java.util.Map;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.solr.handler.dataimport.Context;
import org.apache.solr.handler.dataimport.DataImporter;
import org.apache.solr.handler.dataimport.RegexTransformer;
import org.apache.solr.handler.dataimport.Transformer;

public class HtmlTransformer extends Transformer {

  public static final String TAG = "removeHtml";

  public Map<String, Object> transformRow(Map<String, Object> aRow, Context context) {

    for (Map<String, String> map : context.getAllEntityFields()) {
      if (!Boolean.TRUE.toString().equals(map.get(TAG)))
        continue;
      String columnName = map.get(DataImporter.COLUMN);
      String sourceColumnName = map.get(RegexTransformer.SRC_COL_NAME);
      if (sourceColumnName == null)
        sourceColumnName = columnName;
      Object value = aRow.get(sourceColumnName);
      if (value instanceof String) {
        String result = stripHtml((String) value);
        aRow.put(columnName, result);
      }
    }
    return aRow;
  }

  private String stripHtml(String text) {
    try {
      String cleanText = StringEscapeUtils.unescapeHtml(text.replaceAll("\\<.*?\\>", " "));
      cleanText = cleanText.trim().replaceAll("\n"," ");
      cleanText = cleanText.replaceAll("\t"," ");
      cleanText = cleanText.replaceAll("[\\s]+", " ");
      return cleanText;
    } catch (Exception e) {
      //trata exception de acordo com seu contexto solr
    }
    return text;
  }
}

Bom, o código é bem auto-explicativo. Basicamente recebe o além do contexto em execução do Solr/DIH, um Map de String e Object, que contém todos os campos e valores da linha que está sendo analisada/indexada no momento. Vale lembrar que este modelo de passagem de parâmetro é feito exatamente como descrito no Pattern BCDR.

Enfim, as linhas 18 e 19 garantem que o código só será executado para campos que tenham declarado a tag removeHtml=true como descrito anteriormente.

A linha 24 recupera o valor original do campo, ou seja, o que foi retornado pela query no banco de dados, e nas linhas 26 e 27 o resultado é tratado (através da chamada para o método stripHtml) e devolvida ao Map.

Ou seja, este é o momento onde você tem acesso a todos os campos que estão vindo do banco antes de irem ao índice. É nesta hora que você duplica seus campos, faz tratamentos, aplica padrões e templates, enfim trabalha a informação bruta original do banco de dados.

Já o método de remoção de tags HTML, não é nada além de um conjunto de regexes encadeadas  com uma ajudinha do StringEscapeUtils (que saudade deste post) do Commons-lang.

Simples como

Written by Lucas Teixeira

October 26th, 2009 at 6:59 pm

Get Adobe Flash playerPlugin by wpburn.com wordpress themes