Uma das funcionalidades centrais do RDocumentation.org é a busca. Desde o início, nossa ideia foi ter uma barra de pesquisa super simples que encontra o que você precisa, sem exigir um formulário complexo pedindo nome do pacote, nome da função, versão ou qualquer outra coisa. Só uma barra de busca simples.
No blog técnico de hoje, vamos destacar as tecnologias e técnicas que usamos para entregar resultados relevantes e úteis para nossos usuários.
Elasticsearch
O RDocumentation.org usa o Elasticsearch para indexar e pesquisar em todos os pacotes e tópicos de R.
Elasticsearch é um mecanismo de busca open source, escalável, distribuído e de nível corporativo.
Elasticsearch é perfeito para consultar documentação porque não depende de dados SQL convencionais; ele armazena documentos em uma estrutura de dados similar a JSON. Cada documento é apenas um conjunto de pares chave-valor com tipos simples (strings, números, listas, datas, …). Por ser distribuído, o Elasticsearch pode ser extremamente rápido.
Um cluster Elasticsearch pode ter vários índices, e cada índice pode ter vários tipos de documento. Um tipo de documento descreve como deve ser a estrutura do documento. Para saber mais sobre os tipos no Elasticsearch, confira o guia em elastic.co.
O RDocumentation.org usa três tipos diferentes: package_version, topic e package. Os dois primeiros são os principais; vamos falar de package mais adiante.
Como o RDocumentation.org é open source, você pode ver os mapeamentos do Elasticsearch no nosso repositório no GitHub.
tipo package_version
O tipo package_version é como uma tradução do arquivo DESCRIPTION de um pacote e traz os principais campos encontrados nele: package_name, version, title, description, release_date, license, url, copyright, created_at, updated_at, latest_version, maintainer e collaborators. Os campos maintainer e collaborators são extraídos do campo Authors no arquivo DESCRIPTION.
tipo topic
Os documentos de tópico são analisados a partir dos arquivos Rd, o formato padrão de documentação em R. O tipo topic tem as seguintes chaves: name, title, description, usage, details, value, references, note, author, seealso, examples, created_at, updated_at, sections, aliases e keywords.
Pontuação no Elasticsearch
Antes de aplicar qualquer pontuação, o Elasticsearch primeiro tenta reduzir o conjunto de candidatos verificando se o documento realmente corresponde à consulta. Basicamente, uma consulta é uma palavra (ou um conjunto de palavras). Com base nas configurações da consulta, o Elasticsearch busca uma correspondência em certos campos de determinados tipos.
Mas uma correspondência não significa necessariamente que o documento é relevante; a mesma palavra pode ter significados diferentes em contextos diferentes. Com base nas configurações da consulta, podemos filtrar por tipo e campo e incluir mais informações contextuais. Essas informações melhoram a relevância — é aí que entra a pontuação.
O Elasticsearch usa o Lucene por baixo dos panos, então a pontuação se baseia na função prática de pontuação do Lucene, que combina modelos como TF-IDF, modelo de espaço vetorial e modelo booleano para pontuar o documento.
Se quiser se aprofundar em como essa função é usada no Elasticsearch, confira esta seção do guia da elastic.co.
Uma forma de melhorar a relevância é aplicar um boost em alguns campos. Por exemplo, na busca completa do RDocumentation.org, naturalmente damos mais peso a campos como package_name e title para pacotes e aliases e name para tópicos.
Dando mais peso aos documentos populares
Outra forma eficaz de melhorar a relevância é impulsionar documentos com base na sua popularidade. A ideia é simples: se um pacote é mais popular, é mais provável que o usuário esteja procurando por ele. Mostrar primeiro os pacotes mais populares aumenta a chance de entregarmos exatamente o que o usuário quer.
Usando downloads como medida de popularidade
Há várias maneiras de medir popularidade. Podemos usar medidas diretas, como votos ou classificações dadas pelos usuários (como as avaliações de produtos na Amazon), ou medidas indiretas, como número de itens vendidos ou número de visualizações (como em vídeos do YouTube).
No RDocumentation.org, escolhemos a segunda opção. Mais especificamente, usamos o número de downloads como medida de popularidade. Medidas indiretas costumam ser mais fáceis de coletar porque não exigem ação direta do usuário.
Janela de tempo
Um problema ao usar o número de downloads é que pacotes antigos naturalmente acumulam mais downloads totais do que pacotes novos. Isso não significa que sejam mais populares — eles apenas existem há mais tempo. E se um pacote foi muito popular anos atrás, mas ficou obsoleto e a comunidade quase não usa mais?
Para resolver isso, consideramos apenas o número de downloads do último mês. Assim, a popularidade de pacotes antigos não é inflada artificialmente e pacotes obsoletos perdem destaque rapidamente.
Downloads diretos vs. indiretos
Outro problema vem das dependências reversas. Pacotes R geralmente dependem de muitos outros pacotes. Pacotes com muitas dependências reversas serão baixados muito mais do que outros. Porém, esses pacotes costumam ser mais de baixo nível e não são usados diretamente pelo usuário final. Precisamos tomar cuidado para não dar peso exagerado ao número de downloads deles.
Como exemplo, veja o Rcpp. Mais de 70% de todos os pacotes no CRAN, o repositório abrangente de R, dependem dele — o que obviamente o torna o pacote R mais baixado. No entanto, poucos usuários de R usam esse pacote diretamente ou buscam sua documentação.
Para resolver esse problema, separamos downloads diretos (quando o usuário solicita o pacote) de downloads indiretos (quando o pacote é baixado por causa de uma dependência). Para distinguir downloads diretos e indiretos nos logs do CRAN, usamos a mesma heurística descrita no pacote cran.stats do Arun Srinivasan.
Com isso, temos uma métrica de popularidade significativa: o número de downloads diretos no último mês. O Elasticsearch oferece uma forma simples de injetar essa informação adicional; para mais detalhes, veja este artigo em elastic.co.
A pontuação é modificada assim:
new_score = old_score * log(1 + number of direct downloads in the last month)
Usamos a função log() para suavizar o valor de number of downloads, porque cada download adicional deve ter menos peso; a diferença entre 0 e 1000 downloads deve impactar mais a popularidade do que a diferença entre 100.000 e 101.000 downloads.
Esse reprocessamento de pontuação melhora a relevância geral dos resultados exibidos pelo RDocumentation.org e, como resultado, os usuários podem focar em ler a documentação em vez de procurá-la.
Se quiser ver como a consulta do Elasticsearch foi implementada, dê uma olhada no projeto RDocumentation no GitHub. A consulta em si está no SearchController.
Quer saber mais sobre como o RDocumentation.org é implementado? Confira nossos repositórios:
- RDocumentation-app: o aplicativo web que roda o rdocumentation.org.
- RDocumentation-elasticsearch: configuração e feeders do servidor Elasticsearch que atende o rdocumentation.org.
- RDocumentation: pacote R para integrar o rdocumentation.org ao seu fluxo de trabalho em R
- RDocumentation-lambda-worker: pipeline em AWS Lambda para processar a documentação de pacotes para o rdocumentation.org
Sobre o RDocumentation
O RDocumentation agrega a documentação de ajuda de pacotes R do CRAN, BioConductor e GitHub — as três fontes mais comuns de documentação atual de R. Mas o RDocumentation.org vai além de simplesmente agregar essas informações: ele coloca tudo ao seu alcance por meio do pacote RDocumentation. O pacote RDocumentation substitui as funções básicas de ajuda do pacote utils e dá a você acesso ao RDocumentation.org diretamente no RStudio. Descubra os pacotes R mais novos e populares, pesquise pela documentação e publique exemplos da comunidade.


