Pesquisar

quarta-feira, 27 de janeiro de 2010

Vagas Agile Funny - OFF

Com o título Vagas na Fibonacci Soluções Agéis - foi um anuncio feito pelo GOJava (legal) veja:

Requisitos:

Imprescindíveis:

- Gostar muito de programação
- Não achar que a carreira ideal é aquela em que você começa como programador, é "promovido" para analista e um dia se torna gerente de "sua própria equipe"
- Preferir trabalhar em uma equipe auto-gerenciável
- Não acreditar que uma única tecnologia é a solução para todos os problemas, mas sim que existe a ferramenta correta para cada trabalho
- Ser bom em google-fu

Desejáveis

- Experiência/conhecimento em Desenvolvimento Orientado a Testes, Desenvolvimento para Web, Arquitetura de Software, Desenvolvimento Orientado a Objetos, Metodologias Ágeis
- Saber jogar truco
- Ser ala-direita ou centro-avante no futebol (precisamos completar o time)
- Gostar de video-game

Benefícios:

- Os tradicionais vale-transporte e plano de saúde
- Uma cozinha com lanche disponível o tempo todo e dois horários de lanche por dia (de manhã e de tarde)
- Não ter chefe, porque aqui não é nenhuma tribo.
- Você nunca vai ter que explicar seu trabalho nem vai ser avaliado com base em um Diagrama de Gantt


Quem derá as empresas tivessem um pouco mais desse espírito.
PS: não trabalho, não conheço nada nem ninguém da empresa.

quarta-feira, 23 de dezembro de 2009

Jpcsp - v0.4 lançado - Castelvania Dracula X Chronicles

JPCSP - O emulador do PSP feito em Java

A muito tempo não dou mais nenhuma contribuição no projeto Jpcsp mas não deixo de acompanhar o progresso do projeto. (Pra quem não sabe o que é o Jpcsp!) A última notícia foi mesmo um presente de natal, a versão 0.4 do Jpcsp foi lançada e já está disponível para download.

Sinto um pouco de orgulho por ter conseguido participar, efetivamente, e realizar um dos meus sonhos de moleque. (Criar um emulador :) )... agora deixando de conversa fiada segue alguns screenshots!

Castlevania - Dracula X Chronicles


Heatseeker


God of war (In menu)



Feliz Natal! ho ho ho - Veja mais notícias do Jpcsp ou os meus posts antigos sobre Jpcsp.

quinta-feira, 3 de dezembro de 2009

Adicione o recurso "você quis dizer" nas suas aplicações Java

SpellChecker - Uma extensão no Lucene

Continuando brincando com Lucene, no novo Lucene 3.0.0 encontrei uma pasta contrib na qual há libs diversas. Uma delas é o SpellChecker que lhe oferece recursos para que você implemente em suas aplicações java (web ou desktop) recursos como "Você quis dizer".

Recurso Você quis dizer

Imagine : Você é dono de uma loja virtual na qual é oferecido DVDs para venda. Um fanático pelo ator Arnold Schwarzenegger entra no sua loja e tem em mente comprar todos os DVDs desse ator (hoje, governador) a primeira ação do usuário é digitar o nome do ator no campo busca. Facilmente ele irá errar a digitação do nome, por exemplo digitando "arnold swuazeneger", e isso não deveria ser algo impeditivo para compra dos DVDs. Para esse problema bastaria a solução do tipo "Você quis dizer foo" implementada pelo Google Inc. no seu motor de busca. Você consegue esse mesmo, ou próximo, efeito em suas buscas utilizando uma das extensões do Lucene, chamada de SpellChecker. O exemplo-código abaixo é simples e demonstra como fazer isso.

Código


     Directory diretorioDicionario = new RAMDirectory();
//criação do diretório
SpellChecker sp = new SpellChecker(diretorioDicionario);
//instânciação do objeto SpellChecker
sp.indexDictionary(new PlainTextDictionary(new File("dicionario.txt")));
//indexação do Dictionary (há duas implementações).
String pesquisa = "arnold swuazeneger";
//seu termo pesquiado
int numeroDeSugestoes = 5;
//número de sugestões similares
String[] similares = sp.suggestSimilar(pesquisa, numeroDeSugestoes);
//as sugestões em si.

