SlideShare uma empresa Scribd logo
1 de 45
Baixar para ler offline
Luciano Ramalho
                                      luciano@ramalho.org
                                              @ramalhoorg




               Open Library no MongoDB


     Usando Map/Reduce e o Aggregation Framework
     para análise e modelagem de dados
Tuesday, July 17, 12
Temas
           • Sobre o projeto Open Library
           • Conversão e importação da massa de dados
           • Análise dos dados com o framework de agregação
           • Análise dos dados com Map	

/Reduce
           • Refatoração do modelo de dados para o
                   MongoDB
           • Encerramento
                                                     @ramalhoorg
Tuesday, July 17, 12
Sobre o projeto
                        Open Library



                                         @ramalhoorg
Tuesday, July 17, 12
Sobre a Open Library
           • Missão:
               “One web page for every book”
           • Um projeto do Internet Archive
           • 117.439.126 registros bibliográficos em jun/2012
           • Mais de 1.000.000 de e-books gratuitos para
                   baixar (livres, CC, domínio público etc.)

                                                               @ramalhoorg
Tuesday, July 17, 12
A Tecnologia da
       Open Library
         • Infobase: uma API Python para bases de dados
                 semi-estruturadas sobre tabelas normalizadas
                • também conhecida como ThingDB
         • Inclui versionamento de registros
         • Muitos join para recuperar uma entidade conceitual
         • Fortemente depenente do SOLR/Lucene para
                 exibir suas páginas
                                                           @ramalhoorg
Tuesday, July 17, 12
Modelo de dados
       semi-estruturado
           • Base teórica existe!
           • Palavras-chave para pesquisa:
                   semistructured ou semi-structured database

    “The semi­structured data model is designed as an
   evolution of the relational data model that allows the
     representation of data with a flexible structure. ”
                                    SUCIU, Dan. Semi­Structured Data Model.
                                           In: LIU, L. Encyclopedia of Database Systems
                                                                           @ramalhoorg
Tuesday, July 17, 12
Data on the
       Web (1999)
           • From Relations to
                   Semistructured Data
                   and XML
           • Autores: Abiteboul,
                   Buneman & Suciu
           • Notação apresentada:
                   semelhante a JSON

                                         @ramalhoorg
Tuesday, July 17, 12
Semistructured
       Database Design
       (2004)
           • Autores: Ling, Lee & Dobbie
           • Algoritmos de normalização
                   sem a 1ª Forma Normal
                   (N1NF = Non First Normal
                   Form)

                                              @ramalhoorg
Tuesday, July 17, 12
Conversão e
                       importação da
                       massa de dados



                                        @ramalhoorg
Tuesday, July 17, 12
Massa de dados
           • OL Complete Dump: ol_cdump_latest.txt.gz*
           • 118.598.056 linhas em 1/jun/2012
           • 16 GB comprimidos (.gz), 91 GB sem compressão
           • 32 tipos diferentes de registros
            • 1.158.930 (~1%) não são registros bibliográficos
           • Inclui todas as revisões de todos os registros
                       * http://openlibrary.org/developers/dumps
                                                         @ramalhoorg
Tuesday, July 17, 12
Converter para carregar
           • Escolha de uma chave primária (campo _id)
            • Chave composta: key+"-"+revision
              • /books/OL1656964M-1
           • Opção adotada: a conversão mais simples possível
            • Usar JSON do dump, acrescido de campo _id

                                                       @ramalhoorg
Tuesday, July 17, 12
Carga: conversor_ol.py
        import sys
        import json
        import io

        def conv_linha(lin, indent=None):
            rec_type, rec_key, rec_revision, rec_modified, rec_json = lin.split(u't')
            rec = json.loads(rec_json)
            rec[u'_id'] = rec_key + u'-' + rec_revision
            return json.dumps(rec, indent=indent)

        def conv_arquivo(nome_arq, max_lin=sys.maxsize, indent=None):
            with io.open(nome_arq, encoding='utf-8') as arq:
                for num_lin, lin in enumerate(arq, 1):
                    if not lin.strip():
                        continue
                    saida = conv_linha(lin, indent)
                    print saida.encode('utf-8')
                    if num_lin >= max_lin:
                        break

        if __name__=='__main__':
            if len(sys.argv) == 2:
                converte_arquivo(sys.argv[1])
            else:
                print 'Modo de usar: %s <ol_dump_file>' % __name__


                                  * https://github.com/ramalho/mongosp
                                                                @ramalhoorg
Tuesday, July 17, 12
Usando mongoimport
  python conversor_ol.py $1 | 
    mongoimport -d openlibrary -c complete --stopOnError

           • -d: database
           • -c: collection
           • --stopOnError: interromper se houver erro
           • --upsert: sobrescrever ao importar _id duplicado
                   (default: ignorar o novo registro)
           • --file: arquivo a inserir (default: stdin)
                                                         @ramalhoorg
Tuesday, July 17, 12
Análise dos dados usando
         o framework de agregação



                              @ramalhoorg
Tuesday, July 17, 12
Indexação para análise

           • Criar índices esparsos para:
            • key
            • revision
            • type
            • outros...
                                            @ramalhoorg
Tuesday, July 17, 12
Aggregation Framework:
       o básico
           • Novidade no MongoDB 2.1/2.2
           • Alternativa ao Map/Reduce
           • Mais fácil de usar
           • Melhor desempenho
            • implementado em C++, usa threads
                       (Map/Reduce depende do interpretador
                       JavaScript Spidermonkey, mono-thread)
                                                               @ramalhoorg
Tuesday, July 17, 12
Exemplo: group_types.js
      db = db.getMongo().getDB('openlibrary');
      db.complete.ensureIndex({"type.key":1});

      var res = db.complete.aggregate(
          { "$group" : {
              ! "_id" : "$type.key",

          }},
              ! "qt" : { "$sum" : 1 }               • $group
      );
          { "$sort" : { "qt" : -1 }}                • $sort
      res.result.forEach(function (r) {
          print(r.qt+"t"+r._id);
      });

                       * https://github.com/ramalho/mongosp
                                                     @ramalhoorg
