Ich verfolge gerade einige Tweets zum Thema Geodaten und bin auf einen interessanten Tweet über eine neue Option gestoßen, einen Geodatenindex zu einer MongoDB hinzuzufügen. Da ich in letzter Zeit einige Dinge mit Scala gemacht habe, beschloss ich, die Daten mit Scala und scamongo in MongoDB einzufügen. Leider bereitete mir der Scala-Treiber von scamongo für MongoDB zu viele Probleme, so dass ich auf den Java-Treiber umstieg.
Ich habe keinerlei Erfahrung mit MongoDB, es hört sich nur cool an und die Leute sagen mir, dass es cool ist. Das reicht mir, um ein wenig zu recherchieren. Ich habe vor kurzem meine Bachelorarbeit über das Sammeln von GPS-Punkten und die Ermittlung von Laufstrecken aus diesen Punkten abgeschlossen. Der größte Engpass in meiner Anwendung bestand darin, die Anzahl der Punkte innerhalb eines bestimmten Radius um einen Punkt zu zählen. Sie müssen im Grunde alle Punkte daraufhin überprüfen, ob sie sich innerhalb des Radius befinden. Nehmen wir an, Sie haben 10^6 Punkte (so wie ich), dann sind (10^6)*(10^6) Schritte erforderlich. In meiner Schlussfolgerung habe ich empfohlen, einen Geodatenindex mit PostGIS zu verwenden, aber das ist nicht wirklich neu und cool, also versuchen wir es mit MongoDB.
Was ist MongoDB?
"MongoDB (von 'humongous') ist eine skalierbare, leistungsstarke, quelloffene, schemafreie, dokumentenorientierte Datenbank."
Nun, ich denke, das ist eine recht gute Beschreibung. Die Idee ist, Dokumente (JSON-Objekte) in eine Sammlung (vergleichbar mit einer Tabelle in einem RDBMS) in einer Datenbank einzufügen. Abfragen verwenden kein SQL, sie sind ein wenig mit QBE vergleichbar.
Einfügen und Abfragen können mit einer Vielzahl von Sprachen durchgeführt werden. Offizielle Unterstützung gibt es für C, C++, Java, Javascript, Perl, PHP, Python und Ruby. Die Community unterstützt eine Reihe weiterer Sprachen, die > db.foo.save( { a : 1 } )
db.foo.find() Die erste Zeile des obigen Codes speichert ein Dokument in der Sammlung foo mit dem Schlüssel/Wert a/1. Wenn Sie eine Suche durchführen (zweite Zeile), wird dasselbe Objekt angezeigt, jetzt mit einer eindeutigen ID (dafür wird der Schlüssel _id verwendet) Es gäbe viel über MongoDB zu erzählen, aber das haben schon viele getan, also konzentrieren wir uns auf die räumliche Indizierung in Kombination mit Scala.
Wie ein geografischer Index in MongoDB funktioniert
Ein geografischer Index ist genau wie ein normaler Datenbankindex, aber in zwei Dimensionen (oder manchmal drei, wenn Sie die Höhe berücksichtigen). Der Index in MongoDB ist ein so genannter Grid-Index (es gibt noch andere Indizes wie r-tree und quadtree, aber das ist vielleicht zu viel Information für einen Blog). Der Geo-Index von MongoDB kodiert einen Geohash auf einem standardmäßigen MongoDB b-tree. Geohashing (nicht zu verwechseln mit Geocaching) ist eine Methode zur Unterteilung eines Koordinatensystems in hierarchische, rasterförmige Buckets. Im Grunde wird ein Gebiet für jedes Bit in zwei Teile geteilt usw. Eine ausführliche Beschreibung finden Sie auf der Seite Gerade verfolge ich einige geospatiale Tweets und bin auf einen interessanten Tweet über eine neue Option gestoßen, mit der Sie einen geospatialen Index zu einer MongoDB hinzufügen können. Da ich in letzter Zeit einige Dinge mit Scala gemacht habe, beschloss ich, die Daten mit Scala und scamongo in MongoDB einzufügen. Leider bereitete mir der Scala-Treiber von scamongo für MongoDB zu viele Probleme, so dass ich auf den Java-Treiber umstieg. <!--more--> Ich habe keinerlei Erfahrung mit MongoDB, es hört sich nur cool an und die Leute sagen mir, dass es cool ist. Das reicht mir, um ein wenig zu recherchieren. Ich habe vor kurzem meine Bachelorarbeit über das Sammeln von GPS-Punkten und die Ermittlung von Laufrouten aus diesen Punkten abgeschlossen. Der größte Engpass in meiner Anwendung war das Zählen der Anzahl der Punkte im Umkreis eines Punktes. Sie müssen im Grunde alle Punkte daraufhin überprüfen, ob sie sich innerhalb des Radius befinden. Angenommen, Sie haben 10^6 Punkte (wie ich), dann sind (10^6)*(10^6) Schritte erforderlich. In meiner Schlussfolgerung habe ich empfohlen, einen Geodatenindex mit PostGIS zu verwenden, aber das ist nicht wirklich neu und cool, also versuchen wir es mit MongoDB. <h2>Was ist MongoDB</h2> <img class="alignleft size-full wp-image-4329" title="mongodb-logo" src=" target="_blank" rel="noopener">wikipedia-Seite. Ein Nachteil des Geohashings ist das Wrapping (-180 und 179 liegen z.B. sehr nahe beieinander). Dies kann durch eine Rastersuche nach dem ersten Scan gelöst werden. Es ist ein wenig vergleichbar mit der Art und Weise, wie Google Maps die Kartenbilder lädt, es beginnt mit dem Zentrum des Ansichtsfensters und dann werden die umliegenden Bereiche heruntergeladen. Unser Laapersveld Büro in einem Geohash: u179jbzdexru
Verwendung des Java-Treibers (in Scala)
Da der Scala-Treiber mir zu viele Probleme bereitet hat, habe ich den Java-Treiber ausprobiert. Sie können ihn von einem Github Repo herunterladen. Binden Sie einfach das jar in Ihr Scala-Projekt ein und schon kann es losgehen. Um alles aus der Sammlung foo abzufragen, benötigen Sie den folgenden Code:
val mongo = new Mongo( "localhost" , 27017 ) val db = mongo.getDB( "test" ) val coll = db.getCollection("foo") val cursor = db.find() while (cursor.hasNext) { println(cursor.next) }Eine große Warnung der API, die wichtig genug ist, um sie zu wiederholen, ist, dass toArray und length on cursor den Cursor in ein Array konvertieren, was eine sehr teure Operation sein kann, insbesondere bei großen Datenbanken!Einfügen der Daten
Nehmen wir einige prominente Daten aus meinem Datensatz:
{ "routeId" : "9327014.tcx", "id" : "1105409", "loc" : { "x" : 5.1400218, "y" : 52.0614276 } }Wie Sie sehen können, verwende ich ein verschachteltes Objekt, das wir später für den Index benötigen und das Ihnen zeigen soll, wie man verschachtelte Objekte erstellt (einfache Objekte sind einfach zu einfach ;) ).val doc = new BasicDBObject() doc.put("routeId", "9327014.tcx") doc.put("id", "1105409") val loc=new BasicDBObject() loc.put("x", 5.1400218) loc.put("y", 52.0614276) doc.put("loc", loc) coll.insert(doc) / coll is a DBCollection /Das ist alles! Keine Transaktionen zu übertragen oder Verbindungen zu schließen.Erstellen des Index
Das Erstellen des Indexes ist ganz einfach, es kann über den Java-Treiber oder die Befehlszeile erfolgen. Die Objekte in der Datenbank sehen wie folgt aus:
{ "routeId" : "activity_123456.tcx", "id" : " 1105402", "loc" : { "x" : 5.1415501, "y" : 52.0616409 } }Die x,y-Koordinaten sind in einen loc-Schlüssel verpackt, denn so mag es MongoDB. Die ersten beiden Spalten im loc-Objekt werden als x- und y-Koordinaten behandelt. Führen Sie auf der Befehlszeile db.foo.ensureIndex( { loc: "2d" } ) aus und Ihr Index wird erstellt. Das Erstellen des Index in Scala ist ebenfalls möglich:val index=new BasicDBObject() index.put("loc","2d") coll.ensureIndex(index) / coll is a DBCollection /Wenn Sie vergessen, einen Index zu erstellen, und räumliche Abfragen durchführen, kann das funktionieren, aber manchmal kam es zu seltsamen Abstürzen (und schlechter Leistung). Prüfen Sie dies also, bevor Sie MongoDB aus dem Fenster werfen ;-)Abfrage der Daten und Vergleich der Geschwindigkeit
Es ist jetzt möglich, eine Geodatenabfrage durchzuführen:
db.foo.find( { loc : { $near : [5.14,52.06] } } )Dies zeigt alle Punkte in der Nähe von 5.14, 52.06 an, sortiert nach der Entfernung zu diesem Punkt. Beachten Sie, dass standardmäßig maximal 100 Punkte zurückgegeben werden! Sie können dieses Problem lösen, indem Sie die Abfrage mit .limit(500) ergänzen, um maximal 500 Ergebnisse zu erhalten. Beachten Sie, dass Ihre Abfrage umso langsamer wird, je höher die Zahl ist. Seien Sie also vorsichtig mit der Erhöhung dieser Zahl. Ich wollte die Anzahl der Punkte innerhalb eines bestimmten Radius zählen. Hierfür müssen Sie der Abfrage ein Begrenzungskriterium hinzufügen:db.foo.find({"loc" : {"$within" : {"$center" : [[5.14,52.06], 0.0005]}>Beachten Sie, dass die Abgrenzungskriterien vor zwei Wochen hinzugefügt wurden (Version 1.3.4) und ich nicht sicher bin, ob dies bereits für die Produktion geeignet ist. Bei mir funktioniert es einwandfrei, aber Sie sollten etwas vorsichtiger sein, wenn Sie es wirklich verwenden. In Scala ist die Erstellung der Abfrage etwas umständlicher. Sie müssen ein Objekt konstruieren und eine Sammlung nach diesem Objekt abfragen (beachten Sie, dass dies dasselbe ist wie die erste Abfrage):val query = new BasicDBObject() val loc = new BasicDBObject() val near = new BasicDBList() near.put( "0", 5.15 ) near.put( "1", 52.069 ) loc.put("near", near) query.put("loc",loc) / coll is a DBCollection / coll.find(query).limit(50)Ich wollte einen Geschwindigkeitsvergleich machen, aber ich habe beschlossen, dass das noch nicht so wichtig ist. Da MongoDB und insbesondere der Geo-Index täglich verbessert werden, genügt es zu sagen, dass es bei großen Datensätzen (bei mir400.000 Punkte) viel schneller ist. Bei kleinen Datensätzen ( < 200.000) ist die Geschwindigkeit vergleichbar. Fazit
MongoDB ist cool und die Leute, die mir das gesagt haben, hatten Recht. Abgesehen davon, dass es cool ist, fand ich es wirklich toll. Ich habe meine Datenbank innerhalb weniger Minuten zum Laufen gebracht. Die Dokumentation ist sehr gut geschrieben und wird regelmäßig aktualisiert (die neuen Funktionen im Geo-Index wurden in der Dokumentation sofort aktualisiert, was ziemlich einzigartig ist). Scamongo war eine kleine Enttäuschung (wahrscheinlich auch dank meiner Beharrlichkeit und dem Wunsch nach schnellen Ergebnissen ;) ), es sieht vielversprechend aus, also werde ich es vielleicht in ein paar Monaten noch einmal versuchen. Der Geo-Index ist wirklich cool. Als ich vor ein paar Wochen anfing, damit herumzuspielen, fehlten noch einige Funktionen, aber innerhalb weniger Tage wurden diese Funktionen hinzugefügt (und ich musste einige Teile dieses Blogs neu schreiben ;) ). Vielen Dank an die Jungs von MongoDB, die mir coole Sachen zur Verfügung stellen, sie regelmäßig aktualisieren und dabei nicht einmal kaputt gehen!
Quellen
MongoDB Geohashing MongoDB Java-Treiber MongoDB Java-Treiber API
Verfasst von
Jeroen van Wilgenburg
Unsere Ideen
Weitere Blogs
Contact



