MongoDB für Java-Programmierer
Upcoming SlideShare
Loading in...5
×
 

MongoDB für Java-Programmierer

on

  • 1,833 views

Der Talk wurde am 25.09.2013 auf der Java User Group Frankfurt gehalten und gibt einen Überblick und Einstieg in MongoDB aus der Sicht eines Java-Programmierers. ...

Der Talk wurde am 25.09.2013 auf der Java User Group Frankfurt gehalten und gibt einen Überblick und Einstieg in MongoDB aus der Sicht eines Java-Programmierers.

Dabei werden folgende Themen behandelt:

- Buzzword Bingo: NoSQL, Big Data, Horizontale Skalierung, CAP-Theorem, Eventual Consistency
- Übersicht über MongoDB
- Datenmanipulation: CRUD, Aggregation Framework, Map/Reduce
- Indexing
- Konsistenz beim Schreiben und Lesen von Daten
- Java API & Frameworks

Statistics

Views

Total Views
1,833
Views on SlideShare
1,828
Embed Views
5

Actions

Likes
1
Downloads
29
Comments
0

2 Embeds 5

https://twitter.com 4
https://www.xing.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

MongoDB für Java-Programmierer MongoDB für Java-Programmierer Presentation Transcript

  • MongoDB für Java-Programmierer Uwe Seiler uweseiler
  • About me Big Data Nerd Hadoop Trainer MongoDB Author Photography Enthusiast Travelpirate
  • About us is a bunch of… Big Data Nerds Agile Ninjas Continuous Delivery Gurus Join us! Enterprise Java Specialists Performance Geeks
  • Agenda • Buzzword Bingo • Überblick über MongoDB • Datenmanipulation • Indexing • Konsistenz beim Schreiben und Lesen von Daten • Java API & Frameworks
  • Buzzword Bingo
  • NoSQL
  • Klassifizierung von NoSQL Key-Value Stores K V K V K V K 1 V K Column Stores V Graph Databases 1 1 1 1 1 1 1 1 1 1 Document Stores _id _id _id
  • Big Data
  • Meine Lieblingsdefinition
  • Die klassische Definition • The 3 V’s of Big Data Volume Velocity •Variety
  • «Big Data» != Hadoop
  • Horizontale Skalierung
  • Vertikale Skalierung RAM CPU Storage
  • Vertikale Skalierung RAM CPU Storage
  • Vertikale Skalierung RAM CPU Storage
  • Horizontale Skalierung RAM CPU Storage
  • Horizontale Skalierung RAM CPU Storage RAM CPU Storage RAM CPU Storage RAM CPU Storage RAM CPU Storage
  • Horizontale Skalierung RAM CPU Storage RAM CPU Storage RAM CPU Storage RAM CPU Storage RAM CPU Storage RAM CPU Storage RAM CPU Storage RAM CPU Storage RAM CPU Storage RAM CPU Storage RAM CPU Storage RAM CPU Storage RAM CPU Storage RAM CPU Storage RAM CPU Storage
  • Das Problem mit der Verteilung
  • Das CAP Theorem Availability Jede Anfrage bekommt eine Antwort Consistency Alle Knoten haben jederzeit die gleichen Informationen Partition Tolerance Trotz Knotenausfall funktioniert das System
  • Überblick über NoSQL Systeme Availability Jeder Client kann immer schreiben und lesen C onsistency Alle Knoten haben jederzeit die gleichen Informationen Partition Tolerance Trotz Knotenausfall funktioniert das System
  • Das Problem mit der Konsistenz
  • ACID vs. BASE
  • ACID vs. BASE 1983 Atomicity RDBMS Consistency Isolation Durability
  • ACID vs. BASE ACID ist ein gutes Konzept, aber es ist kein in Stein gemeißeltes Gesetz!
  • ACID vs. BASE Basically Available Soft State 2008 NoSQL Eventually consistent
  • ACID vs. BASE ACID BASE - - Starke Konsistenz Isolation Zwei-Phasen-Commit Komplexe Entwicklung Zuverlässiger Schwache Konsistenz Verfügbarkeit "Fire-and-forget" Leichtere Entwicklung Schneller
  • Überblick über MongoDB
  • MongoDB ist eine … • Dokumenten-basierte • Open Source • Performante • Flexible • Skalierbare • Hochverfügbare • Funktionsreiche …Datenbank
  • Dokumenten-basierte Datenbank • Nicht im Sinne einer Datenbank für PDFoder Worddokumente…
  • Open Source Datenbank • MongoDB ist ein Open Source Projekt • Auf GitHub – https://github.com/mongodb/mongo • Steht unter der AGPL Lizenz • Gestartet und gesponsert von MongoDB Inc. (früher: 10gen) • Kommerzielle Lizenzen sind verfügbar • Jeder darf mitmachen! – https://jira.mongodb.org
  • Performance Datenlokalität In-Memory Caching In-Place Updates
  • Flexibles Schema MongoDB RDBMS { _id : ObjectId("4c4ba5e5e8aabf3"), employee_name: "Dunham, Justin", department : "Marketing", title : "Product Manager, Web", report_up: "Neray, Graham", pay_band: “C", benefits : [ { type : "Health", plan : "PPO Plus" }, { type : "Dental", plan : "Standard" } ] }
  • Skalierbarkeit Auto-Sharding • Erhöhung der Kapazität wenn nötig • Ausgelegt für Commodity Hardware • Funktioniert mit Cloud-Architekturen
  • Hochverfügbarkeit • Automatische Replikation und Failover • Unterstützung für mehrere Datenzentren • Ausgelegt auf möglichst einfachen Betrieb • Beständigkeit und Konsistenz der Daten
  • MongoDB Architektur
  • Reichhaltige Abfragen
  • Aggregation Framework
  • Map/Reduce MongoDB Data Map() emit(k,v) Group(k) Shard 1 Sort(k) Shard 2 … Shard n Reduce(k, values) Finalize(k, v)
  • Geoinformationen
  • Treiber & Shell Treiber verfügbar für die populärsten Programmiersprachen und Frameworks Java JavaScript Python Shell zur Interaktion mit der Datenbank Ruby Perl Haskell > db.collection.insert({product:“MongoDB”, type:“Document Database”}) > > db.collection.findOne() { “_id” : ObjectId(“5106c1c2fc629bfe52792e86”), “product” : “MongoDB” “type” : “Document Database” }
  • NoSQL Trends Google Search LinkedIn Job Skills MongoDB Competitor 1 Competitor 2 Competitor 3 Competitor 4 Competitor 5 MongoDB Competitor 2 Competitor 1 Competitor 4 Competitor 3 All Others Jaspersoft Big Data Index Indeed.com Trends Top Job Trends Direct Real-Time Downloads MongoDB Competitor 1 Competitor 2 Competitor 3 1.HTML 5 2.MongoDB 3.iOS 4.Android 5.Mobile Apps 6.Puppet 7.Hadoop 8.jQuery 9.PaaS 10.Social Media
  • Datenmanipulation
  • Terminologie RDBMS Tabelle / View Zeile Index Join Fremdschlüssel Partition MongoDB ➜ ➜ ➜ ➜ Collection Dokument Index Eingebettetes Dokument ➜ Referenziertes Dokument ➜ Shard
  • Let’s have a look…
  • Anlegen einer Datenbank // Anzeigen aller Datenbanken > show dbs digg 0.078125GB enron 1.49951171875GB // Wechsel in eine Datenbank > use blog // Erneutes Anzeigen aller Datenbanken > show dbs digg 0.078125GB enron 1.49951171875GB
  • Anlegen einer Collection I // Anzeigen aller Collections > show collections // Einfügen eines Benutzers > db.user.insert( { name : “Sheldon“, mail : “sheldon@bigbang.com“ } ) Beim Einfügen erfolgt kein Feedback über den Erfolg der Operation, Abfrage über: db.runCommand( { getLastError: 1} )
  • Anlegen einer Collection II // Anzeigen aller Collections > show collections system.indexes user // Anzeigen aller Datenbanken > show dbs blog 0.0625GB digg 0.078125GB enron 1.49951171875GB Datenbank und Collection werden automatisch beim ersten Insert anlegt.
  • Lesen aus einer Collection // Anzeigen des ersten Dokuments > db.user.findOne() { "_id" : ObjectId("516684a32f391f3c2fcb80ed"), "name" : "Sheldon", "mail" : "sheldon@bigbang.com" } // Alle Dokumente einer Collection anzeigen > db.user.find() { "_id" : ObjectId("516684a32f391f3c2fcb80ed"), "name" : "Sheldon", "mail" : "sheldon@bigbang.com" }
  • Filtern von Dokumenten // Filtern von bestimmten Dokumenten > db.user.find( { name : ”Penny” } ) { "_id" : ObjectId("5166a9dc2f391f3c2fcb80f1"), "name" : "Penny", "mail" : "penny@bigbang.com" } // Nur bestimmte Felder anzeigen > db.user.find( { name : ”Penny” }, {_id: 0, mail : 1} ) { "mail" : "sheldon@bigbang.com" }
  • _id • _id ist der primäre Schlüssel in MongoDB • Index auf _id wird automatisch erzeugt • Wenn nicht anders angegeben, handelt es sich dabei um eine ObjectId • _id kann auch selbst beim Einfügen von Dokumenten vergeben werden, jeder einzigartige unveränderbare Wert kann dabei verwendet werden
  • ObjectId • Eine ObjectId ist ein spezieller 12 Byte Wert • Ihre Einzigartigkeit über den gesamten Cluster ist durch die Zusammensetzung garantiert: ObjectId("50804d0bd94ccab2da652599") |-------------||---------||-----||----------| ts mac pid inc
  • Cursor // Benutzen eines Cursors für die Dokumente > var myCursor = db.user.find( ) // Nächstes Dokument holen und Mail anzeigen > var myDocument = myCursor.hasNext() ? myCursor.next() : null; > if (myDocument) { printjson(myDocument.mail); } // Restliche Dokumente anzeigen > myCursor.forEach(printjson); In der Shell werden per Default 20 Dokumente angezeigt.
  • Logische Verknüpfungen // Oder-Verknüpfung > db.user.find( {$or : [ { name : “Sheldon“ }, { mail : amy@bigbang.com } ] }) // Und-Verknüpfung > db.user.find( {$and : [ { name : “Sheldon“ }, { mail : amy@bigbang.com } ] })
  • Ergebnismengen anpassen // Sortieren von Dokumenten > db.user.find().sort( { name : 1 } ) // Aufsteigend > db.user.find().sort( { name : -1 } ) // Absteigend // Ergebnismenge limitieren > db.user.find().limit(3) // Ergebnisdokumente überspringen > db.user.find().skip(2) // Kombination der Methoden > db.user.find().skip(2).limit(3)
  • Update von Dokumenten I // Update der Mail-Adresse (So bitte nicht!) > db.user.update( { name : “Sheldon“ }, { mail : “sheldon@howimetyourmother.com“ } ) // Anzeige des Updates db.user.findOne() { "_id" : ObjectId("516684a32f391f3c2fcb80ed"), "mail" : "sheldon@howimetyourmother.com" } Aufpassen beim Update von Dokumenten!
  • Löschen von Dokumenten // Löschen des Dokuments > db.user.remove( { mail : “sheldon@howimetyourmother.com“ } ) // Löschen aller Dokumente > db.user.remove() // Löschen von Dokumenten mittels Bedingung > db.user.remove( { mail : /.*mother.com$/ } ) // Löschen nur des ersten passenden Dokuments > db.user.remove( { mail : /.*.com$/ }, true )
  • Update von Dokumenten II // Update der Mail-Adresse (Jetzt aber richtig!) > db.user.update( { name : “Sheldon“ }, { $set : { mail : “sheldon@howimetyourmother.com“ }}) // Anzeige des Updates db.user.find(name : “Sheldon“) { "_id" : ObjectId("5166ba122f391f3c2fcb80f5"), "mail" : "sheldon@howimetyourmother.com", "name" : "Sheldon" }
  • Hinzufügen zu Arrays // Hinzufügen eines Arrays > db.user.update( {name : “Sheldon“ }, { $set : {enemies : [ { name : “Wil Wheaton“ }, { name : “Barry Kripke“ } ] }}) // Hinzufügen eines Wertes zum Array > db.user.update( { name : “Sheldon“}, { $push : {enemies : { name : “Leslie Winkle“} }})
  • Löschen aus Arrays // Löschen eines Wertes aus dem Array > db.user.update( { name : “Sheldon“ }, {$pull : {enemies : {name : “Barry Kripke“ } }}) // Löschen des kompletten Feldes > db.user.update( {name : “Sheldon“}, {$unset : {enemies : 1}} )
  • Einfügen eines Subdokuments // Hinzufügen eines Subdokuments > db.user.update( { name : “Sheldon“}, { $set : { mother :{ name : “Mary Cooper“, residence : “Galveston, Texas“, religion : “Evangelical Christian“ }}}) { "_id" : ObjectId("5166cf162f391f3c2fcb80f7"), "mail" : "sheldon@bigbang.com", "mother" : { "name" : "Mary Cooper", "residence" : "Galveston, Texas", "religion" : "Evangelical Christian" }, "name" : "Sheldon" }
  • Abfragen auf Subdokumenten // Abfrage des Namens der Mutter > db.user.find( { name : “Sheldon“}, {“mother.name“ : 1 } ) { "_id" : ObjectId("5166cf162f391f3c2fcb80f7"), "mother" : { "name" : "Mary Cooper" } } Zusammengesetzte Feldnamen müssen in “…“ stehen!
  • Übersicht über alle UpdateOperatoren Für Felder: $inc $rename $set $unset Bitweise: $bit Isolation: $isolated Für Arrays: $addToSet $pop $pullAll $pull $pushAll $push $each (Modifier) $slice (Modifier) $sort (Modifier)
  • Dokumentation Create http://docs.mongodb.org/manual/core/create/ Read http://docs.mongodb.org/manual/core/read/ Update http://docs.mongodb.org/manual/core/update/ Delete http://docs.mongodb.org/manual/core/delete/
  • Das Aggregation Framework • Wurde eingeführt, um Aggregationen ohne Map/Reduce berechnen zu können • Framework von Methoden & Operatoren – Deklarativ – Kein eigener JavaScript-Code mehr nötig – Framework kann erweitert werden • Implementiert in C++ – Overhead der JavaScript-Engine wird vermieden – Höhere Performance
  • Aggregation Pipeline Pipeline Operator Pipeline Operator Pipeline Operator { document } Ergebnis { sum: 337 avg: 24,53 min: 2 max : 99 }
  • Aggregation Pipeline • Verarbeitet einen Strom von Dokumenten – Eingabe ist eine Collection – Ausgabe ist ein Ergebnisdokument • Aneinanderreihung von PipelineOperatoren – Jede Stufe filtert oder transformiert die Dokumente – Ausgabedokumente einer Stufe sind die Eingabe- dokumente der nächsten Stufe
  • Aufruf > db.tweets.aggregate( { $pipeline_operator_1 { $pipeline_operator_2 { $pipeline_operator_3 { $pipeline_operator_4 ... ); }, }, }, },
  • Pipeline Operatoren // Alte Bekannte* // Neue Freunde $match $sort $limit $skip * Aus der Abfragefunktionalität $project $group $unwind
  • Aggregation Framework I // Collection mit Tweets { "_id" : ObjectId("4fb9fb91d066d657de8d6f39"), "text" : "I can't wait for #BoardwalkEmpire", "in_reply_to_status_id" : null, "retweet_count" : null, "contributors" : null, "created_at" : "Thu Sep 02 18:11:24 +0000 2010", … "user" : { "friends_count" : 204, … "followers_count" : 24, "id" : 64054560, … }, …}
  • Aggregation Framework II // Finde die Top-3-Twitterer nach Followern > db.tweets.aggregate( { $project : {name : "$user.name", follower_count : "$user.followers_count"}}, { $group : {_id : {name : "$name"}, follower_count : {$max : "$follower_count"}}}, { $sort : {follower_count : -1}}, { $limit: 3} );
  • Aggregation Framework III // Finde die Top-3-Links aus Tweets > db.tweets.aggregate( { $project : {_id: 0, inhalt_des_tweets : "$text", links : "$entities.urls.url" } }, { $unwind : "$links" }, { $group : { _id : "$links", anzahl : {$sum : 1} } }, { $sort : {anzahl : -1} }, { $limit : 3 } );
  • Was ist Map/Reduce? • Programmiermodel aus der funktionalen Welt • Framework zur – parallelen Verarbeitung – von großen Datenmengen – mittels verteilter Systeme • Populär geworden durch Google – Wird zur Berechnung des Suchindex verwendet, welcher Seiten zu Keywords zuordnet (Page Rank) – http://research.google.com/archive/mapreduce.html
  • Map/Reduce mit MongoDB MongoDB map() Daten group(k) emit(k,v) Shard 1 • Iteriert über alle Dokumente sort(k) Shard 2 … Shard n reduce(k, values) finalize(k, v) k, v k, v • • Input = Output Kann mehrfach laufen
  • Word Count: Problemstellung INPUT { MongoDB uses MapReduce } { There is a map phase } { There is a reduce phase } MAPPER GROUP/SORT REDUCER OUTPUT a: 2 is: 2 map: 1 Problem: Wie häufig kommt ein Wort in allen Dokumenten vor? mapreduce: 1 mongodb: 1 phase: 2 reduce: 1 there: 2 uses: 1
  • Word Count: Tweets // Beispiel: Twitter-Datenbank mit Tweets > db.tweets.findOne() { "_id" : ObjectId("4fb9fb91d066d657de8d6f38"), "text" : "RT @RevRunWisdom: The bravest thing that men do is love women #love", "created_at" : "Thu Sep 02 18:11:24 +0000 2010", … "user" : { "friends_count" : 0, "profile_sidebar_fill_color" : "252429", "screen_name" : "RevRunWisdom", "name" : "Rev Run", }, …
  • Word Count: Map Funktion // Map Funktion mit Bereinigung der Daten map = function() { this.text.split(' ').forEach(function(word) { // Entfernen von Whitespace word = word.replace(/s/g, ""); // Entfernen alle Non-Word-Characters word = word.replace(/W/gm,""); // Finally emit the cleaned up word if(word != "") { emit(word, 1) } }); };
  • Word Count: Reduce Funktion // Reduce Funktion reduce = function(key, values) { return values.length; };
  • Word Count: Aufruf // Anzeigen des Ergebnisses in der Konsole > db.tweets.mapReduce(map, reduce, { out : { inline : 1 } } ); // Speichern des Ergebnisses in einer Collection > db.tweets.mapReduce(map, reduce, { out : "tweets_word_count"} ); { "result" : "tweets_word_count", "timeMillis" : 19026, "counts" : { "input" : 53641, "emit" : 559217, "reduce" : 102057, "output" : 131003 }, "ok" : 1, }
  • Word Count: Ergebnis // Ausgeben der 10 häufigsten Wörter in Tweets > db.tweets_word_count.find().sort({"value" : -1}).limit(10) { { { { { { { { { { "_id" "_id" "_id" "_id" "_id" "_id" "_id" "_id" "_id" "_id" : : : : : : : : : : "Miley", "value" : 31 } "mil", "value" : 31 } "andthenihitmydougie", "value" : 30 } "programa", "value" : 30 } "Live", "value" : 29 } "Super", "value" : 29 } "cabelo", "value" : 29 } "listen", "value" : 29 } "Call", "value" : 28 } "DA", "value" : 28 }
  • Indexing
  • Indexe in MongoDB sind B-Trees
  • Abfragen, Einfügen und Löschen: O(log(n))
  • Fehlende oder nicht optimale Indexe sind das häufigste vermeidbare MongoDB Performance-Problem
  • Wie lege ich Indexe an? // Anlegen eines Index, wenn er noch nicht existiert > db.recipes.createIndex({ main_ingredient: 1 }) // Der Client merkt sich den Index und wirft keinen Fehler > db.recipes.ensureIndex({ main_ingredient: 1 }) * 1 für aufsteigend, -1 für absteigend
  • Was kann indexiert werden? // Mehrere Felder (Compound Key Indexes) > db.recipes.ensureIndex({ main_ingredient: 1, calories: -1 }) // Arrays mit Werten (Multikey Indexes) { name: 'Chicken Noodle Soup’, ingredients : ['chicken', 'noodles'] } > db.recipes.ensureIndex({ ingredients: 1 })
  • Was kann indexiert werden? // Subdokumente { name : 'Apple Pie', contributor: { name: 'Joe American', id: 'joea123' } } db.recipes.ensureIndex({ 'contributor.id': 1 }) db.recipes.ensureIndex({ 'contributor': 1 })
  • Wie verwalte ich Indexe? // Auflisten aller Indexe einer Collection > db.recipes.getIndexes() > db.recipes.getIndexKeys() // Löschen eines Index > db.recipes.dropIndex({ ingredients: 1 }) // Löschen und Neuerzeugung aller Indexe db.recipes.reIndex() // Defaultindex auf _id
  • Weitere Optionen • Unique Indexe – Nur eindeutige Werte erlaubt • Sparse Indexe – Für Felder, die nicht in allen Dokumenten vorkommen • Geospatial Indexe – Zur Modellierung von Geoinformationen • TTL Collections – Verfallen nach x Sekunden
  • Unique Indexe // Der Name eines Rezepts muss eindeutig sein > db.recipes.ensureIndex( { name: 1 }, { unique: true } ) // Erzwingen eines Index auf einer Collection mit nicht eindeutigen // Namen – Die Duplikate werden gelöscht > db.recipes.ensureIndex( { name: 1 }, { unique: true, dropDups: true } ) * dropDups bitte mit sehr viel Vorsicht anwenden!
  • Sparse Indexe // Nur Dokumente mit dem Feld calories werden indexiert > db.recipes.ensureIndex( { calories: -1 }, { sparse: true } ) // Kombination mit einem Unique Index möglich > db.recipes.ensureIndex( { name: 1 , calories: -1 }, { unique: true, sparse: true } ) * Fehlende Felder werden im Index als null gespeichert
  • Geospatial Indexe // Hinzufügen von Längen- und Breitengraden { name: ‚codecentric Frankfurt’, loc: [ 50.11678, 8.67206] } // Indexierung der Koordinaten > db.locations.ensureIndex( { loc : '2d' } ) // Abfrage nach Orten in der Nähe von codecentric Frankfurt > db.locations.find({ loc: { $near: [ 50.1, 8.7 ] } })
  • TTL Collections // Die Dokumente müssen ein Datum des Typs BSON UTC haben { ' submitted_date ' : ISODate('2012-10-12T05:24:07.211Z'), … } // Dokumente werden automatisch nach 'expireAfterSeconds' // Sekunden gelöscht > db.recipes.ensureIndex( { submitted_date: 1 }, { expireAfterSeconds: 3600 } )
  • Limitierungen von Indexen • Collections können nicht mehr als 64 Indexe haben. • Indexschlüssel können nicht größer als 1024 Byte sein. • Der Name eines Index inklusive Namespace muss kleiner als 128 Zeichen sein. • Abfragen können nur einen Index verwenden – Ausnahme: Abfragen mit $or • Indexe verbrauchen Speichern und verlangsamen das Schreiben von Daten
  • Optimierung von Indexen
  • Vorgehensweise 1. Langsame Abfragen identifizieren 2. Mittels explain() mehr über die langsame Abfrage herausfinden 3. Anlegen der Indexe auf den abgefragten Feldern 4. Optimierung der Abfragen anhand der verwendeten Indexe
  • 1. Langsame Abfragen identifizieren > db.setProfilingLevel( n , slowms=100ms ) n=0: Profiler abgeschaltet n=1: Protokollieren aller Abfragen langsamer als slowms n=2: Protokollieren aller Operationen > db.system.profile.find() * Die Collection profile ist eine Capped Collection und hat daher eine feste Anzahl von Einträgen
  • 2. Benutzung von explain() > db.recipes.find( { calories: { $lt : 40 } } ).explain( ) { "cursor" : "BasicCursor" , "n" : 42, "nscannedObjects” : 53641 "nscanned" : 53641, ... "millis" : 252, ... } * Keine Verwendung von Plänen aus dem Cache und erneuten Ausführungen
  • 2. Metriken des Executionplans I • Cursor – Der Typ des Cursors. BasicCursor bedeutet, dass kein Index benutzt wurde • n – Die Anzahl der passenden Dokumente • nscannedObjects – Die Anzahl der gescannten Dokumente • nscanned – Die Anzahl der untersuchten Einträge (Indexeinträge oder Dokumente)
  • 2. Metriken des Executionplans II • millis – Ausführungszeit der Abfrage • Komplette Referenz unter – http://docs.mongodb.org/manual/reference/explain Das Verhältnis der gescannten zu den gefundenen Dokumenten sollte möglichst nahe an 1 sein!
  • 3. Anlegen der Indexe auf den abgefragten Feldern
  • 4. Optimierung der Abfragen anhand der verwendeten Indexe // Bei folgendem Index… > db.collection.ensureIndex({ a:1, b:1 , c:1, d:1 }) // // > > … können die folgenden Sortieroperationen und Abfragen den Index benutzen db.collection.find( ).sort({ a:1 }) db.collection.find( ).sort({ a:1, b:1 }) > db.collection.find({ a:4 }).sort({ a:1, b:1 }) > db.collection.find({ b:5 }).sort({ a:1, b:1 })
  • 4. Optimierung der Abfragen anhand der verwendeten Indexe // Bei folgendem Index… > db.collection.ensureIndex({ a:1, b:1, c:1, d:1 }) // … können diese Abfragen ihn nicht verwenden > db.collection.find( ).sort({ b: 1 }) > db.collection.find({ b: 5 }).sort({ b: 1 })
  • 4. Optimierung der Abfragen anhand der verwendeten Indexe // Bei folgendem Index… > db.recipes.ensureIndex({ main_ingredient: 1, name: 1 }) // … verwendet diese Abfrage nur Felder des Index > db.recipes.find( { main_ingredient: 'chicken’ }, { _id: 0, name: 1 } ) // Das Feld indexOnly bei explain() zeigt dies an > db.recipes.find( { main_ingredient: 'chicken' }, { _id: 0, name: 1 } ).explain() { "indexOnly": true, }
  • Index manuell angeben // MongoDB mitteilen, welcher Index verwendet werden soll > db.recipes.find({ calories: { $lt: 1000 } } ).hint({ _id: 1 }) // Die Verwendung von Indexen ausschalten (z.B. zur Performance// messung > db.recipes.find( { calories: { $lt: 1000 } } ).hint({ $natural: 1 })
  • Häufige Stolperfallen bei Indexen
  • Mehrere Index verwenden // MongoDB kann nur einen Index pro Abfrage verwenden > db.collection.ensureIndex({ a: 1 }) > db.collection.ensureIndex({ b: 1 }) // Nur einer der beiden obigen Indexe wird verwendet > db.collection.find({ a: 3, b: 4 })
  • Zusammengesetzte Indexe // Zusammengesetzte Indexe sind im Allgemeinen sehr effektiv > db.collection.ensureIndex({ a: 1, b: 1, c: 1 }) // Aber nur wenn die Abfrage ein Präfix des Indexes ist… // Diese Abfrage kann den Index nicht effektiv verwenden db.collection.find({ c: 2 }) // …diese Abfrage hingegen schon db.collection.find({ a: 3, b: 5 })
  • Indexe mit geringer Selektivität // Folgendes Feld hat nur sehr wenige eindeutige Werte > db.collection.distinct('status’) [ 'new', 'processed' ] // Ein Index auf diesem Feld bringt nur sehr wenig > db.collection.ensureIndex({ status: 1 }) > db.collection.find({ status: 'new' }) // Besser ist ein zusammengesetzter Index zusammen mit einem // anderen Feld > db.collection.ensureIndex({ status: 1, created_at: -1 }) > db.collection.find( { status: 'new' } ).sort({ created_at: -1 })
  • Reguläre Ausdrücke & Indexe > db.users.ensureIndex({ username: 1 }) // Abfragen mit regulären Ausdrücken, die linksgebunden sind // können den Index verwenden > db.users.find({ username: /^joe smith/ }) // Generische Abfragen mit regulären Ausdrücken hingegen nicht… > db.users.find({username: /smith/ }) // Ebenso nicht schreibungsunabhängige Abfragen… > db.users.find({ username: /Joe/i })
  • Negation // Bei Negationen können Indexe nicht verwendet werden > db.things.ensureIndex({ x: 1 }) // z.B. bei Abfragen mit not equal > db.things.find({ x: { $ne: 3 } }) // …oder Abfragen mit not in > db.things.find({ x: { $nin: [2, 3, 4 ] } }) // …oder Abfragen mit dem $not Operator > db.people.find({ name: { $not: 'John Doe' } })
  • Konsistenz beim Schreiben und Lesen von Daten
  • Starke Konsistenz
  • Verzögerte Konsistenz
  • Write Concern - Schreibmodi • Bestätigung durch das Netzwerk • Bestätigung durch MongoDB • Bestätigung durch das Journal • Bestätigung durch Secondaries • Bestätigung durch Tagging
  • Bestätigung durch das Netzwerk „Fire and forget“
  • Bestätigung durch MongoDB Wait for Error
  • Bestätigung durch das Journal Wait for Journal Sync
  • Bestätigung durch Secondaries Wait for Replication
  • Tagging beim Schreiben • Verfügbar seit Version 2.0 • Ermöglicht stärkere Kontrolle woher Daten gelesen und wohin geschrieben werden • Jeder Knoten kann mehrere Tags haben – tags: {dc: "ny"} – tags: {dc: "ny", subnet: „192.168", rack: „row3rk7"} • Erlaubt das Anlegen für Regeln für das Write Concern pro Replikaset • Anpassung der Regeln ohne Codeänderung
  • Beispiel für Tagging { _id : "mySet", members : [ {_id : 0, host : "A", tags : {"dc": "ny"}}, {_id : 1, host : "B", tags : {"dc": "ny"}}, {_id : 2, host : "C", tags : {"dc": "sf"}}, {_id : 3, host : "D", tags : {"dc": "sf"}}, {_id : 4, host : "E", tags : {"dc": "cloud"}}], settings : { getLastErrorModes : { allDCs : {"dc" : 3}, someDCs : {"dc" : 2}} } } > db.blogs.insert({...}) > db.runCommand({getLastError : 1, w : "someDCs"})
  • Bestätigung durch alle Datenzentren Wait for Replication (Tagging)
  • Setzen des Write Concerns // Wait for network acknowledgement > db.runCommand( { getLastError: 1, w: 0 } ) // Wait for error (Default) > db.runCommand( { getLastError: 1, w: 1 } ) // Wait for journal sync > db.runCommand( { getLastError: 1, w: 1, j: "true" } ) // Wait for replication > db.runCommand( { getLastError: 1, w: “majority" } ) // Mehrheit > db.runCommand( { getLastError: 1, w: 3 } ) // # der Secondaries
  • Modi zum Lesen von Daten (Seit Version 2.2) • Nur Primary (primary) • Primary bevorzugt (primaryPreferred) • Nur Secondaries (secondary) • Secondaries bevorzugt (secondaryPreferred) • Nähester Knoten (Nearest) Falls mehr als ein Knoten möglich ist, wird immer der näheste Knoten zum Lesen der Daten verwendet. (Alle Modi außer Primary)
  • Read Nur Primary primary
  • Read Read Primary bevorzugt primaryPreferred
  • Read Read Nur Secondaries secondary
  • Read Read Read Secondaries bevorzugt secondaryPreferred
  • Read Read Read Nähester Knoten nearest
  • Tagging beim Lesen • Ermöglicht eine individuelle Kontrolle woher Daten gelesen werden – z.B. { "disk": "ssd", "use": "reporting" } • Lässt sich mit den Standard-Lese-Modi kombinieren – Außer dem Modus „Nur Primary“
  • Setzen der Read Preference // Nur Primary > cursor.setReadPref( “primary" ) // Primary bevorzugt > cursor.setReadPref( “primaryPreferred" ) …. // Nur Secondaries mit Tagging > cursor.setReadPref( “secondary“, [ rack : 2 ] ) Aufruf der Methode auf dem Cursor muss vor dem Lesen der Dokumente erfolgen
  • Java API & Frameworks
  • Übersicht Jongo Spring Data MongoDB Morphia Hibernate OGM JPA JDBC MongoDB Java Driver MongoDB
  • MongoDB Java Treiber
  • MongoDB Treiber • Ein Wire Protokoll für alle Programmiersprachen • Eine Implementierung des Treibers pro Sprache • Hauptaufgaben: – Konvertierung der sprachspezifischen Datenstrukturen nach BSON – Generierung der ObjectId für das Feld _id
  • MongoDB Java Treiber • Ein JAR ohne weitere Abhängigkeiten: <dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>2.11.3</version> </dependency> Verfügbar auf Github: https://github.com/mongodb/mongo-java-driver
  • Verbindungsaufbau import com.mongodb.MongoClient; // Default: localhost:27017 mongo = new MongoClient(); // Replica set mongo = new MongoClient(Arrays.asList( new ServerAddress("replicant01", 10001), new ServerAddress("replicant02", 10002), new ServerAddress("replicant03", 10003) )); // Sharding: mongos server mongo = new MongoClient("mongos01", 4711);
  • Zugriff auf Datenbank und Collection import com.mongodb.DB; import com.mongodb.DBCollection; DB db = mongo.getDB("test"); DBCollection collection = db.getCollection("foo");
  • Dokument einfügen import com.mongodb.BasicDBObject; import com.mongodb.DBObject; // insert document DBObject doc = new BasicDBObject(); doc.put("date", new Date()); doc.put("i", 42); collection.insert(doc);
  • Dokumente abfragen import com.mongodb.DBCursor; DBCursor cursor; cursor = collection.find(); // all documents // documents w/ {i: 42} cursor = collection.find( new BasicDBObject("i", 42) ); document = cursor.next(); ...
  • Beispiel: Bestellung > db.order.find( {"items.quantity": ? } )
  • Beispiel: Bestellung I DB db = mongo.getDB("test"); DBCollection collection = db.getCollection("order"); DBObject order; List<DBObject> items = new ArrayList<DBObject>(); DBObject item; // order order = new BasicDBObject(); order.put("date", new Date()); order.put("custInfo" , „Sheldon Cooper"); // items item = new BasicDBObject(); item.put("quantity", 1); item.put("price", 47.11); item.put("desc", "Item #1"); items.add(item); item = new BasicDBObject(); item.put("quantity", 2); item.put("price", 42.0); item.put("desc", "Item #2"); items.add(item); order.put("items", items); collection.insert(order);
  • Beispiel: Bestellung II DB db = mongo.getDB("test"); DBCollection collection = db.getCollection("order"); DBObject query; DBObject document; DBCursor cursor; query = new BasicDBObject("items.quantity", 2); cursor = collection.find(query); while ( cursor.hasNext() ) { document = cursor.next(); println(document); }
  • Jongo
  • Kurzüberblick über Jongo Entwickler Lizenz Dokumentation Hauptmerkmale Benoît Guérout, Yves Amsellem Apache License, Version 2.0 http://jongo.org/ • Object/Document Mapping • Eigene Query API
  • Query in Java as in Mongo Shell
  • Jongo: Object Mapping public class Order { private ObjectId id; private Date date; @JsonProperty("custInfo") private String customerInfo; List<Item> items; … } public class Item { private int quantity; private double price; @JsonProperty("desc") private String description; … }
  • Jongo: Abfragen // Java driver API MongoClient mc = new MongoClient(); DB db = mc.getDB("odm_jongo"); // Jongo API entry point Jongo jongo = new Jongo(db); MongoCollection orders = jongo.getCollection("order"); // no DAO needed Iterable<Order> result = orders.find("{"items.quantity": #}", 2).as(Order.class); // supports projection Iterable<X> result = orders.find().fields("{_id:0, date:1, custInfo:1}").as(X.class);
  • Morphia
  • Kurzüberblick über Morphia Entwickler Lizenz Dokumentation Scott Hernandez, James Green Apache License, Version 2.0 https://github.com/jmkgreen/morph ia/wiki/Overview Hauptmerkmale • Object/Document Mapping • Eigene Query API • Unterstützung für DAO‘s
  • Morphia: Object Mapping public class Order { @Id private ObjectId id; private Date date; @Property("custInfo") private String customerInfo; @Embedded List<Item> items; ... } public class Item { private int quantity; private double price; @Property("desc") private String description; ... }
  • Morphia: Abfragen public class OrderDao extends BasicDAO<Order, ObjectId> { List<Order> findByItemsQuantity(int quantity) { return find( createQuery().filter("items.quantity", quantity)) .asList(); } List<Order> findByItemsPriceGreaterThan(double price) { return find( createQuery().field("items.price").greaterThan(price) ) .asList(); } … }
  • Morphia: Eigene Syntax für Abfragen Morphia Mongo Query = !=, <> >, <, >=,<= in, nin elem … $eq $neq $gt, $lt, $gte, $lte $in, $nin $elemMatch ….
  • Spring Data MongoDB
  • Kurzüberblick über Spring Data MongoDB Hersteller Lizenz Dokumentation VMware / SpringSource Apache License, Version 2.0 http://www.springsource.org/spring -data/mongodb Hauptmerkmale • Repository Support • Object/Document Mapping • Templating
  • Spring Data CrudRepository Spring Data JPA PagingAndSortingRepository Spring Data Neo4j MongoReposito ry GraphRepos itory MongoT em plate JpaRepository Spring Data MongoDB Neo4jTemplate Em bedded JPA JDBC RDBMS Spring Data … RES T Mongo Java Driver Mongo DB Neo4j … Einheitliche Architektur für relationale Datenbanken sowie für unterstützte NoSQL-Stores
  • Spring Data MongoDB • Repository Support – Abfragen werden aus den Methodensignaturen erstellt – Annotationen für Abfragen • Object-Document-Mapping – Annotationen: @Document, @Field, @Index, … – Klassen werden auf Collections gemappt, Javaobjekte auf Dokumente • Templating – – – – Abstraktion der Ressourcen Konfigurierbarkeit der Verbindungen zu MongoDB Abdeckung des Lebenszyklus einer Collection Unterstützung für Map/Reduce & Aggregation Framework
  • Spring Data MongoDB: Konfiguration <!-- Connection to MongoDB server --> <mongo:db-factory host="localhost" port="27017" dbname="test" /> <!-- MongoDB Template --> <bean id="mongoTemplate, class="org.springframework.data.mongodb.core.MongoTemplate"> <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/> </bean> <!-- Package w/ automagic repositories --> <mongo:repositories base-package="mongodb" />
  • Spring Data MongoDB: Template <mongo:mongo host="${mongo.host}" port="${mongo.port}"> <mongo:options connections-per-host="${mongo.connectionsPerHost}„ threads-allowed-to-block-for-connection multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}„ connect-timeout="${mongo.connectTimeout}„ max-wait-time="${mongo.maxWaitTime}„ auto-connect-retry="${mongo.autoConnectRetry}„ socket-keep-alive="${mongo.socketKeepAlive}„ socket-timeout="${mongo.socketTimeout}„ slave-ok="${mongo.slaveOk}„ write-number="1„ write-timeout="0„ write-fsync="true"/> </mongo:mongo> <mongo:db-factory dbname= "test" mongo-ref="mongo"/>
  • Spring Data MongoDB: Object Mapping public class Order { @Id private String id; private Date date; @Field("custInfo") private String customerInfo; List<Item> items; ... } public class Item { private int quantity; private double price; @Field("desc") private String description; ... }
  • Spring Data MongoDB: Repository Support public interface OrderRepository extends MongoRepository<Order, String> { List<Order> findByItemsQuantity(int quantity); List<Order> findByItemsPriceGreaterThan(double price); }
  • Spring Data MongoDB: Zusätzliche Unterstützung für… • Map/Reduce & das Aggregation Framework • Das Management von Indexen • Große Dateien mittels GridFS • Geoinformatische Indexe und Abfragen • Optimistisches Locking
  • Hibernate OGM
  • Kurzüberblick über Hibernate OGM MongoDB Hersteller Lizenz Dokumentation JBoss / Redhat GNU LGPL, Version 2.1 http://www.hibernate.org/subproject s/ogm.html Hauptmerkmale • JPA API (Teilweise) • JPQL Query Language
  • Hibernate OGM • Implementiert ein Subset der JPA API • JP-QL Anfragen werden in native Datenbankabfragen übersetzt • Unterstützt Infinispan, EhCache, MongoDB
  • Architektur von Hibernate OGM Source: http://docs.jboss.org/hibernate/ogm/4.0/reference/en-US/html/ogm-architecture.html#d0e409
  • Hibernate OGM MongoDB: Konfiguration <persistence version="2.0" …> <persistence-unit name="primary"> <provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider> <class>hibernate.Order</class> <class>hibernate.Item</class> <properties> <property name="hibernate.ogm.datastore.provider" value="org.hibernate.ogm.datastore.mongodb.impl.MongoDBDatastorePr ovider"/> <property name="hibernate.ogm.mongodb.database" value=„odm"/> <property name="hibernate.ogm.mongodb.host" value=„localhost"/> <property name="hibernate.ogm.mongodb.port" value=„27017"/> </properties> </persistence-unit> </persistence>
  • Hibernate OGM MongoDB: Object Mapping @Entity @NamedQuery( name="byItemsQuantity", query = "SELECT o FROM Order o JOIN o.items i WHERE i.quantity = :quantity" ) public class Order { @GeneratedValue(generator = "uuid") @GenericGenerator(name = "uuid", strategy = "uuid2") @Id private String id; private Date date; @Column(name = "custInfo") private String customerInfo; @ElementCollection private List<Item> items; @Embeddable public class Item { private int quantity; private double price; @Column(name="desc") private String description; ...
  • Hibernate OGM MongoDB: Aktueller Status • Frühes Beta-Stadium • Aktuell nur Speichern / Mergen / Löschen von Daten möglich • Noch keine Unterstützung für Abfragen • Benutzt eine relationale API
  • Not yet ready for prime time…
  • Empfehlung
  • Was sollte ich einsetzen? - „Ready for production“ JPA Hibernate OGM Spring Data MongoDB - Frühes Betastadium - Diskrepanz in API - Aktive Community - Ältestes Framework - Nicht so mächtig wie Spring Morphia Der „bessere“ Treiber Jongo JDBC MongoDB Java Driver - „Ready for production“ - Von MongoDB Inc. unterstützt MongoDB
  • Getting started… One more thing…
  • MongoDB User Group https://www.xing.com/net/mongodb-ffm/ http://www.meetup.com/Frankfurt-Rhine-Main-MongoDB-User-Group/
  • MongoDB Munich 2013 http://www.mongodb.com/events/mongodb-munich-2013/
  • So Long, and Thanks for All the Fish!