Tuesday, July 17, 12
Exemplo: group_types.js
                                  $ time mongo2.1

       • O primeiro lote
                                  group_types.js
                                  MongoDB shell version: 2.1.2
               de 1.000.000 de    connecting to: test
                                  605781! /type/edition
               registros tem 9    382428! /type/author
               tipos diferentes   9211!/type/work
                                  1935!/type/redirect
       • Os três primeiros        623! /type/delete
                                  7! /type/template
               são os mais        7! /type/page
               importantes:       5! /type/doc
               edition, author,   3! /type/macro
               work               real!0m23.658s
                                  user!0m0.030s
                                  sys! 0m0.004s        @ramalhoorg
Tuesday, July 17, 12
Agregação em estágios
           • Estágios: etapas em um fluxo (steps in a pipeline)
           • Estágios são executados em ordem, na ordem dos
                   parâmetros da invocação de mapReduce
           • Cada estágio aplica um operador especial
           • O mesmo operador pode ser usado várias vezes
                   em estágios diferentes


                                                          @ramalhoorg
Tuesday, July 17, 12
Operadores de estágios
           • $match     • $group
           • $project   • $sort
           • $limit     • $unwind
           • $skip


                                    @ramalhoorg
Tuesday, July 17, 12
Exemplo 2a
                       * https://github.com/ramalho/mongosp
      var res = db.complete.aggregate(
          { $match : {"type.key" : "/type/edition"} },
          { $project : { languages : 1} },
          { $unwind : "$languages" },
          { $group : {
              _id : "$languages.key",            • $match

          }},
              qt : { $sum : 1 }
                                                 • $project

      );
          { $sort : { qt : -1, _id : 1 }}
                                                 • $unwind
                                                 • $group
                                                 • $sort
                                                    @ramalhoorg
Tuesday, July 17, 12
Exemplo 2b
                              * https://github.com/ramalho/mongosp
                  db = db.getMongo().getDB('openlibrary');
                  db.complete.ensureIndex({"revision":1});
                  var res = db.complete.aggregate(
                      { $match : {"type.key" : "/type/edition"} },

                                                           •
                      { $project : { languages : 1} },
                      { $unwind : "$languages" },           $group
                      { $group : {
                          _id : "$languages.key",
                          qt : { $sum : 1 }
                                                           •$sort
                      }},
                      { $sort : { qt : -1, _id : 1 }}
                  );
                  res.result.forEach(function (r) {
                      print(r.qt+"t"+r._id);
                  });                                      @ramalhoorg
Tuesday, July 17, 12
O que não dá para fazer
       (atualmente)
            • Conjunto limitado de operadores
            • Para lidar com strings, por exemplo:
             • $substr, $toLower, $toUpper, $strcasecmp
             • não tem length, regex, startswith, etc.
            • O framework foi feito para ser extensível
             • Mas não tem uma arquitetura de plug-ins
                                                      @ramalhoorg
Tuesday, July 17, 12
Análise dos dados com
                            Map/Reduce



                                          @ramalhoorg
Tuesday, July 17, 12
O problema do
       “schema after”
           • Conceito: “schema before” x “schema after”
            • Michael Stonebraker (criou Ingres,VoltDB etc):
           • MongoDB é “schema after”
           • Em uma base “schema after” em produção, o
                   esquema real quase nunca é exatamente o
                   planejado

                                                             @ramalhoorg
Tuesday, July 17, 12
Análise profunda
       dos dados
           • Estatísticas sobre a estrutura dos registros
            • para cada tipo de registro, quais campos
                       ocorrem, e em qual frequência
           • Estatísticas sobre estrutura dos campos
            • valores simples, arrays e documentos aninhados
                       (objetos)


                                                            @ramalhoorg
Tuesday, July 17, 12
Map/Reduce: o básico
           • Executado através do método mapReduce:
               db.complete.mapReduce(map, reduce,
                    {out: { inline : 1}, jsMode: true})

           • Função map deve processar cada item (this) e
                   emitir um par de chave: valor
           • Função reduce deve aceitar chave e um array de
                   valores, e devolver apenas um valor agregado

                                                             @ramalhoorg
Tuesday, July 17, 12
Map/Reduce




                       @ramalhoorg
Tuesday, July 17, 12
Map/Reduce
       me lembra
       Pacman
           • Jogador faz reduce
                   dos pontinhos
           • Resultado do reduce
                   é o score


                                   @ramalhoorg
Tuesday, July 17, 12
Exemplo                            284396!
                                          251678!
                                                    subtitle
                                                    subject_place
                                          592707!   lc_classifications
                                          264695!   contributions
                                          605777!   title
                                          604455!   languages

           • Obter lista de todos         475865!
                                          598671!
                                                    subjects
                                                    publish_country
                   os campos e quantas    193955!   series
                   vezes cada um          113818!   title_prefix
                                          605781!   type
                   ocorre nos registros   538357!   by_statement
                   de edition             605781!   revision
                                          600934!   publishers
                                          605781!   last_modified
                                          605781!   key

                                                               @ramalhoorg
Tuesday, July 17, 12
Map
           • Se o registro é do tipo edition, emitir um par de
                   («nome_do_campo», 1) para cada campo


                       var map = function () {
                           if (this.type.key === "/type/edition") {
                               for (field_name in this) {
                                   emit(field_name, 1);
                               }
                           }
                       }


                                                              @ramalhoorg
Tuesday, July 17, 12
Reduce
           • Todos os pares de («chave»,        «valor»)
                   são agrupados em pares pela «chave»:
                   («chave»: [«valor0», «valor1», «valor2»])

           •       A função reduce deve reduzir cada
                   «array_de_valores» a um único valor

               var reduce = function (key, values) {
                   var total = 0;
                   values.forEach(function(n) { total += n; });
                   return total;
               }
                                                         @ramalhoorg
