Laboratorul 11 - MongoDB II

Obiective

  • Indexare
  • Funcții
  • Agregarea datelor

Indexare

MongoDB suport diferite tipuri de indecși. Indecși sunt utilizați pentru a crește performanțele operațiilor de căutare. Indecși sunt creați la nivel de colecție. Pentru a crea un index se folosește comanda createIndex(). La creare se specifică numele câmpului (i.e., label) și modul de ordonare a indexului (i.e., order)

  • Indecși simpli db.collection.createIndex({“label”: order})
  • Indecși compusi db.collection.createIndex({“label_1”: order_1, “label_2”: order_2, …})
  • Indecși pe documente imbricate: db.collection.createIndex({“label_1.nested_label”: order_1, “label_2.nested_label”: order_2, …})
  • Indecși geo-spațiali db.collection.createIndex({“label_1.nested_label”: “2d”})
  • Indecși textuali (o colecție poate să aibă un singur index textual, dar acesta poate fi compus)db.collection.createIndex({“label_1”: “text”, “label_2”: “text”, …})
  • Indecși hashed (utili pentru sharding): db.collection.createIndex({“label”: “hashed”})

Pentru următoarele exemple să se importe documentele din fișierul bd2_mongo care conține baza de date în format JSON. Noua bază de date se va numi BD2 și colecția se va numi documents.

Ex. 1. Analizați schema documentelor și înțelegeți structura

db.documents.createIndex({author: 1})
db.documents.createIndex({gender: 1, age: 1})
db.documents.createIndex({"words.word": 1})
db.documents.createIndex({"geoLocation": "2d"})
db.documents.createIndex({"lemmaText": "text"}) 
db.documents.createIndex({"date": "hashed"})

Ex. 2. Descrieți tipul indecșilor construiți anterior.

Pentru a vedea toți indecși se folosește comanda db.collection.getIndexes()

Pentru a șterge un index se folosește comanda db.collection.dropIndexes(“index_name”)

Pentru a șterge toți indecși (cu excepția indexului de pe cheia primară) se folosește comanda db.collection.dropIndexes()

Utilizare indecși geo-spațiali

  • Pentru a găsi documentele de lângă un punct p=[x, y] se folosește $near
  • Pentru a găsi documentele care se găsesc în diferite figuri geometrice se folosește $within:
    • Pentru un cerc cu centrul într-un punct p=[x, y] și o rază r se folosește $center
    • Pentru un dreptunghi definit prin punctele din stânga jos și dreapta sus se folosește $box
    • Pentru un poligon dat de o listă puncte se folosește $polygon
db.documents.find( { geoLocation: { $near: [25, 25] } }, {geoLocation: 1} )
db.documents.find( { geoLocation: { $within: { $center: [[25, 10], 3] } } }, {geoLocation: 1} )
db.documents.find( { geoLocation: { $within: { $box: [[25, 40], [30, 45]] } } }, { geoLocation: 1 } )
db.documents.find( { geoLocation: { $within: { $polygon: [[20, 40], [40, 50], [30, 30]] } } },  { geoLocation: 1 } )

Utilizare indecși textuali

Pentur a utiliza un index textual se folosește următoare sintaxă:

{
  $text:
    {
      $search: <string>,
      $language: <string>,
      $caseSensitive: <boolean>,
      $diacriticSensitive: <boolean>
    }
}

Unde

  • $search - este șirul de cuvinte căutat sau fraza căutată
  • $language - este limba pentru cuvintele căutate
  • $caseSensitive - dacă se caută case sensitive sau nu
  • $diacriticSensitive - dacă se ține cont de diacritice sau nu
# Caută un cuvânt
db.documents.find( { $text: { $search: "coffee", $language: "english", $caseSensitive: false, $diacriticSensitive: false } } ,  { lemmaText: 1 } )
 
# Caută mai multe cuvinte (se folosește operatorul or)
db.documents.find( { $text: { $search: "coffee cup", $language: "english", $caseSensitive: false, $diacriticSensitive: false } } ,  { lemmaText: 1 } )
 
# Caută o frază
db.documents.find( { $text: { $search: "\"heaven tonight\"", $language: "english", $caseSensitive: false, $diacriticSensitive: false } } ,  { lemmaText: 1 } )
 
# Caută o frază cu un scor de relevanță
db.documents.find( { $text: { $search: "\"heaven tonight\"", $language: "english", $caseSensitive: false, $diacriticSensitive: false } } ,  { score: { $meta: "textScore" }, lemmaText: 1, _id: 0})

Ex. 3. Să se găsească toate documentele care se află într-un dreptunghi dat de punctele [20, -100] și [40, 90], care să conțină cuvintele tech și engineering. Cererea să se folosească de indexul textual. Afișeți câmpul rawText. Să se refacă cererea utilizând alt câmp din document.

Funcții

MongoDB permite dezvoltatorilor sa scrie funcții folosind limbajul JavaScript.

Ex. 4. Să se scrie o funcție care primește un query pentru filtrare și împarte lemmaText în cuvinte. Funcția va întoarce un vector.

tokenization = function(q){
    var cursor = db.documents.find(q,{"_id": 0, lemmaText: 1});
    var tokens = Array();
    cursor.forEach(function(elem){
        tokens = tokens.concat(elem["lemmaText"].split(" "));
    });
    return tokens;
}
 
