Mais uma do SOLR – Dynamic Fields
Como alguns que acompanham o blog já devem ter percebido, eu estou usando o SOLR em um projeto. O SOLR é um servidor Web de busca, feito em cima do Lucene (grupo Apache). Ele é realmente poderoso e simples de usar. Recomendo muito para quem precisa fazer buscar textuais pesados e que tem uma quantidade razoável de documentos/dados para indexar. Como minha aplicação é Rails, estou usando uma GEM, chamada Sunspot, que serve de DSL (facilitador) nessa “conexão” entre minha app e o SOLR.
Nesse dias surgiu a necessidade de fazer uma nova feature em nosso sistema que parece ser bem simples mas como busco pelo SOLR a coisa ganhou bastante complexidade.Só para que entendam o problema, deixe me contextualizá-los. Minha aplicação é uma ferramenta de seleção de pessoas – CASTING. Nela um administrador cria uma campanha e define um formulários com N perguntas que serão respondido pelo candidato. Ao finalizar o preenchimento, esse formulário vira um inscrições e salvamos suas respostas. Surgiu então a necessidade de buscarmos por inscrições através de valores de respostas a perguntas específicas: Quero buscar por todas as inscrições que responderam Vasco para a pergunta “Qual é o seu time do coração?”.
Muitos, se não considerarmos que estamos usando o SOLR e que vamos fazer essa pesquisa direto no banco de dados, vão dizer é a solução bem simples: Se resume a um query onde informo o campo e o valor de resposta desejado. Tendo isso busca pelas inscrições que tenha aquela resposta. Simples, não é? Nem tanto. O meu cliente deseja que isso esteja integrado aos demais filtros já existentes – idade, sexo, estado, status, etc.
Bem antes desse nova funcionalidade, a busca direto no banco, dado a quantidade de dados, já se mostrou inviável. Logo, sem chances de eu largar o SOLR e voltar para o banco ou tentar fazer algo híbrido.
Parte para tentar descobrir se existia algo dentro do universo do SOLR e/ou do Sunspot onde eu pudesse definir um campo do indice de forma dinâmica, ou seja, para cada instancia que for criando. Depois de um certo tempo gasto com o Oráculo (Google) , fiquei feliz que mais uma vez nem a gem nem o servidor me decepcionou.
O Sunspot tem um recurso que é o “dynamic field” que é o seguinte: todo o indice de sua classe é feito no build da classe, ou seja, no seu load. Como precisava definir coisas que só existiriam no contexto da instância, eu precisa de algum recurso que me permitisse delegar a criação de alguns campos nesse momento de indexação (instancia). Esse recurso de “dynamic” é exatamente isso: ele configura um bloco que será criado quando ele for indexar. Com isso eu pude buscar no SOLR por campos que só existem para algumas inscrições.
Em termos de código é mais ou menos o seguinte. Imagine que sua Inscricao tenha uma relação has_many com Resposta.
class Inscricao << ActiveRecord
has_many :repostas
end
A classe Resposta faz referencia a um campo de seu formulário. Logo a busca terá como nome do campo do indice o campo + id e seu valor será a resposta. Assim o mapeamento fica:
…
searchable do
dynamic :respostas do
respostas.inject({}) do |mapa, resposta|
mapa.merge({ resposta.campo.id.to_sym => resposta.valor})
end
end
end
Com isso acima, fica pronto a configuração. Para busca fica assim:
search do
dynamic :respostas do
with(:1, “teste”)
end
…
Assim estou buscando por Inscrições cujo a resposta a pergunta 1 foi teste. E pronto. A mágica foi feita.
Espero sinceramente que isso ajuda alguém como outros blogs que consultei me ajudaram. Fiquem em paz e até a próximo.