Tuesday, July 17, 12
Executar mapReduce
                       var res = db.complete.mapReduce(map, reduce, {
                           "out": { "inline" : 1},
                           "jsMode": true
                       });

                       //exibir resultado
                       res.results.forEach(function (r) {
                           print(r.value+"t"+r._id);
                       });
                       print("-----");
                       for (var chave in res.counts) {
                           if (chave !== "_id") {
                               print(chave+"t"+res.counts[chave]);
                           }
                       }
                       print("-----");
                       print("tempo (s)t"+res.timeMillis/1000);
                                                              @ramalhoorg
Tuesday, July 17, 12
Resultado de
     mapReduce    • Usando                     {"out":
  > var res = db.complete.mapReduce(map,         { "inline" : 1}}
  ...   reduce, {"out": { "inline" : 1},
  ...           "jsMode": true });
  {                                        [...]
  "results" : [                            !   !   {
  !   !  {                                 !   !   !   "_id" : "works",
  !   !  !   "_id" : "_id",                !   !   !   "value" : 4415
  !   !  !   "value" : 605781              !   !   }
  !   !  },                                !   ],
  !   !  {                                 !   "timeMillis" : 156659,
  !   !  !   "_id" : "authors",            !   "counts" : {
  !   !  !   "value" : 469305              !   !   "input" : 1000000,
  !   !  },                                !   !   "emit" : 13196408,
  !   !  {                                 !   !   "reduce" : 363448,
  !   !  !   "_id" : "by_statement",       !   !   "output" : 61
  !   !  !   "value" : 538357              !   },
  !   !  },                                !   "ok" : 1,
  !   !  {                                 }
  !   !  !   "_id" : "classifications",    real! 2m36.696s
  !   !  !   "value" : 3                   user! 0m0.028s
  !   !  },                                sys!0m0.005s
                                                                     @ramalhoorg
Tuesday, July 17, 12
Executar mapReduce
                       * https://github.com/ramalho/mongosp
  $ mongo2.1 mr_fields.js        210! ! coverimage
  MongoDB shell version:         16! ! isbn_odd_length
                                    !
  2.1.2                          3! ! ! classifications
  connecting to: test            1! ! ! collections
  284396! subtitle               5! ! ! copyright_date
  251678! subject_place          4! ! ! download_url
  592707! lc_classifications     3! ! ! purchase_url
  264695! contributions          1! ! ! language_code
  605777! title                  -----
  604455! languages              input! 1000000
                                       !
  475865! subjects               emit!! 13196408
  598671! publish_country        reduce! 363448
  193955! series                 output! 61
  113818! title_prefix           -----
  605781! type                   tempo (s)! 102.13 @ramalhoorg
Tuesday, July 17, 12
$ mongo2.1 mr_fieldtypes_sort.js
                                MongoDB shell version: 2.1.2

       Campos                   connecting to: test
                                _id:string!
                                          605781
                                authors:array! 469305

       e tipos                  by_statement:string! 538357
                                classifications:object!3
                                collections:array!1
                                contributions:array! 264695
                                copyright_date:string! 5
      • Identificar tipo         coverimage:string!210
                                covers:array!3648
              do dado em        created:object! 10086
              cada ocorrência   description:object! 33040
                                dewey_decimal_class:array!325519
      • Detectar                download_url:array! 4
                                edition_name:string! 124615
              inconsistências   first_sentence:object! 682
                                first_sentence:string! 2

                            * https://github.com/ramalho/mongosp
                                                          @ramalhoorg
Tuesday, July 17, 12
Refatorando o esquema
                    para o MongoDB



                                    @ramalhoorg
Tuesday, July 17, 12
{
                                 "subtitle": "Ausbau und Planung der petrochemischen und energieintensiven
                               Industrien zum Zeitpunkt des zweiten Golfkriegs",




       Um registro
                                 "subject_place": [
                                    "Middle East."
                                 ],
                                 "lc_classifications": [
                                    "HD9579.C33 M6284 1991"
                                 ],
                                 "contributions": [
                                    "Helmschrott, Helmut."
                                 ],
                                 "title": "Industrialisierung der arabischen OPEC-Lau0308nder und des Iran",
                                 "languages": [
                                    {
                                      "key": "/languages/ger"
                                    }
                                 ],
                                 "subjects": [
                                    "Petroleum chemicals industry -- Middle East.",
                                    "Petroleum industry and trade -- Middle East.",
                                    "Gas industry -- Middle East."
                                 ],
                                 "publish_country": "gw ",
                                 "series": [
                                    "Ifo Forschungsberichte der Abteilung Entwicklungslau0308nder ;",
                                    "Nr. 74",
                                    "Ifo Forschungsberichte der Abteilung Entwicklungslau0308nder ;",
                                    "74."
                                 ],
                                 "title_prefix": "Die ",
                                 "type": {
                                    "key": "/type/edition"
                                 },




           • 25 campos neste
                                 "by_statement": "von Axel J. Halbach, Helmut Helmschrott.",
                                 "revision": 1,
                                 "publishers": [
                                    "Ifo Institut fuu0308r Wirtschaftsforschung",
                                    "Weltforum Verlag"
                                 ],
                                 "last_modified": {



                   registro
                                    "type": "/type/datetime",
                                    "value": "2008-04-01T03:28:50.625462"
                                 },
                                 "key": "/books/OL1656964M",
                                 "authors": [
                                    {
                                      "key": "/authors/OL45038A"
                                    }
                                 ],
                                 "publish_places": [
                                    "Muu0308nchen"
                                 ],
                                 "pagination": "viii, 270 p. :",
                                 "lccn": [
                                    "91218377"
                                 ],
                                 "notes": {
                                    "type": "/type/text",
                                    "value": "Includes bibliographical references (p. 268-270)."
                                 },
                                 "number_of_pages": 270,
                                 "isbn_10": [
                                    "3803903955"
                                 ],
                                 "publish_date": "1991",
                                 "_id": "/books/OL1656964M-1"
                               }


                                                                                       @ramalhoorg