System.out.println("Seu Termo : " + pesquisa);
for (String palavra : similares) {
System.out.println("Você quis dizer: " + palavra);
}

pesquisa = "bava";
similares = sp.suggestSimilar(pesquisa, numeroDeSugestoes);
System.out.println("Seu Termo : " + pesquisa);
for (String palavra : similares) {
System.out.println("Você quis dizer: " + palavra);
}

Saída


Seu Termo : arnold swuazeneger
Você quis dizer: arnold schwarzenegger

Seu Termo : bava
Você quis dizer: java
Você quis dizer: lava
Você quis dizer: bala


Arquivo dicionario.txt:
arnold schwarzenegger
jean claude van damme
java
lava
bala

Conclusão

Nem sempre é tão difícil quanto parece, sempre há uma roda já pronta para seu problema. Você ainda pode ajustar a acurácia da pesquisa pelo método setAccuracy do SpellChecker. Claro que o uso do recurso em produção requer mais e mais atenção quanto ao diretório e o dicionário de busca. Baseado nos códigos acima, facilmente você consegue levar essa características para seus sistemas Java Web ( JSF - JavaServer Faces, Struts, JSP).

terça-feira, 1 de dezembro de 2009

Tutorial Apache Lucene 3.0.0 - motor de busca textual


Lucene um motor de busca textual

No dia 25 de novembro foi lançado a nova versão do motor de busca Lucene, a versão 3.0.0. Lucene é um framework de alta performance para busca textual feito em java. (há versões para php e .net também) Uma das características marcantes dele é a integração com Hadoop. (um framework para computação distribuida - que possui, dentre outros, um MapReduce e um sistema de arquivos distribuido HDFS)

Porque usar Lucene?

Imagine o seguinte cenário: Seu usuário deseja criar um modulo de gerenciamento de artigos e também expó-los na Internet. As informações do artigo são: título, autor e o contéudo. Normalmente cada artigo desse contém cerca de 1500 palavras e o usuário poderá buscar pelo conteudo desses artigos. Suponha que há 1 milhão e meio de artigos para serem cadastrados, o simples uso de um banco de dados e o operador LIKE '%palavra%' é inviável. E aí que entra um bom framework de busca textual, usá-lo passa ser a solução mais tranquila e viável. Além de trazer velocidade, também traz outras características nas buscas que dificilmente fariamos codificando tudo do zero.

Domain-Specific Language | Ubiquitous Language

Há vários termos usados na terminologia do framework, os principais são: Documento, Campo, Diretório, Indexador, Pesquisador, Analisador e Termo.

  • Documento - é o conjunto de dados que você deseja indexar, por ex. título, conteudo e autor formam o documento artigo, pode ser visto como um objeto no lucene é visto como Document.
  • Campo - é o dado, identificado, que pode ser analogo a um campo de uma tabela ou uma propriedade de um objeto no lucene é visto como Field.
  • Diretório - conceito abstrato que denota um local para guardar os índices no lucene é visto como uma interface Directory, que possui diversas implementações DbDirectory, FSDirectory, JEDirectory, RAMDirectory.
  • Indexador - é o responsável por indexar os documentos num diretorio no lucene é visto, geralmente, como IndexWriter.
  • Pesquisador - responsável por pesquisar uma Query no diretorio de índices, no lucene é visto como Searcher.
  • Analisador - atua como um filtro e faz uma pré-avaliação do que pode ser indexado ou não, no lucene há uma lista de vários analisadores.
  • Termo - pode ser visto como objeto que pode ser usado como parametro da pesquisa, composto pelo nome do campo e o valor a ser pesquisado, no lucene é visto como Term.

Como isso funciona?

A descrição a seguir é um resumo bem simplificado sobre o funcionamento de um motor de busca textual. A primeira fase, geralmente, é a indexação do documento, nessa fase o documento é analizado (por um Analizer que também já retira as stopwords) para posteriomente ser indexado.

Set stopWords = new HashSet();
stopWords.add("the");
stopWords.add("it");
stopWords.add("is");
IndexWriter writer = new IndexWriter(FSDirectory.open(INDEX_DIR),
new StandardAnalyzer(Version.LUCENE_CURRENT,
stopWords),
false,
IndexWriter.MaxFieldLength.LIMITED);