// utilizate
var q = {gender: "male"}
tokens = tokenization(q)

Ex. 5. Să se scrie o funcție numită countWords care primește un query pentru filtrare și numără aparițiile unui cuvânt. Funcția va întoarce un obiect de forma {word_1: count, word_2: count, …}. Folosiți funcția tokenization.

Funcții stocate

Funcțiile pot fi stocate la nivelul MongoDB. Pentru acest lucru se folosește o colecție specială numită system.js. Stocarea se face cu comanda: db.system.js.save(_id: “function_name”, value: “function_body”). Pentru a lucra cu funcțiile stocare (a le încărca în sesiune) se folosește comanda db.loadServerScripts().

db.system.js.save(
   {
     _id: "tokenization",
     value : function(q){
                var cursor = db.documents.find(q,{"_id": 0, lemmaText: 1});
                var tokens = Array();
                cursor.forEach(function(elem){
                    tokens = tokens.concat(elem["lemmaText"].split(" "));
                });
                return tokens;
            }
   }
)
 
db.loadServerScripts()

Ex. 6. Salvați și apoi încărcați în sesiune funcția countWords.

Agregarea datelor

În MongoDB putem să agregăm datele folosind mai multe metode:

  • Funcții de agregare
  • Modulul nativ de Aggregation Pipeline
  • MapReduce

Funcții de agregare

MongoDB oferă utilizatorilor două funcții pentru agregare:

1. Count: db.collection.count(query)

// Cate documente au lungimea textului lematizat 10
db.documents.count({lemmaTextLength: 10})

2. Distinct: db.collection.distinct(field, query)​

// afiseaz varstele distincte
db.documents.distinct("age")
 
// afiseaz varstele distincte pentru female
db.documents.distinct("age", {gender: "female"}).sort()

Ex. 7. Afișați toate cuvintele distincte. Folosiți câmpul words.

Aggregation Pipeline

Pentru agregare, MongoDB oferă și Aggregation Pipeline (Documentație).

db.collection.aggregate(
    { $match: <query> },
    { $unwind: <array> },
    { $project: <projection>},
    { $group: <aggregation_group, aggregation_functions> },
    { $sort: <sorting_fields> },
)

Unde:

  • $match - filtrează documentele de intrare după un query
  • $unwind - procesează elementele unui vector
  • $project - proiecția
  • $group - face grupuri și a aplica funcții agregare
  • $sort - reordonează documentele de intrare după o cheie

Contează ordinea în care sunt folosiți operatorii.

Ex. 8. Să se utilizeze Aggregation Pipeline pentru a calcula numărul de apariții ale cuvintelor.

db.documents.aggregate([
    { $match: q },
    { $project: { words: { $split: ["$lemmaText", " "]}}},
    { $unwind: "$words" },
    { $group: { _id: "$words", counts: { $sum: 1 } } }
])

Ex. 9. Să se utilizeze Aggregation Pipeline pentru a calcula numărul de apariții ale cuvintelor folosind coloana words.

MapReduce

MongoDB oferă un framework de MapReduce. Pentru a utiliza acest framework trebuie să scriem două funcții,i.e., Map și Reduce. Pentru a utilza funcțiile pe o colecție se folosește mapReduce (Documentație):

 
db.collection.mapReduce(
    mapFunction, 
    reduceFunction, 
    {
        finalize: <function>,
        out: <output>,
        query: <document>,
        sort: <document>,
        limit: <number>,
        scope: <document>
    }
)

Unde:

  • mapFunction - funcția de map
  • reduceFunction - funcția de reduce
  • finalize - (opțional) funcție pentru finalizare, se aplică după ce se termină procesul și datele sunt agregate
  • out - (opțional) colecția unde va fi salvat rezultatul
  • query - (opțional) filtru pentru documentele de intrare
  • sort - (opțional) ordonează documentele de intrare după cheie
  • limit - (opțional) limitează numărul de documente de intrare
  • scope - (opțional) variabile din exterior care pot fi folosite în funcțiile map, reduce și finalize

Comanda mapReduce este o mapare peste comanda mapReduce din MongoDB (Documentație)

db.runCommand(
    {
        mapReduce: <collection>,
        map: <function>,
        reduce: <function>,
        finalize: <function>,
        out: <output>,
        query: <document>,
        sort: <document>,
        limit: <number>,
        scope: <document>
    }
)

Ex. 10. Să se utilizeze MapReduce pentru a calcula numărul de apariții ale cuvintelor.

mapFunction = function() {
    var tokens = this.lemmaText.split(" ");
    for (var idx=0; idx<tokens.length; idx++){
        emit(tokens[idx], 1);
    }
}
 
reduceFunction = function(key, values) {
    return Array.sum(values);
};
 
var q = {"gender": "female"}       
db.documents.mapReduce(mapFunction, reduceFunction, {query: q, out: "wordCounts"});
 
db.wordCounts.count()
 
db.wordCounts.find({"_id": "0"})
 
db.wordCounts.drop()

Ex. 11. Să se utilizeze MapReduce pentru a calcula numărul de apariții ale cuvintelor folosind câmpul words.

bd2/laboratoare/12.txt · Last modified: 2021/01/05 16:23 by ciprian.truica
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0