Lucas Teixeira

@lucastex

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

Postado por Lucas Teixeira

October 26th, 2009 at 6:59 pm

14 Respostas a 'Criando um Transformer customizado para o Solr'

Receber novos comentários por RSS or TrackBack to 'Criando um Transformer customizado para o Solr'.

  1. Usa #solr ? Já precisou implementar um Transformer específico para seu projeto? http://tinyurl.com/ylsg3cj (Por favor RT)

    Lucas Teixeira

    26 Oct 09 at 19:02

  2. RT: @lucastex: Usa #solr ? Já precisou implementar um Transformer específico para seu projeto? http://tinyurl.com/ylsg3cj

    Emerson Rocco

    26 Oct 09 at 19:06

  3. RT @lucastex Usa #solr ? Já precisou implementar um Transformer específico para seu projeto? http://tinyurl.com/ylsg3cj

    Mayumi Sato

    26 Oct 09 at 19:10

  4. RT @lucastex: Usa #solr ? Já precisou implementar um Transformer específico para seu projeto? http://tinyurl.com/ylsg3cj (Por favor RT)

    Paulo Suzart

    26 Oct 09 at 19:31

  5. Usa #solr ? Já precisou implementar um Transformer específico para seu projeto? http://tinyurl.com/ylsg3cj (Por favor RT)

    lucastex

    26 Oct 09 at 19:02

  6. RT: @lucastex: Usa #solr ? Já precisou implementar um Transformer específico para seu projeto? http://tinyurl.com/ylsg3cj

    Emerson Bernardino

    26 Oct 09 at 19:06

  7. RT @lucastex Usa #solr ? Já precisou implementar um Transformer específico para seu projeto? http://tinyurl.com/ylsg3cj

    mayogax

    26 Oct 09 at 19:10

  8. RT @lucastex: Usa #solr ? Já precisou implementar um Transformer específico para seu projeto? http://tinyurl.com/ylsg3cj (Por favor RT)

    paulosuzart

    26 Oct 09 at 19:31

  9. RT @lucastex: Usa #solr ? Já precisou implementar um Transformer específico para seu projeto? http://tinyurl.com/ylsg3cj

    Jeveaux

    26 Oct 09 at 21:27

  10. RT @lucastex: Usa #solr ? Já precisou implementar um Transformer específico para seu projeto? http://tinyurl.com/ylsg3cj

    jeveaux

    26 Oct 09 at 21:27

  11. RT @lucastex: Usa #solr ? Já precisou implementar um Transformer específico para seu projeto? http://tinyurl.com/ylsg3cj

    Raphael Miranda

    26 Oct 09 at 22:39

  12. RT @lucastex: Usa #solr ? Já precisou implementar um Transformer específico para seu projeto? http://tinyurl.com/ylsg3cj

    Raphael Miranda 永

    26 Oct 09 at 22:39

  13. Repostando: Usa #solr ? Já precisou implementar um Transformer específico para seu projeto? http://tinyurl.com/ylsg3cj

    Lucas Teixeira

    27 Oct 09 at 11:36

  14. Repostando: Usa #solr ? Já precisou implementar um Transformer específico para seu projeto? http://tinyurl.com/ylsg3cj

    lucastex

    27 Oct 09 at 11:36

Deixe um comentário

Get Adobe Flash playerPlugin by wpburn.com wordpress themes