No Lucene você pode criar um índice usando o IndexWriter, a criação desse objeto envolve dizer onde será (ou está) o diretório dos índices, qual analizador você irá utilizar, se irá criar o indice e qual a quantidade máxima de campos.

O objetivo do indexador é indexar documentos, para tanto é necessário que haja documentos para serem indexados.
Document doc = new Document();
doc.add(new Field("nomedocampo", "valores a serem guardados", Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.add(new Field("camp1","valores a serem analisados tokenizados",Field.Store.YES, Field.Index.toIndex(true, true)));
writer.addDocument(doc);
É o objetivo final de todo processo de busca textual é mesmo a busca em si.
String valueToBeSearched = "red";
String index = "indexDir"; //dirotorio base do indice
IndexReader reader = IndexReader.open(FSDirectory.open(new File(index)), true); //indexador
Searcher searcher = new IndexSearcher(reader); //pesquisador
QueryParser parser = new QueryParser(Version.LUCENE_CURRENT, field, analyzer); //transoformador do texto em uma query
Query query = parser.parse(valueToBeSearched); //a consulta (query) em si
TopScoreDocCollector collector = TopScoreDocCollector.create(hitsPerPage, false); //os melhores resultados
searcher.search(query, collector);
ScoreDoc[] hits = collector.topDocs().scoreDocs; //o conjunto de melhores documentos para a consulta

int maximo = hits.length;
Document doc = searcher.doc(hits[index].doc);
String valor = doc.get("nomeDoCampo");

Recursos na busca de documentos

Quando se faz uma pesquisa por documentos no Lucene podemos utilizar de alguns operadores (+, -, AND, NOT, OR, * e etc.) juntamente com o termo pesquisado ou apenas pesquisar uma frase completa.

Exemplo : termo
Consequência: Irá pesquisar a palavra "termo" nos documentos indexados.

Exemplo : termo OR palavra ( == termo palavra)
Consequência: Irá pesquisar "termo" ou "palavra" nos documentos indexados.

Exemplo : +termo +palavra ( == termo AND palavra)
Consequência: Irá pesquisar "termo" e "palavra" nos documentos indexados.

Exemplo : campo:termo
Consequência: Irá pesquisar "termo" no campo "campo" nos documentos indexados.

Exemplo : +homer +simpsons -house
Consequência: Irá pesquisar documentos que contenham homer e simpsons e não tenha house.

Exemplo : "termo exato"
Consequência: Irá pesquisar documentos que contenham exatamente "termo exato".

Exemplo :
java*
Consequência: Irá pesquisar documentos que contenham palavras que começem com java (javadb, javanet...).

Exemplo : java~
Consequência: Irá pesquisar documentos que contenham palavras similares a java como por ex. lava, jaba...

Finalizando tive as seguintes impressões sobre essa nova versão do Lucene.

Prós:
  • Maior facilidade para uso do framework, ex: criações de Fields estão bem mais fluentes.
  • Sensível otimização nos tempos de busca e indexação.

Contras:
  • Otimas ferramentas como luke ainda não tem suporte para a versão 3.0.0. (mas já há uma solicitação aberta para tal mudança.)
  • Muitas mudanças no core do framework; o que fez livros mais antigos quase perderem seu valor.

Referências

terça-feira, 24 de novembro de 2009

quinta-feira, 29 de outubro de 2009

JPA - lock otimista e pessimista, concorrência e afins

JPA - Java Persistence API

JPA é especificação para mapeamento ORM e persistência de dados inspiradíssima no famoso framework Hibernate.

A especificação JPA (1.0) já é amplamente usada e aceita na comunidade de desenvolvedores Java. Há vários provedores de implementação para o padrão ( Hibernate , EclipseLink, TopLink ...)

Um assunto pouco explorado, quando se trata de tutoriais de jpa, é sobre locks (otimista e pessimista). E é sobre esse assunto que tento escrever um pouco aqui.

Tratamento de concorrência em bancos de dados

Há basicamente três tipos de tratamento para concorrência em banco de dados:
  1. Otimista - Quando é criado mecanismos para versionar o dado, no momento em que o banco vai efetivar sua operação sua versão é checada para garantir que você está com um dado que não foi alterado.
  2. Pessimista - O banco simplesmente trava o dado e só aquele que tem a trava consegue trabalhar com os dados.
  3. Ostrich - Quando não há tratamento nenhum pra concorrência :) , ou seja, a maioria dos casos atuais.

O exemplo básico

Começaremos com os perigos do modo Ostrich de agir. Para exemplificar criaremos uma simples classe.
@Entity
public class Produto implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String nome;
private double quantidade;
//getters and setters omitidos
}
Agora considere dois usuários A e B trabalhando sobre o Produto com id = 1( Nintendo Wii) ambos usuários têm o mesmo produto na tela de edição, o usuário A modifica quantidade e salva antes do usuário B, já o usuário B modifica o nome e salva depois. Note que há incosistência, o usuário A acredita (porque ele editou e salvou) que alterou a quantidade de nintendos wii, porém o usuario B (ainda com a quantidade antiga) mudou o nome e salvou o objeto. O que acontece? Depende do seu provedor de JPA, há casos em que o update só é feito para a coluna modificada mas há casos em que o objeto todo é modificado, o que causa claramente inconsistência. Escrever, escrever e escrever pode não ajudar então veja o código abaixo exemplificando esse cenário.
            Produto nintendoWiiA = em.find(Produto.class,1L);