Tuesday, July 17, 12
Chave estrangeira
                       "title": "Industrialisierung der arabischen...",
                       "revision": 1,
                       "publishers": [
                          "Ifo Institut fuu0308r Wirtschaftsforschung",
                          "Weltforum Verlag"
                       ],
                       "last_modified": {
                          "type": "/type/datetime",
                          "value": "2008-04-01T03:28:50.625462"
                       },
                       "key": "/books/OL1656964M",
                       "authors": [
                          {
                            "key": "/authors/OL45038A"
                          }
                       ],
                       "publish_places": [
                          "Muu0308nchen"
                       ],
                                                              @ramalhoorg
Tuesday, July 17, 12
Refatoração do esquema
           • Usar key+revision como chave primária _id
           • Manter campos key e revision separados
            • Para fazer pseudo-auto join recuperando o
                       histórico de um registro bibliográfico
           • Embutir (embed) campo nome do autor no
                   documento
                                              "authors": [
                                                 {
                                                   "key": "/authors/OL45038A",
                                                   "name": "W. A. Mozart"
                                                 }
                                              ],                     @ramalhoorg
Tuesday, July 17, 12
Representação do
       histórico de versões
           • Embutir pode ser uma boa opção para os tipos de
                   registros que são raramente atualizados
                  • Versões antigas embutidas
           • Para registros que sofrem muitas atualizações, a
                   melhor opção é uma sequência de referências
                   (“chaves estrangeiras”)
                  • Um “pseudo self-join” pode ser feito pelo
                       atributo key para recuperar o histórico
                                                                 @ramalhoorg
Tuesday, July 17, 12
Integridade referencial
           • Identificação de problemas atuais
           • Ferramentas de suporte
            • Índices
            • Uso de um framework com ODM (object-
                       document mapper)
                  • Tarefas de monitoração assíncrona
                                                        @ramalhoorg
Tuesday, July 17, 12
Algumas dicas
           • Todo registro deve ter campos identificando:
            • seu tipo
            • a versão do esquema usada naquele registro
           • Mudanças no esquema podem ser feitas de modo
                   incremental, quando um documento é alterado
           • Use um ODM (Object-Document Mapper) para
                   aumentar a consistência dos dados armazenados

                                                           @ramalhoorg
Tuesday, July 17, 12
Tuesday, July 17, 12
Excelente opção para
                         hospedagem de MongoDB.
                        Pequenas instâncias gratuitas,
                       instâncias maiores por preços
                        acessíveis, sem você precisar
                        gerenciar o servidor, sistema
                          operacional, storage etc.
Tuesday, July 17, 12

Mais conteúdo relacionado

Mais procurados (6)

MongoDB: Uma forma diferente de pensar no desenvolvimento
MongoDB: Uma forma diferente de pensar no desenvolvimento MongoDB: Uma forma diferente de pensar no desenvolvimento
MongoDB: Uma forma diferente de pensar no desenvolvimento
 
Mongo + php
Mongo + phpMongo + php
Mongo + php
 
Minicurso Epoca mongoDB
Minicurso Epoca mongoDBMinicurso Epoca mongoDB
Minicurso Epoca mongoDB
 
Nosql e BD Orientados a Documentos
Nosql e BD Orientados a DocumentosNosql e BD Orientados a Documentos
Nosql e BD Orientados a Documentos
 
Modelando aplicação em documento - MongoDB
Modelando aplicação em documento - MongoDBModelando aplicação em documento - MongoDB
Modelando aplicação em documento - MongoDB
 
No sql e as vantagens na utilização do mongodb
No sql e as vantagens na utilização do mongodbNo sql e as vantagens na utilização do mongodb
No sql e as vantagens na utilização do mongodb
 

Destaque (7)

Python para quem sabe Python (aula 2)
Python para quem sabe Python (aula 2)Python para quem sabe Python (aula 2)
Python para quem sabe Python (aula 2)
 
Iteráveis e geradores (versão RuPy)
Iteráveis e geradores (versão RuPy)Iteráveis e geradores (versão RuPy)
Iteráveis e geradores (versão RuPy)
 
Objetos Pythonicos - compacto
Objetos Pythonicos - compactoObjetos Pythonicos - compacto
Objetos Pythonicos - compacto
 
Modelos ricos
Modelos ricosModelos ricos
Modelos ricos
 
Encapsulamento com Descritores em Python
Encapsulamento com Descritores em PythonEncapsulamento com Descritores em Python
Encapsulamento com Descritores em Python
 
JavaScript: agora é sério
JavaScript: agora é sérioJavaScript: agora é sério
JavaScript: agora é sério
 
Wiki-wiki S/A
Wiki-wiki S/AWiki-wiki S/A
Wiki-wiki S/A
 

Semelhante a Open Library no Mongodb

MongoDB - Apresentação
MongoDB - ApresentaçãoMongoDB - Apresentação
MongoDB - Apresentação
Terra / Neo
 
Estudo de técnicas de persistência e acesso concorrente a ontologias
Estudo de técnicas de persistência e acesso concorrente a ontologiasEstudo de técnicas de persistência e acesso concorrente a ontologias
Estudo de técnicas de persistência e acesso concorrente a ontologias
Helio Henrique L. C. Monte-Alto
 
Uma implementação de suporte a
Uma implementação de suporte a Uma implementação de suporte a
Uma implementação de suporte a
Rômulo Jales
 

Semelhante a Open Library no Mongodb (20)

Utilizando NoSQL no desenvolvimento de soluções inteligentes
Utilizando NoSQL no desenvolvimento de soluções inteligentesUtilizando NoSQL no desenvolvimento de soluções inteligentes
Utilizando NoSQL no desenvolvimento de soluções inteligentes
 
MongoDB na Campus Party
MongoDB na Campus PartyMongoDB na Campus Party
MongoDB na Campus Party
 
