Apache Jena | TUTORIAL Apache Jena TUTORIAL Elo perdido Conheça um novo método para processar, combinar, analisar e apresentar informações ocultas em dados brutos usando a plataforma Jena: web semântica e dados vinculados (linked data) para Java. por Ian Dickinson O compartilhamento de dados é um dos tópicos mais quentes atualmente na computação. As fontes podem ser desde APIs do Facebook, dados científicos abertos e até dados públicos gerados pelo governo e disponibilizados gratuitamente. Por todos os lados, há alguém liberando novos dados para serem explorados por desenvolvedores e cientistas de dados [1]. Nesse cenário, espera-se que projetistas, exploradores de dados e desenvolvedores criem aplicativos de valor para usuários finais, com recursos novos e interessantes. Sendo um desenvolvedor, como abordar essa montanha de informações? Que ferramentas e técnicas serão úteis? Muitas abordagens estão disponíveis, variando desde de simples análise de arquivos com valores separados por vírgulas (CSV) em planilhas de dados, consulta em bancos de dados relacionais, chegando a ferramentas de larga escala e distribuídas de análise de informações na nuvem. Como cada técnica possui vantagens e desvantagens, e ao invés de fazer um levantamento completo de todas elas, vamos focar apenas em dados semânticos vinculados, mais especificamente na plataforma Jena. é autor do artigo123, sobre Jena” poderia ser escrito com a seguinte linha de código, podendo ser representado graficamente como na figura 1. A web semântica <ian> <autor-do> <artigo123>. <artigo123> <tem-o-assunto> “Jena”. Não por acaso, as técnicas e ideias da web semântica acabaram ganhando uma reputação de complexidade e dificuldade. O modelo de XML padrão do RDF (Resource Description Framework) é grosseiro, razão pela qual modelar o mundo real pode revelar nuances conflituosas. No entanto, em seu núcleo estão duas ideias importantes. A primeira é a de que estruturas ricas e expressivas de dados, descrevendo informações sobre determinado assunto, podem ser construídas a partir de um conjunto de informações simples sobre o relacionamento entre pares de elementos: duas entidades nomeadas ou uma entidade nomeada e um valor, como um número. Um exemplo simples: suponhamos que o identificador para o artigo que você está lendo é artigo123 (voltaremos a isso em breve); então, a sentença “Ian Figura 1: Uma representação gráfica da sentença. Linux Magazine #80 | Julho de 2011 Matematicamente, a estrutura exemplificada na figura é um gráfico direcionado, que rotula os dois nós e suas extremidades. Para ser simples, irei me referir a ele apenas como um gráfico. Uma vez que cada declaração contém tipicamente três elementos – o assunto, o objeto e o nome do predicado que os liga –, o termo triple é usado para denotar tal declaração. Isso leva a outras expressões como triplestore, para um banco de dados constituído de triples. A segunda das duas ideias importantes é o nome das coisas que não são valores, que é representado por URIs. Um URI (Uniform Resource Identifier, ou Identificador de Recursos Uniforme) refere-se a um conjunto de identificadores definidos pela RFC 2396. O mais importante desse conjunto é que ele inclui identificadores http:// para websites familiares. O uso de URIs por identificadores tem duas consequências importantes: primeiro, todos os identificadores formam eficazmente um grande namespace, minimizando as chances de usar acidentalmente um mesmo nome para 63 TUTORIAL | Apache Jena se referir a coisas diferentes. Segundo, a maioria dos URIs podem ser “resolvidos” ou procurados com um navegador de Internet, de forma que dê informações sobre o termo que está sendo identificado. Além das consequências óbvias de ter o significado, ou a semântica, declarado explicitamente, isso significa também que o responsável pela manutenção do domínio web que hospeda o identificador tem alguma autoridade sobre o uso ou significado pretendido do termo. Além disso, qualquer um pode reutilizar um termo publicado em um domínio. Aliás, a web semântica acaba encorajando esse tipo de ação. No entanto, somente pessoas com direitos de escrita direta sobre aquele domínio podem atualizar o significado mais diretamente associado aos termos. Então, para atualizar o exemplo com o uso de URIs, precisamos considerar quais identificadores usar. Sempre que possível, deve-se tentar reutilizar vocabulários existentes. O vocabulário Dublin Core Metadata Initiative [2] possui um conjunto bem estabelecido de vocábulos para “metadados conhecidos”, como o autor de uma matéria. O próprio artigo, aliás, eventualmente ganhará uma identidade no espaço web de quem publica. Por enquanto, isso é um rascunho. Imagine portanto o URI padrão http://epimorphics.com/documents/ draft#jena-1. O URI para dar cré- Listagem 1: Código gerado pelo Schemagen no Doap.Java 01 /** URL de uma homepage de um projeto, associada com exatamente um projeto. */ 02 public static final Property homepage = m_model.createProperty( "http://usefulinc.com/ns/doap#homepage" ) Listagem 2: O núcleo do Init.java 01 public void run() { 02 if (noTDB() || hasOption( "f" )) { 03 // (re)criar a imagem TDB 04 FileUtils.deleteQuietly( getTDBFile() ); 05 FileUtils.forceMkdir( getTDBFile() ); 06 Dataset dataset = TDBFactory.createDataset( getTdbLocation() ); 07 08 // o nome do projeto é um argumento requisitado 09 String projectName = getArgs()[0]; 10 String projectURI = projectNamespace() + projectName; 11 Resource project = dataset.getDefaultModel(). createResource( projectURI ); 12 13 project.addProperty( RDF.type, DOAP.Project ); 14 project.addProperty( DOAP.name, projectName ); 15 16 // adicione descrições a partir de opções de linhas de comando 17 addOptionalProperty( project, DOAP.shortdesc, "s" ); 18 addOptionalProperty( project, DOAP.description, "d" ); 19 20 System.out.println( String.format( "Criada nova descrição DOAP para %s projetos com %s triples", projectName, dataset.getDefaultModel().size() ) ); 21 } 22 else { 23 System.out.println( "Logbook já existe, nenhuma ação sendo tomada" ); 24 } 25 } 64 ditos ao autor deve ser tratado com cuidado, porque uma pessoa não é um recurso de informação na web. Essa questão, amplamente debatida, tem uma série de soluções que vão além do escopo deste artigo. Um URI elaborado com a classe Person do vocabulário Friend of a Friend (FOAF, ou amigo do amigo) [3], será suficiente. Com essas mudanças, o exemplo fica assim: <http://epimorphics.com/rdf/ staff#ian> rdf:type foaf:Person. <http://epimorphics.com/rdf/ staff#ian> dcterms:creator. <http://epimorphics.com/documents/ drafts/jena-1>. <http://epimorphics.com/documents/ drafts/jena-1> dcterms:subject “Jena”. <http://epimorphics.com/documents/ drafts/jena-1> rdf:type foaf:Document. Claro que poderíamos entrar em muitos detalhes sobre as várias tecnologias de web semântica: linguagens de consulta, armazenamento persistente, vocabulários específicos e assim por diante. Para focar na prática, no entanto, falareremos apenas sobre como os triples podem ser manipulados com código Java usando o Jena. Apache Jena O Jena é um framework Java de código aberto para criar, armazenar, manipular e consultar dados semânticos na web. Foi desenvolvido originalmente por pesquisadores dos laboratórios da HP no Reino Unido e tem sido amplamente utilizado desde seu primeiro lançamento em 2001. Em 2008, o time do Jena deixou a HP e, em 2009, o Jena se tornou um projeto incubado na Apache [4]. Ao invés de listar os recursos técnicos do Jena, vamos introduzir a abordagem de algumas partes do framework enquanto trabalhamos por meio de exemplos. Algumas linhas de terminologia básica, no entanto, ajudarão. O gráfico descrito previamente é gerenciado no código Jena como um www.linuxmagazine.com.br Apache Jena | TUTORIAL objeto Model. O objeto é, nos termos do Java, uma interface ou especificação abstrata que permite ao Jena fornecer vários tipos de objetos Model (armazenado na memória, no disco, sem interferência de disco etc.) com uma API comum. O Model é uma das abstrações chaves do Jena para lidar com RDF. Um recurso no modelo, denotado por uma URI, é representado por um objeto Resource, enquanto um valor, como um número, é um Literal. O predicado que liga os nós do gráfico são objetos Property, e Property é uma subclasse de Resource. Finalmente, um objeto Statement representa um triple. Um determinado Statement terá um assunto Resource, um predicado Property e um objeto, que pode ser tanto um Resource quanto um Literal. Chega de teoria. Vamos ver um pouco de código. Exemplo de aplicativo Suponhamos que você queira compartilhar detalhes com outros desenvolvedores de código aberto, como, por exemplo, o nome do projeto, a localização do repositório fonte, quem está trabalhando nele e assim por diante. Felizmente, um vocabulário já existe para gravar esse tipo de informação: DOAP (Description of a Project, ou descrição de um projeto) [5] [6]. Coincidentemente, os projetos da Apache são encorajados a usar arquivos DOAP. Embora o DOAP forme o núcleo de um caderno de notas de um aplicativo, você deve ter a possibilidade de adicionar outras informações que pareçam relevantes sem ser restringido por esquemas rígidos de dados. Projetar uma ferramenta visual rica em recursos para criar e editar arquivos DOAP está além do escopo deste artigo. Em vez disso, tenho a meta de criar um conjunto de ferramentas de linhas de comando e atualizar um diário de bordo, imprimir um relatório e enriquecê-lo ao mesclar informações a partir de uma fonte externa. O objetivo deste miniprojeto é gerar e manter dados DOAP para um projeto em particular; assim, eu presumirei Listagem 3: Consultar o ref:type 01 /** O recurso com URI tem rdf:type t? */ 02 public boolean hasType( String u, Resource t ) { 03 return getModel().getResource( u ).hasProperty( RDF.type, t ); 04 } Listagem 4: Acumular documentos RDF descobertos por meio do sindice.com 01 // fase de leitura: adicione os documentos em um modelo combinado 02 Model m = ModelFactory.createDefaultModel(); 03 for (ResIterator i = sIndex.listSubjectsWithProperty( RDF.type, Sindice.Result ); i.hasNext(); ) { 04 String docURL = i.next().getPropertyResourceValue( Sindice.link ).getURI(); 05 06 // poderíamos ser mais sofisticados sobre a proveniência dos recursos 07 try { 08 m.read( docURL ); 09 } 10 catch (RuntimeException e) { 11 // alerte sobre falha de leitura, mas siga na leitura de outros documentos 12 log.warn( String.format( “Failed to retrieve from %s because: %s”, docURL, e.getMessage() ) ); 13 } 14 } Linux Magazine #80 | Julho de 2011 que os dados DOAP estão armazenados no diretório do próprio projeto. Com o tempo, meu objetivo poderá ser o de desenvolver a ferramenta para armazenar mais do que simples dados DOAP, talvez até incluir controle de tempo, entre outras informações. Por essa razão, vou generalizar o nome e chamá-lo simplesmente de “Projeto Diário de Bordo”, representado pelo termo plb. Para brincar com o código, veja o quadro 1. Uma escolha razoável para o projeto seria armazenar os dados em um simples arquivo RDF. No entanto, como meu o objetivo é ilustrar os vários recursos do Jena, vamos armazenar o RDF gerado em um triplestore persistente. O Jena tem uma série de soluções de armazenamento RDF persistentes. Vamos usar o TDB, customizado para triplestore, com a capacidade de armazenar um grande números de triples com eficiência sem requerer um banco de dados relacional adicional, como o MySQL, por exemplo. O TDB pode suportar ordens de magnitude muito maior que aquelas que eu vou gerar agora, mas ele torna bem direta a tarefa de atualizar o banco de dados persistente. Quadro 1: Teste o código Para o projeto, você precisará de um compilador Java que suporte Java 1.6. Eu estou usando também o Maven para gerenciar o Jena e outras bibliotecas dependentes. Então, você precisará da versão mais recente do mvn. Finalmente, o código está no repositório Git e o exemplo também lida com metadata Git, de modo que você precisará do Git instalado. O pom.xml, no diretório raiz do projeto, lista as dependências de software. O Maven instalará todos automaticamente como necessário. Para clonar o projeto do repositório Git, use o seguinte comando: git clone [email protected]: epimorphics/epimorphics-open/ jena-plb-tutorial.git 65 TUTORIAL | Apache Jena Início do projeto O problema tem quatro componentes: inicializar o projeto, atualizar a descrição DOAP manualmente, aumentar a descrição automaticamente e reportar o perfil DOAP. Cada componente é chamado pela linha de comando (quadro 2). Inicializar o projeto é algo direto: você precisará criar o elemento de armazenamento TDB (ou recriar se o usuário quiser forçar a criação de um novo elemento de armazenamento) e adicionar um recurso root para representar o projeto DOAP que estou descrevendo. Criar um elemento de armazenamento TDB requer um diretório para os dados – vamos usar o ./.plb/tdb por padrão – e um chamado Java. O chamado é uma linha getTdbLocation(), método que retorna uma string especificamente no diretório TDB. Dataset dataset = TDBFactory. createDataset( getTdbLocation() ); Criar o recurso root para o projeto é conceitualmente simples: é preciso somente um URI para denotar o projeto e esse deve ser atribuído ao doap:Project. Aqui, doap: é o componente namespace do URI e se expande para http://usefulinc.com/ns/doap#, enquanto Project é o nome de uma classe RDFS. Matematicamente, classes RDFS (RDF Schema ou Esquema RDF) correspondem a conjuntos de coisas que compartilham características semelhantes – o conjunto de todas as coisas que são descrições de projetos, por exemplo. Para desenvolvedores, é interessante pensar nas classes RDFS como análogas aos types na linguagem Java ou outras linguagens de programação. Tenha em mente, no entanto, que as classes Java e as classes RDFS têm diferenças importantes. Em particular, à medida que você descobre mais informações sobre um recurso, você poderá achar que se trata de um membro de uma classe que você não sabia de que fazia parte. Além disso, 66 um recurso pode ser membro de muitas classes ao mesmo tempo. Obter o código Java para fazer com que o recém criado projeto seja membro da classe doap:Project vai requerer um novo triple, com o projeto como assunto, o predicado especial rdf:type como propriedade e um recurso denotando a classe doap:Project como um objeto. O URI doap:Project não muda (a não ser que o esquema mude), então este será definido como constante. Embora seja possível escrever manualmente a declaração de uma constante no código, correríamos o risco de fazer erros de transcrição e criar problemas de manutenção com a mudança de esquema. Felizmente, o Jena oferece uma ferramenta que gera um código Java automaticamente a partir de um arquivo RDFS, o schemagen. A classe Java gerada define constantes para cada uma das classes, propriedades e recursos in- dividuais definidos no arquivo. A ferramenta Schemagen pode ser executada a partir da linha de comando ou como um plugin Maven [7]. Uma amostra do código gerado aparece na listagem 1. Os vocabulários completos estão incluídos no projeto para download. Considerando que eu tenho acesso às propriedades e classes DOAP por meio da classe DOAP.java, o início do projeto é direto, como mostrado na listagem 2. Inclusão manual no diário de bordo Muitos bits de informação útil sobre um projeto devem ser capturados, inclusive as várias propriedades diferentes utilizadas pelo DOAP. Assim, eu quero que meus usuários possam adicionar informações de forma incremental. No entanto, é necessário atingir um balanço na interface apre- Listagem 4: Acumular documentos RDF descobertos por meio do sindice.com 01 // fase de leitura: adicione os documentos em um modelo combinado 02 Model m = ModelFactory.createDefaultModel(); 03 for (ResIterator i = sIndex.listSubjectsWithProperty( RDF.type, Sindice.Result ); i.hasNext(); ) { 04 String docURL = i.next().getPropertyResourceValue( Sindice.link ).getURI(); 05 06 // poderíamos ser mais sofisticados sobre a proveniência dos recursos 07 try { 08 m.read( docURL ); 09 } 10 catch (RuntimeException e) { 11 // alerte sobre falha de leitura, mas siga na leitura de outros documentos 12 log.warn( String.format( "Failed to retrieve from %s because: %s", docURL, e.getMessage() ) ); 13 } 14 } Listagem 5: Modelo de consulta 01 String queryString = String.format( "describe ?s where {?s <%s> \"%s\"}", FOAF.mbox_sha1sum.getURI(), mboxSha1 ); 02 // analise a consulta 03 Query query = QueryFactory.create( queryString ) ; 04 // vincule ao modelo 05 QueryExecution qexec = QueryExecutionFactory.create( query, collected ); 06 // faça a consulta 07 dev.getModel().add( qexec.execDescribe() ); www.linuxmagazine.com.br Apache Jena | TUTORIAL sentada aos usuários. Como não há modelo de dados fixo, o RDF permite que qualquer predicado seja anexado a qualquer recurso, algumas vezes declarado como “qualquer um pode dizer qualquer coisa sobre qualquer coisa”. Esse modelo pode ser muito poderoso, mas tanta abertura pode dificultar as coisas. Por exemplo, há algumas restrições na estruturação da interação do usuário. Nesse caso, não espero que os usuários digitem uma propriedade URI completa ou linha de comando só para adicionar um triple para a descrição do projeto; então, permitirei que qualquer propriedade no vocabulário do DOAP seja abreviada somente com seu nome de local, menos o namespace. Os usuários digitarão algo como: $> plb set language Java $> plb set -r release 1.0.1 Esses dois comandos adicionam valores para doap:language e doap:release; a bandeira -r substitui um valor existente armazenado. O código RDF específico na classe de ação Set é pequeno: a maior parte do código é ocupada com checagem de rotina e manipulação de argumen- tos. A definição da classe completa pode ser encontrada no download. Com Jena, toda informação de estado é mantida no objeto Model. No entanto, um objeto Resource contém referência para o Model que o contém. Então, eu posso perguntar ao Resource pelos seus triples relacionados, ou seja, pergunto se um determinado URI corresponde ao recurso com um rdf:type em particular (aqui atribuído ao parâmetro type; listagem 3). Dado um Resource denotando o projeto, posso adicionar um novo triple com esse recurso como um assunto, usando o método addProperty. Já que eu optei por usar um modelo baseado em TDB persistente, eu não preciso fazer uma chamada separada para salvar os triples atualizados no disco. Dados automáticos no diário de bordo Até então, eu criei um novo diário de bordo usando TDB e uma armazenagem triple, defini um recurso para representar o projeto e permiti que os usuários anexassem algumas propriedades à linha de comando. É um começo sólido, mas não fez muito ainda pela web semântica e os princípios de dados ligados. Meu projeto tem alguns desenvolvedores. Deste modo, vamos assumir que eu quero anotar no meu diário de bordo quaisquer informações que possam ser coletadas sobre eles para ter a visão mais fiel possível sobre o projeto. Para evitar questões de privacidade, vamos usar somente informações públicas. Qual seria a estratégia? Se o projeto está usando um sistema de gerenciamento de recursos, posso listar todos eles facilmente. Nesse tutorial, vou presumir que o código é gerenciado por um repositório Git. Algum processamento simples do log do Git listará os desenvolvedores por nome e e-mail e podemos usar o endereço de e-mail como uma chave para reunir mais dados. Amigo do amigo (Friend of a Friend ou FOAF [8]) é outro vocabulário RDF usado amplamente. As pessoas utilizam FOAF para publicar dados pessoais, como Listagem 6: Listar todos os desenvolvedores do projeto 01 $ sp="prefix foaf: <http://xmlns.com/foaf/0.1/> prefix doap: <http://usefulinc.com/ns/doap#> prefix plb: <http://www.epimorphics.com/tutorial/plb#> prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> 02 $ tdbquery --loc=.plb/tdb "$sp select ?p ?e ?w {?p a doap:Project . ?p doap:developer ?d. optional {?d foaf:mbox ?e ; foaf:homepage ?w}}" 03 -------------------------------------------------------------------------------04 | p | e | w | 05 ================================================================================ 06 | plb:plb | "mailto:[email protected]" | <http://www.iandickinson.me.uk> | 07 | plb:plb | "mailto:[email protected]" | <http://www.iandickinson.me.uk> | 08 -------------------------------------------------------------------------------- Listagem 7: Listar todas as propriedades do projeto 01 02 03 04 05 06 07 08 09 10 $ tdbquery --loc=.plb/tdb "$sp select ?p ?o where {?proj a plb:root . ?proj ?p ?o} order by ?p" ---------------------------------------------------------------------------------------| p | o | ======================================================================================== | doap:description | "A Jena tutorial showing how to create DOAP project descriptions" | | doap:developer | <http://www.iandickinson.me.uk/rdf/foaf#ian> | | doap:name | "plb" | | doap:shortdesc | "Jena PLB tutorial" | | rdf:type | doap:Project | ---------------------------------------------------------------------------------------- Linux Magazine #80 | Julho de 2011 67 TUTORIAL | Apache Jena websites, detalhes de contato, interesses e amigos que conhecem por referência de perfis de outros amigos. A princípio, eu poderia usar esses detalhes do log inicial para procurar informações públicas dos membros e adicionar automaticamente ao diário de bordo. Na história inicial do FOAF, a prática de disfarçar endereços de e-mail para evitar spams era uma medida comum contra estes; assim, precisamos buscar pela soma SHA1 dos endereços de e-mail dos meus desenvolvedores. Um algoritmo ideal para obter essa informação seria: for each unique committer C let m be the email address of C let s be sha1( m ) run the sparql query: describe ?person where {?person foaf:mbox_sha1sum “value of s”} A linguagem SPARQL é a padrão para fazer consultas em armazenagens triple RDF e é totalmente suportada pelo Jena. Ela tem quatro verbos de consulta: Quadro 2: Empacotador de linhas de comando Uma variedade de comandos pode ser executada de um shell. Em vez de um script Bash para cada um deles, um script empacotado, plb, pode chamar um conjunto de comandos diferentes. Veja o exemplo: plb init test-project O script Bash plb chama um programa Java para desempenhar o comando predefinido no primeiro argumento, com a convenção de que um comando cmd corresponde a classe Java com.epimorphics.plb. Cmd. Para ter dependências no caminho da classe, o script empacotador executa o programa com mvn:exec, que, por sua vez, executa um programa Java arbitrário com todas as dependências do pom.xml, baixando as dependências que faltam antes, se necessário. O script Bash está no diretório bin do projeto plb. 68 ➧ select: entrega linha de valores correspondentes, semelhante às armazenagens relacionais SQL; ➧ ask: confirma se um padrão de consulta pode ser correspondido; ➧ construct: cria um novo gráfico com o uso de templates e padrões e consultas; ➧ describe: transfere a responsabilidade de retornar uma descrição útil de um recurso para um servidor, suportando especificamente o caso no qual o cliente não sabe a estrutura do gráfico contendo um recurso em particular. Tipicamente, o servidor retorna algum tipo de descrição vinculada [9]. O ponto chave, aqui, é que o cliente – meu programa – não sabe os esquemas que podem ser usados para anotar um recurso particular, razão pela qual os verbos descritos são úteis para obter um conjunto de dados que podem ser processados localmente. O único problema com meu algoritmo, é que, no momento da escrita, um serviço disponível publicamente que agregava dados FOAF de múltiplos pontos de publicação ficou indisponível. No entanto, o projeto de serviço de pesquisa Sindice [10] proporciona um índice navegável para todos os documentos RDF que possam ser detectados. Posso emendar meu algoritmo da seguinte maneira: for each unique committer C let m be the email address of C let s be sha1( m ) query sindice.com for docs mentioning s for each found document accumulate the doc into local model L run the sparql query against model L: describe ?person where {?person foaf:mbox_sha1sum “valor do s”} A princípio, o programa poderia obter uma lista de desenvolvedores de qualquer fonte de sistema de gerenciamento, no entanto o tutorial somente lida com o repositório Git. O retorno daquela parte de código é um Model do Jena, contendo recursos denotando os desenvolvedores no projeto, cada um com um foaf:mbox denotando seu endereço de e-mail como dado ao Git. O que são esses recursos, no entanto? Uma vez que eu não sei as reais identidades dos desenvolvedores, apenas um dos endereços de e-mail, que recurso URI deve ser usado para denotar cada desenvolvedor? Eu poderia criar um identificador, porém o RDF também permite um tipo especial de recurso chamado recurso anônimo (anonymous resource). Esse recurso age como qualquer outro, exceto pelo fato de não ter identidade conhecida. Por razões históricas, é normalmente chamado de bNode, que pode ser usado como um alocador de recurso, sobre o qual conheço a existência e propriedades, mas não conheço a identidade. No exemplo plb, eu crio bNodes para denotar os desenvolvedores antes de reunir informações sobre eles de fontes públicas. A API Sindice é muito fácil: é só chamar http://sindice.com/search?q= com o termo de busca depois do sinal de igual (=). Esse endereço usa negociação de conteúdo HTTP para determinar o formato no qual deve retornar resultados, o que faz da busca algo muito natural para o Jena, uma vez que o método Model. read() faz com que o tipo favorito de conteúdo vá ao RDF. Para procurar por todos os documentos que mencionam uma caixa de correio SHA1 em particular, mboxSha1, tudo o que eu tenho de fazer é digitar: Model sIndex = ModelFactory. createDefaultModel(); sIndex.read( “http://api.sindice. com/v2/search?q=” + mboxSha1 ); O Model resultante contém um conjunto de recursos sindice:Result denotando as buscas. Para cada uma das buscas, eu tento executar o link para o documento original, tendo em mente que isso pode falhar se o documento foi indexado há algum tempo. A listagem 4 mostra o processo. www.linuxmagazine.com.br Apache Jena | TUTORIAL Dado um modelo que contenha triples potencialmente relevantes e acumuladas, eu posso executar a consulta descrita (listagem 5). Aqui, collected (linha 5) é o modelo contendo os triples dos documentos que foram coletados da web e dev (linha 7) são os recursos para o desenvolvedor sendo adicionados à descrição do projeto. Resta um passo. Eu utilizei muitas informações da web. O modelo inclui uma série de fontes denotando a mesma pessoa, alguma delas sendo bNodes; e eu gostaria de simplificar o gráfico, mesclando essas fontes redundantes. O Jena não tem uma ferramenta interna para fazer isso, mas não é difícil com a propriedade foaf:mbox_ sha1sum, que é uma boa chave de desambiguação. Em geral, esse tipo de mesclagem de informação pode ser bem complexo, mas não com essa simples abordagem. Finalmente, adicionei os resultados da consulta describe para meu modelo TDB persistente. Relatórios A SPARQL é útil também quando quero produzir relatórios simples a partir do diário de bordo. O comando tdbquery está disponível na instalação completa do Jena e executa uma consulta contra um modelo TDB da linha de comando. Por exemplo, eu poderia listar todos os desenvolvedores no projeto com os seus sites, se conhecidos (listagem 6), ou listar cada propriedade do projeto (listagem 7). Obviamente, eu poderia escrever relatórios muito mais abrangentes, mas precisaria de tutoriais separados para isso. Conclusão Meu objetivo com este artigo foi introduzir os recursos Jena para uma tarefa prática. Não pretendo, com isso, oferecer a melhor forma de gerar perfis DOAP. Na verdade, o plugin Maven Linux Magazine #80 | Julho de 2011 faz esse trabalho. No entanto, a combinação de um formato flexível de dados e a habilidade de mesclar informações de múltiplas fontes na web mostra as possibilidades tanto do Jena em relação à abordagem de web semântica e dados vinculados em geral. O Jena está, atualmente, incubado na Apache, e contribuições são bem vindas: bugs, sugestões, correções etc. Mais informações estão disponíveis no site do Jena. ■ Gostou do artigo? tigo? Queremos ouvir sua ua opinião. Fale conosco em m [email protected] gazine.com br Este artigo no nosso osso site: te: http://lnm.com.br/article/5494 br/art /549 Mais informações [1] “What is Data Science?” por Mike Loukides, O’Reilly Radar, junho de 2010: http://radar. oreilly.com/2010/06/ what-is-data-science.html [2] Dublin Core Metadata Initiative: http:// dublincore.org/ [3] Vocabulário FOAF: http:// xmlns.com/foaf/spec/ [4] Projeto Apache Jena: http:// incubator.apache.org/jena [5] Vocabulário DOAP: http:// usefulinc.com/ns/doap# [6] Página DOAP: http:// trac.usefulinc.com/doap [7] Código-fonte Jena: http:// jena.sourceforge. net/downloads.html [8] Projeto Friend of a Friend: http://www. foaf-project.org/ [9] Descrição vinculada: http://goo.gl/rOjmt [10] Serviço Sindice: http:// www.sindice.com/ 69