Produto nintendoWiiB = em.find(Produto.class,1L);
/*Usuário A*/
em.getTransaction().begin();
nintendoWiiA.setQuantidade(45.0D);
em.getTransaction().commit();

/*Usuário B*/
em.getTransaction().begin();
nintendoWiiB.setNome("Nintendo WII");
em.getTransaction().commit();

System.out.println(em.find(Produto.class,1L));
ps: O código é apenas para demonstrar como isso é feito, não é funcional.

Agora para mudar esse exemplo para o modo otimista de ser basta criarmos uma propriedade no objeto com a anotação @Version para denotar que este campo será usado para o fim da implementação otimista. Esse campo deve ser int, long ou timestamp.

Com a adição do lock otimista quando o usuário B fosse tentar salvar suas modificações ele receberia a execeção OptimisticLockException. Isso já garantiria ao menos a notificação ao usuário que alguém estava trabalhando sobre o mesmo dado e ( lembra das canseiras que o IDE nos livra no versionamento de código) apartir dai você poderia mostrar o que foi mudado para o usuário tomar a decisão de salvar ou não suas alterações.

A parte chocante fica por conta do modo pessimista de ser, a JPA 1.0 não suporta diretamente o modo pessimista de ser (O JPA 2.0 prevê esse modo a mais :)

Então o que fazer?

Imaginem duas contas bancárias: (sempre esse exemplo) aMinhaConta (com saldo de R$ 150,00) e a suaConta (com saldo de R$ 25.000,00) e você quer me presentear com um Wii mas não tem como mandá-lo pelo correio, logo acha mais conviniente realizar uma transferência para que eu compre. O processo (bem simplificado) se resume a isso:

#0 quantiaASerDoada = R$ 1390,00;
#1 se suaConta.saldo > quantiaASerDoada então
#2 suaConta.transerePara(minhaConta, quantiaASerDoada);
#3 fim se

Se entre a linha 1 e 2 você fizer um saque de R$ 25.000,00 (isso pode ocorrer) a transferência não deveria ser realizada. Um modo para que isso ocorra é travar (lock) o dado que pode sofrer com essas concorrências. No JPA 1.0 você pode travar um objeto em dois passos (ai reside el peligro).

#0 Conta suaConta = em.find(Conta.class, 175789);
#1 em.lock(suaConta,LockMode.Write);

Mais uma vez entre a linha 0 e a 1 pode ocorrer um problema de concorrência. (tanto que a especificação JPA 2.0 já prêve um modo similar ao session do hibernate, o travamento no momento da leitura, em.find(Conta.class, 175789, LockMode.PESSIMISTIC);)

Solução fácil para o problema acima

Basta (se estiver usando Hibernate as your JPA provider) :

((Session) ((EntityManagerImpl) em.getDelegate()).getSession())

O session já tem um jeito de select for update session.get(SuaClasse.class, seuId, tipoDeTravamento). ( já perceberam que pra cada problema que você encontra na JPA 1.0 o hibernate quase sempre tem a solução?!)

Referências

http://en.wikibooks.org/wiki/Java_Persistence/Locking
http://www.javaworld.com/jw-07-2001/jw-0713-optimism.html