Mongo db
Mongo dbMongo db
Mongo db
 
Palestra nosql
Palestra nosqlPalestra nosql
Palestra nosql
 
Python e MongoDB - Ensol
Python e MongoDB - EnsolPython e MongoDB - Ensol
Python e MongoDB - Ensol
 
PostgreSQL-Prático.pdf
PostgreSQL-Prático.pdfPostgreSQL-Prático.pdf
PostgreSQL-Prático.pdf
 
Big data para programadores convencionais
Big data para programadores convencionaisBig data para programadores convencionais
Big data para programadores convencionais
 
Mongodb: agregação
Mongodb: agregaçãoMongodb: agregação
Mongodb: agregação
 
Bancos de dados NoSQL
Bancos de dados NoSQLBancos de dados NoSQL
Bancos de dados NoSQL
 
Mongo Db - PHP Day Workshop
Mongo Db - PHP Day WorkshopMongo Db - PHP Day Workshop
Mongo Db - PHP Day Workshop
 
Mongodb praquer-usar-uaijugcloudday2014
Mongodb praquer-usar-uaijugcloudday2014Mongodb praquer-usar-uaijugcloudday2014
Mongodb praquer-usar-uaijugcloudday2014
 
MongoDB Aggregation Framework
MongoDB Aggregation FrameworkMongoDB Aggregation Framework
MongoDB Aggregation Framework
 
Palestra Desenvolvimento Ágil para Web com ROR UVA
Palestra Desenvolvimento Ágil para Web com ROR UVAPalestra Desenvolvimento Ágil para Web com ROR UVA
Palestra Desenvolvimento Ágil para Web com ROR UVA
 
MongoDB com Java - SouJava
MongoDB com Java - SouJavaMongoDB com Java - SouJava
MongoDB com Java - SouJava
 
MongoDB - Apresentação
MongoDB - ApresentaçãoMongoDB - Apresentação
MongoDB - Apresentação
 
Fazendo barba, cabelo e bigode com REDIS
Fazendo barba, cabelo e bigode com REDISFazendo barba, cabelo e bigode com REDIS
Fazendo barba, cabelo e bigode com REDIS
 
Fazendo barba, cabelo e bigode com REDIS
Fazendo barba, cabelo e bigode com REDISFazendo barba, cabelo e bigode com REDIS
Fazendo barba, cabelo e bigode com REDIS
 
Estudo de técnicas de persistência e acesso concorrente a ontologias
Estudo de técnicas de persistência e acesso concorrente a ontologiasEstudo de técnicas de persistência e acesso concorrente a ontologias
Estudo de técnicas de persistência e acesso concorrente a ontologias
 
Ruby on Rails + MongoDB - GURU Sorocaba
Ruby on Rails + MongoDB - GURU SorocabaRuby on Rails + MongoDB - GURU Sorocaba
Ruby on Rails + MongoDB - GURU Sorocaba
 
Uma implementação de suporte a
Uma implementação de suporte a Uma implementação de suporte a
Uma implementação de suporte a
 

Mais de Luciano Ramalho

Encapsulamento com descritores
Encapsulamento com descritoresEncapsulamento com descritores
Encapsulamento com descritores
Luciano Ramalho
 
Python: Iteraveis, geradores etc
Python: Iteraveis, geradores etcPython: Iteraveis, geradores etc
Python: Iteraveis, geradores etc
Luciano Ramalho
 
JavaScript agora é sério (TDC 2011)
JavaScript agora é sério (TDC 2011)JavaScript agora é sério (TDC 2011)
JavaScript agora é sério (TDC 2011)
Luciano Ramalho
 
JavaScript agora é sério (FISL 2011)
JavaScript agora é sério (FISL 2011)JavaScript agora é sério (FISL 2011)
JavaScript agora é sério (FISL 2011)
Luciano Ramalho
 

Mais de Luciano Ramalho (20)

Introdução a linguagem Python
Introdução a linguagem PythonIntrodução a linguagem Python
Introdução a linguagem Python
 
Orientação a objetos em Python (compacto)
Orientação a objetos em Python (compacto)Orientação a objetos em Python (compacto)
Orientação a objetos em Python (compacto)
 
Encapsulamento com descritores
Encapsulamento com descritoresEncapsulamento com descritores
Encapsulamento com descritores
 
Iteraveis e geradores
Iteraveis e geradoresIteraveis e geradores
Iteraveis e geradores
 
Arduino: hardware hacking & coding dojo
Arduino: hardware hacking & coding dojoArduino: hardware hacking & coding dojo
Arduino: hardware hacking & coding dojo
 
Iteraveis e geradores em Python
Iteraveis e geradores em PythonIteraveis e geradores em Python
Iteraveis e geradores em Python
 
Dojo com Processing
Dojo com ProcessingDojo com Processing
Dojo com Processing
 
Dojo com Arduino
Dojo com ArduinoDojo com Arduino
Dojo com Arduino
 
Python: Iteraveis, geradores etc
Python: Iteraveis, geradores etcPython: Iteraveis, geradores etc
Python: Iteraveis, geradores etc
 
Jython no JavaOne Latin America 2011
Jython no JavaOne Latin America 2011Jython no JavaOne Latin America 2011
Jython no JavaOne Latin America 2011
 
OO em Python sem sotaque
OO em Python sem sotaqueOO em Python sem sotaque
OO em Python sem sotaque
 
Python, a arma secreta do Google
Python, a arma secreta do GooglePython, a arma secreta do Google
Python, a arma secreta do Google
 
Ensinando OO com Python
Ensinando OO com PythonEnsinando OO com Python
Ensinando OO com Python
 
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design PatternsAlex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
 
Dspace em 5 minutos
Dspace em 5 minutosDspace em 5 minutos
Dspace em 5 minutos
 
JavaScript agora é sério (TDC 2011)
JavaScript agora é sério (TDC 2011)JavaScript agora é sério (TDC 2011)
JavaScript agora é sério (TDC 2011)
 
JavaScript agora é sério (FISL 2011)
JavaScript agora é sério (FISL 2011)JavaScript agora é sério (FISL 2011)
JavaScript agora é sério (FISL 2011)
 
Wiki sa-v2
Wiki sa-v2Wiki sa-v2
Wiki sa-v2
 
Porque bibliotecários usam bancos de dados esquisitos
Porque bibliotecários usam bancos de dados esquisitosPorque bibliotecários usam bancos de dados esquisitos
Porque bibliotecários usam bancos de dados esquisitos
 
Binary divination
Binary divinationBinary divination
Binary divination
 

Open Library no Mongodb

  • 1. Luciano Ramalho luciano@ramalho.org @ramalhoorg Open Library no MongoDB Usando Map/Reduce e o Aggregation Framework para análise e modelagem de dados Tuesday, July 17, 12
  • 2. Temas • Sobre o projeto Open Library • Conversão e importação da massa de dados • Análise dos dados com o framework de agregação • Análise dos dados com Map /Reduce • Refatoração do modelo de dados para o MongoDB • Encerramento @ramalhoorg Tuesday, July 17, 12
  • 3. Sobre o projeto Open Library @ramalhoorg Tuesday, July 17, 12
  • 4. Sobre a Open Library • Missão: “One web page for every book” • Um projeto do Internet Archive • 117.439.126 registros bibliográficos em jun/2012 • Mais de 1.000.000 de e-books gratuitos para baixar (livres, CC, domínio público etc.) @ramalhoorg Tuesday, July 17, 12
  • 5. A Tecnologia da Open Library • Infobase: uma API Python para bases de dados semi-estruturadas sobre tabelas normalizadas • também conhecida como ThingDB • Inclui versionamento de registros • Muitos join para recuperar uma entidade conceitual • Fortemente depenente do SOLR/Lucene para exibir suas páginas @ramalhoorg Tuesday, July 17, 12
  • 6. Modelo de dados semi-estruturado • Base teórica existe! • Palavras-chave para pesquisa: semistructured ou semi-structured database “The semi­structured data model is designed as an evolution of the relational data model that allows the representation of data with a flexible structure. ” SUCIU, Dan. Semi­Structured Data Model. In: LIU, L. Encyclopedia of Database Systems @ramalhoorg Tuesday, July 17, 12
  • 7. Data on the Web (1999) • From Relations to Semistructured Data and XML • Autores: Abiteboul, Buneman & Suciu • Notação apresentada: semelhante a JSON @ramalhoorg Tuesday, July 17, 12
  • 8. Semistructured Database Design (2004) • Autores: Ling, Lee & Dobbie • Algoritmos de normalização sem a 1ª Forma Normal (N1NF = Non First Normal Form) @ramalhoorg Tuesday, July 17, 12
  • 9. Conversão e importação da massa de dados @ramalhoorg Tuesday, July 17, 12
  • 10. Massa de dados • OL Complete Dump: ol_cdump_latest.txt.gz* • 118.598.056 linhas em 1/jun/2012 • 16 GB comprimidos (.gz), 91 GB sem compressão • 32 tipos diferentes de registros • 1.158.930 (~1%) não são registros bibliográficos • Inclui todas as revisões de todos os registros * http://openlibrary.org/developers/dumps @ramalhoorg Tuesday, July 17, 12
  • 11. Converter para carregar • Escolha de uma chave primária (campo _id) • Chave composta: key+"-"+revision • /books/OL1656964M-1 • Opção adotada: a conversão mais simples possível • Usar JSON do dump, acrescido de campo _id @ramalhoorg Tuesday, July 17, 12
  • 12. Carga: conversor_ol.py import sys import json import io def conv_linha(lin, indent=None): rec_type, rec_key, rec_revision, rec_modified, rec_json = lin.split(u't') rec = json.loads(rec_json) rec[u'_id'] = rec_key + u'-' + rec_revision return json.dumps(rec, indent=indent) def conv_arquivo(nome_arq, max_lin=sys.maxsize, indent=None): with io.open(nome_arq, encoding='utf-8') as arq: for num_lin, lin in enumerate(arq, 1): if not lin.strip(): continue saida = conv_linha(lin, indent) print saida.encode('utf-8') if num_lin >= max_lin: break if __name__=='__main__': if len(sys.argv) == 2: converte_arquivo(sys.argv[1]) else: print 'Modo de usar: %s <ol_dump_file>' % __name__ * https://github.com/ramalho/mongosp @ramalhoorg Tuesday, July 17, 12
  • 13. Usando mongoimport python conversor_ol.py $1 | mongoimport -d openlibrary -c complete --stopOnError • -d: database • -c: collection • --stopOnError: interromper se houver erro • --upsert: sobrescrever ao importar _id duplicado (default: ignorar o novo registro) • --file: arquivo a inserir (default: stdin) @ramalhoorg Tuesday, July 17, 12
  • 14. Análise dos dados usando o framework de agregação @ramalhoorg Tuesday, July 17, 12
  • 15. Indexação para análise • Criar índices esparsos para: • key • revision • type • outros... @ramalhoorg Tuesday, July 17, 12
  • 16. Aggregation Framework: o básico • Novidade no MongoDB 2.1/2.2 • Alternativa ao Map/Reduce • Mais fácil de usar • Melhor desempenho • implementado em C++, usa threads (Map/Reduce depende do interpretador JavaScript Spidermonkey, mono-thread) @ramalhoorg Tuesday, July 17, 12
  • 17. Exemplo: group_types.js db = db.getMongo().getDB('openlibrary'); db.complete.ensureIndex({"type.key":1}); var res = db.complete.aggregate( { "$group" : { ! "_id" : "$type.key", }}, ! "qt" : { "$sum" : 1 } • $group ); { "$sort" : { "qt" : -1 }} • $sort res.result.forEach(function (r) { print(r.qt+"t"+r._id); }); * https://github.com/ramalho/mongosp @ramalhoorg Tuesday, July 17, 12
  • 18. Exemplo: group_types.js $ time mongo2.1 • O primeiro lote group_types.js MongoDB shell version: 2.1.2 de 1.000.000 de connecting to: test 605781! /type/edition registros tem 9 382428! /type/author tipos diferentes 9211!/type/work 1935!/type/redirect • Os três primeiros 623! /type/delete 7! /type/template são os mais 7! /type/page importantes: 5! /type/doc edition, author, 3! /type/macro work real!0m23.658s user!0m0.030s sys! 0m0.004s @ramalhoorg Tuesday, July 17, 12
  • 19. Agregação em estágios • Estágios: etapas em um fluxo (steps in a pipeline) • Estágios são executados em ordem, na ordem dos parâmetros da invocação de mapReduce • Cada estágio aplica um operador especial • O mesmo operador pode ser usado várias vezes em estágios diferentes @ramalhoorg Tuesday, July 17, 12
  • 20. Operadores de estágios • $match • $group • $project • $sort • $limit • $unwind • $skip @ramalhoorg Tuesday, July 17, 12
  • 21. Exemplo 2a * https://github.com/ramalho/mongosp var res = db.complete.aggregate( { $match : {"type.key" : "/type/edition"} }, { $project : { languages : 1} }, { $unwind : "$languages" }, { $group : { _id : "$languages.key", • $match }}, qt : { $sum : 1 } • $project ); { $sort : { qt : -1, _id : 1 }} • $unwind • $group • $sort @ramalhoorg Tuesday, July 17, 12
  • 22. Exemplo 2b * https://github.com/ramalho/mongosp db = db.getMongo().getDB('openlibrary'); db.complete.ensureIndex({"revision":1}); var res = db.complete.aggregate( { $match : {"type.key" : "/type/edition"} }, • { $project : { languages : 1} }, { $unwind : "$languages" }, $group { $group : { _id : "$languages.key", qt : { $sum : 1 } •$sort }}, { $sort : { qt : -1, _id : 1 }} ); res.result.forEach(function (r) { print(r.qt+"t"+r._id); }); @ramalhoorg Tuesday, July 17, 12
  • 23. O que não dá para fazer (atualmente) • Conjunto limitado de operadores • Para lidar com strings, por exemplo: • $substr, $toLower, $toUpper, $strcasecmp • não tem length, regex, startswith, etc. • O framework foi feito para ser extensível • Mas não tem uma arquitetura de plug-ins @ramalhoorg Tuesday, July 17, 12
  • 24. Análise dos dados com Map/Reduce @ramalhoorg Tuesday, July 17, 12
  • 25. O problema do “schema after” • Conceito: “schema before” x “schema after” • Michael Stonebraker (criou Ingres,VoltDB etc): • MongoDB é “schema after” • Em uma base “schema after” em produção, o esquema real quase nunca é exatamente o planejado @ramalhoorg Tuesday, July 17, 12
  • 26. Análise profunda dos dados • Estatísticas sobre a estrutura dos registros • para cada tipo de registro, quais campos ocorrem, e em qual frequência • Estatísticas sobre estrutura dos campos • valores simples, arrays e documentos aninhados (objetos) @ramalhoorg Tuesday, July 17, 12
  • 27. Map/Reduce: o básico • Executado através do método mapReduce: db.complete.mapReduce(map, reduce, {out: { inline : 1}, jsMode: true}) • Função map deve processar cada item (this) e emitir um par de chave: valor • Função reduce deve aceitar chave e um array de valores, e devolver apenas um valor agregado @ramalhoorg Tuesday, July 17, 12
  • 28. Map/Reduce @ramalhoorg Tuesday, July 17, 12
  • 29. Map/Reduce me lembra Pacman • Jogador faz reduce dos pontinhos • Resultado do reduce é o score @ramalhoorg Tuesday, July 17, 12
  • 30. Exemplo 284396! 251678! subtitle subject_place 592707! lc_classifications 264695! contributions 605777! title 604455! languages • Obter lista de todos 475865! 598671! subjects publish_country os campos e quantas 193955! series vezes cada um 113818! title_prefix 605781! type ocorre nos registros 538357! by_statement de edition 605781! revision 600934! publishers 605781! last_modified 605781! key @ramalhoorg Tuesday, July 17, 12
  • 31. Map • Se o registro é do tipo edition, emitir um par de («nome_do_campo», 1) para cada campo var map = function () { if (this.type.key === "/type/edition") { for (field_name in this) { emit(field_name, 1); } } } @ramalhoorg Tuesday, July 17, 12
  • 32. Reduce • Todos os pares de («chave», «valor») são agrupados em pares pela «chave»: («chave»: [«valor0», «valor1», «valor2»]) • A função reduce deve reduzir cada «array_de_valores» a um único valor var reduce = function (key, values) { var total = 0; values.forEach(function(n) { total += n; }); return total; } @ramalhoorg Tuesday, July 17, 12
  • 33. Executar mapReduce var res = db.complete.mapReduce(map, reduce, { "out": { "inline" : 1}, "jsMode": true }); //exibir resultado res.results.forEach(function (r) { print(r.value+"t"+r._id); }); print("-----"); for (var chave in res.counts) { if (chave !== "_id") { print(chave+"t"+res.counts[chave]); } } print("-----"); print("tempo (s)t"+res.timeMillis/1000); @ramalhoorg Tuesday, July 17, 12
  • 34. Resultado de mapReduce • Usando {"out": > var res = db.complete.mapReduce(map, { "inline" : 1}} ... reduce, {"out": { "inline" : 1}, ... "jsMode": true }); { [...] "results" : [ ! ! { ! ! { ! ! ! "_id" : "works", ! ! ! "_id" : "_id", ! ! ! "value" : 4415 ! ! ! "value" : 605781 ! ! } ! ! }, ! ], ! ! { ! "timeMillis" : 156659, ! ! ! "_id" : "authors", ! "counts" : { ! ! ! "value" : 469305 ! ! "input" : 1000000, ! ! }, ! ! "emit" : 13196408, ! ! { ! ! "reduce" : 363448, ! ! ! "_id" : "by_statement", ! ! "output" : 61 ! ! ! "value" : 538357 ! }, ! ! }, ! "ok" : 1, ! ! { } ! ! ! "_id" : "classifications", real! 2m36.696s ! ! ! "value" : 3 user! 0m0.028s ! ! }, sys!0m0.005s @ramalhoorg Tuesday, July 17, 12
  • 35. Executar mapReduce * https://github.com/ramalho/mongosp $ mongo2.1 mr_fields.js 210! ! coverimage MongoDB shell version: 16! ! isbn_odd_length ! 2.1.2 3! ! ! classifications connecting to: test 1! ! ! collections 284396! subtitle 5! ! ! copyright_date 251678! subject_place 4! ! ! download_url 592707! lc_classifications 3! ! ! purchase_url 264695! contributions 1! ! ! language_code 605777! title ----- 604455! languages input! 1000000 ! 475865! subjects emit!! 13196408 598671! publish_country reduce! 363448 193955! series output! 61 113818! title_prefix ----- 605781! type tempo (s)! 102.13 @ramalhoorg Tuesday, July 17, 12
  • 36. $ mongo2.1 mr_fieldtypes_sort.js MongoDB shell version: 2.1.2 Campos connecting to: test _id:string! 605781 authors:array! 469305 e tipos by_statement:string! 538357 classifications:object!3 collections:array!1 contributions:array! 264695 copyright_date:string! 5 • Identificar tipo coverimage:string!210 covers:array!3648 do dado em created:object! 10086 cada ocorrência description:object! 33040 dewey_decimal_class:array!325519 • Detectar download_url:array! 4 edition_name:string! 124615 inconsistências first_sentence:object! 682 first_sentence:string! 2 * https://github.com/ramalho/mongosp @ramalhoorg Tuesday, July 17, 12
  • 37. Refatorando o esquema para o MongoDB @ramalhoorg Tuesday, July 17, 12
  • 38. { "subtitle": "Ausbau und Planung der petrochemischen und energieintensiven Industrien zum Zeitpunkt des zweiten Golfkriegs", Um registro "subject_place": [ "Middle East." ], "lc_classifications": [ "HD9579.C33 M6284 1991" ], "contributions": [ "Helmschrott, Helmut." ], "title": "Industrialisierung der arabischen OPEC-Lau0308nder und des Iran", "languages": [ { "key": "/languages/ger" } ], "subjects": [ "Petroleum chemicals industry -- Middle East.", "Petroleum industry and trade -- Middle East.", "Gas industry -- Middle East." ], "publish_country": "gw ", "series": [ "Ifo Forschungsberichte der Abteilung Entwicklungslau0308nder ;", "Nr. 74", "Ifo Forschungsberichte der Abteilung Entwicklungslau0308nder ;", "74." ], "title_prefix": "Die ", "type": { "key": "/type/edition" }, • 25 campos neste "by_statement": "von Axel J. Halbach, Helmut Helmschrott.", "revision": 1, "publishers": [ "Ifo Institut fuu0308r Wirtschaftsforschung", "Weltforum Verlag" ], "last_modified": { registro "type": "/type/datetime", "value": "2008-04-01T03:28:50.625462" }, "key": "/books/OL1656964M", "authors": [ { "key": "/authors/OL45038A" } ], "publish_places": [ "Muu0308nchen" ], "pagination": "viii, 270 p. :", "lccn": [ "91218377" ], "notes": { "type": "/type/text", "value": "Includes bibliographical references (p. 268-270)." }, "number_of_pages": 270, "isbn_10": [ "3803903955" ], "publish_date": "1991", "_id": "/books/OL1656964M-1" } @ramalhoorg Tuesday, July 17, 12
  • 39. Chave estrangeira "title": "Industrialisierung der arabischen...", "revision": 1, "publishers": [ "Ifo Institut fuu0308r Wirtschaftsforschung", "Weltforum Verlag" ], "last_modified": { "type": "/type/datetime", "value": "2008-04-01T03:28:50.625462" }, "key": "/books/OL1656964M", "authors": [ { "key": "/authors/OL45038A" } ], "publish_places": [ "Muu0308nchen" ], @ramalhoorg Tuesday, July 17, 12
  • 40. Refatoração do esquema • Usar key+revision como chave primária _id • Manter campos key e revision separados • Para fazer pseudo-auto join recuperando o histórico de um registro bibliográfico • Embutir (embed) campo nome do autor no documento "authors": [ { "key": "/authors/OL45038A", "name": "W. A. Mozart" } ], @ramalhoorg Tuesday, July 17, 12
  • 41. Representação do histórico de versões • Embutir pode ser uma boa opção para os tipos de registros que são raramente atualizados • Versões antigas embutidas • Para registros que sofrem muitas atualizações, a melhor opção é uma sequência de referências (“chaves estrangeiras”) • Um “pseudo self-join” pode ser feito pelo atributo key para recuperar o histórico @ramalhoorg Tuesday, July 17, 12
  • 42. Integridade referencial • Identificação de problemas atuais • Ferramentas de suporte • Índices • Uso de um framework com ODM (object- document mapper) • Tarefas de monitoração assíncrona @ramalhoorg Tuesday, July 17, 12
  • 43. Algumas dicas • Todo registro deve ter campos identificando: • seu tipo • a versão do esquema usada naquele registro • Mudanças no esquema podem ser feitas de modo incremental, quando um documento é alterado • Use um ODM (Object-Document Mapper) para aumentar a consistência dos dados armazenados @ramalhoorg Tuesday, July 17, 12
  • 45. Excelente opção para hospedagem de MongoDB. Pequenas instâncias gratuitas, instâncias maiores por preços acessíveis, sem você precisar gerenciar o servidor, sistema operacional, storage etc. Tuesday, July 17, 12