back to basics, webinar 4: indicizzazione avanzata, indici testuali e geospaziali
TRANSCRIPT
MongoDB Europe 2016Old Billingsgate, London
15 November
mongodb.com/europe
Massimo BrignoliPrincipal Solution Architect, [email protected]@massimobrignoli
Back to Basics 2016 : Webinar 4
Indicizzazione AvanzataIndici Geografici e Testuali
Riassunto• Webinar 1 – Introduzione a NoSQL
– I vari tipi di database NoSQL– Che tipo di database è MongoDB
• Webinar 2 – La nostra prima applicazione– Creare database e collection– Operazioni CRUD– Indici e Explain
• Webinar 3 – Schema Design– Schema Dinamico– Approcci all’incapsulamento– Esempi
Indexing• Un modo efficiente per ricercare dei dati usando il loro
valore• Evitare scansione completa di collection
I Database Tradizionali Usano BTREE• … E anche MongoDB...
Ricerche, Inserimenti, Cancellazioni in O(Log(n))
Creazione di un Indice Semplicedb.coll.createIndex( { fieldName : <Direction> } )
Nome del Database
Nome della Collection
Comando
Nome del campo(i) da indicizzare
Ascendente: 1 Discendente: -1
Altri due tipi di Indice• Indice Full Text– Permette la ricerca all’interno del testo di un campo (Lucene,
Solr e Elastic Search)• Indice Geospaziale– Permette la ricerca per posizione geografica (e.g. tutte le
persone vicino a me)• Questi indici non usano Btree
Indici Full Text• Un “inverted index” di tutte le parole contenute in un singolo
campo (si può creare solo un indice full text per ogni collection)
{ “comment” : “I think your blog post is very interesting and informative. I hope you will post more info like this in the future” }>> db.posts.createIndex( { “comments” : “text” } )
MongoDB Enterprise > db.posts.find( { $text: { $search : "info" }} ){ "_id" : ObjectId(“…"), "comment" : "I think your blog post is very interesting and informative. I hope you will post more info like this in the future" }MongoDB Enterprise >
Parametri dell’IndiceMongoDB Enterprise > db.posts.getIndexes()...
{"v" : 1,"key" : {
"_fts" : "text","_ftsx" : 1
},"name" : "comment_text","ns" : "test.posts","weights" : {
"comment" : 1},"default_language" : "english","language_override" : "language","textIndexVersion" : 3
}
Nel Log del ServerI INDEX [conn275] build index on: test.posts properties: { v: 1, key: { _fts: "text", _ftsx: 1 }, name: "comment_text", ns: "test.posts", weights: { comment: 1 }, default_language: "english", language_override: "language", textIndexVersion: 3 }}I INDEX [conn275] building index using bulk methodI INDEX [conn275] build index done. scanned 3 total records. 0 secs
Alcuni Esempi in Dettaglio>> db.posts.insert( { "comment" : "Red yellow orange green" } )>> db.posts.insert( { "comment" : "Pink purple blue" } )>> db.posts.insert( { "comment" : "Red Pink" } )
>> db.posts.find( { "$text" : { "$search" : "Red" }} ){ "_id" : ObjectId(“…”), "comment" : "Red yellow orange green" }{ "_id" : ObjectId( »…"), "comment" : "Red Pink" }>> db.posts.find( { "$text" : { "$search" : "Red Green" }} ){ "_id" : ObjectId(« …"), "comment" : "Red Pink" }{ "_id" : ObjectId(« …"), "comment" : "Red yellow orange green" }>> db.posts.find( { "$text" : { "$search" : "red" }} ) # <- Case Insensitve{ "_id" : ObjectId(“…"), "comment" : "Red yellow orange green" }{ "_id" : ObjectId(«…”), "comment" : "Red Pink" }>>
Usare I Pesi• Possiamo assegnare pesi diversi ai vari campi
nell’indice testuale• Ad esempio posso voler favorire i tag rispetto ai
commenti• Quindi incremento il peso del campo tags
>> db.blog.createIndex( { comment: "text", tags : "text” }, { weights: { comment: 5, tags : 10 }} )• Ora la ricerca favorirà il campo tags
$textscore• Possiamo usare il lo score risultante per ordinare i
risultati
>> db.posts.find( { "$text" : { "$search" : "Red" }}, { score: { $meta: "textScore" }} ).sort( { score: { $meta: "textScore" } } )
{ "_id" : …, "comment" : "hello", "tags" : "Red green orange", "score" : 6.666666666666666 }{ "_id" : …, "comment" : "Red Pink", "score" : 3.75 }{ "_id" : …, "comment" : "Red yellow orange green", "score" : 3.125 }>>
Altri Parametri• Language : Scegli la lingua che vuoi usare in ricerca, ad
esempio:– $language : Spanish
• Abilita la ricerca case sensitive– $caseSensitive : True (default false)
• Supporta i caratteri accentati (diacritic sensitive search ad esempio café è diverso da cafe )– $diacriticSensitive : True (default false)
Indici Geospaziali
Indici Geospaziali• MongoDB supporta indici sferici 2D• Permette ad un utente di rappresentazione una
posizione sulla terra (approssimata ad una sfera)• Le coordinate sono memorizzate in un formato
GeoJSON• L’indice geospaziale supporta un sottoinsieme
delle operazioni GeoJSON• L’indice è basato su una rappresentazione
QuadTree • L’indice è basato sullo standard WGS 84
Coordinate• Le coordinate sono rappresentate con longitudine e
latitudine• longitudine– Misurata dal meridiano di Greenwich a Londra (0 gradi). Le
posizione ad est arrivano fino a 180 gradi, mentre quelle ad ovest si esprimono con un numero negativo
• Latitudine– Misurata dall’equatore verso nord e sud (da 0 a 90 nord, da 0 a -
90 sud)• Le coordinate in MongoDB sono memorizzate con
l’ordine longitutine/latitudine• Coordinate in Google sono memorizzate invertite
Versioni dell’Indice 2DSphere• Versione 1 : prima di MongoDB 2.4• Versione 2 : da MongoDB 2.6 in poi• Versione 3 : da MongoDB 3.2 in poi• Parlaremo solo della Versione 3 in questo webinar
Creare un Indice 2DSpheredb.collection.createIndex ( { <location field> : "2dsphere" } )
• Il campo di posizione deve contenere coordinate oppure una struttura dati GeoJSON
Esempio
>> db.test.createIndex( { loc : "2dsphere" } ){
"createdCollectionAutomatically" : false,"numIndexesBefore" : 1,"numIndexesAfter" : 2,"ok" : 1
}
Output>> db.test.getIndexes()[
{"v" : 1,"key" : {
"loc" : "2dsphere"},"name" : "loc_2dsphere","ns" : "geo.test","2dsphereIndexVersion" : 3
}]>>
Usiamo una Semplice Base Dati per Sperimentare le Query Geografiche
• Cerchiamo i ristoranti a Manhattan• Scarichiamo I dati di due collection
– https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/neighborhoods.json– https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/restaurants.json
• Importiamole dentro MongoDB invocando da shell– mongoimport –c neighborhoods –d geo neighborhoods.json– mongoimport –c restaurants –d geo restaurants.json
Documento dei QuartieriMongoDB Enterprise > db.neighborhoods.findOne(){
"_id" : ObjectId("55cb9c666c522cafdb053a1a"),"geometry" : {
"coordinates" : [[
[-73.94193078816193,40.70072523469547
], ...
[-73.94409591260093,40.69897295461309
], ]
"type" : "Polygon"},"name" : "Bedford"
}
Documento dei RistorantiMongoDB Enterprise > db.restaurants.findOne(){
"_id" : ObjectId("55cba2476c522cafdb053adf"),"location" : {"coordinates" : [-73.98241999999999,40.579505],"type" : "Point"},"name" : "Riviera Caterer"
}MongoDB Enterprise >
Per visualizzarlo su google maps
ricordatevi di invertire le coordinate
Aggiungiamo gli IndiciMongoDB Enterprise > db.restaurants.createIndex({ location: "2dsphere" }){
"createdCollectionAutomatically" : false,"numIndexesBefore" : 1,"numIndexesAfter" : 2,"ok" : 1
}MongoDB Enterprise > db.neighborhoods.createIndex({ geometry: "2dsphere" }){
"createdCollectionAutomatically" : false,"numIndexesBefore" : 1,"numIndexesAfter" : 2,"ok" : 1
}MongoDB Enterprise >
Usiamo $geoIntersects per trovare I Quartieri
• Assumiamo di essere a -73.93414657, 40.82302903• In quale quartiere siamo? Usiamo $geoIntersects
db.neighborhoods.findOne({ geometry: { $geoIntersects: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ]}}}})
Risultato{
"geometry" : { ”coordinates" : [
[-73.9338307684026,40.81959665747723
], ...
[-73.93383000695911,40.81949109558767
] ]
"type" : "Polygon"},"name" : "Central Harlem North-Polo Grounds"
}
Troviamo I Ristoranti a 350mdb.restaurants.find({ location: { $geoWithin: { $centerSphere: [ [ -73.93414657, 40.82302903 ], 0.35 / 6378.1 ] } } })
Distanza in KM Dividete per il raggio
della terra per convertire in radianti
Risultati – (Projected){ "name" : "Gotham Stadium Tennis Center Cafe" }{ "name" : "Chuck E. Cheese'S" }{ "name" : "Red Star Chinese Restaurant" }{ "name" : "Tia Melli'S Latin Kitchen" }{ "name" : "Domino'S Pizza" }
• Senza projection
{ "_id" : ObjectId("55cba2476c522cafdb0550aa"), "location" : { "coordinates" : [ -73.93795159999999, 40.823376 ], "type" : "Point" }, "name" : "Domino'S Pizza" }
Riassunto delle Operazioni• $geoIntersect: Trova aree o punti che si sovrappongono
o sono adiaicenti• $geoWithin: Trova aree che contengono un punto• $geoNear: Restituisce le posizioni geografiche in ordine di
distanza crescente
Riassunto• Text Indexes : Ricerca full text su tutti I campi testo di
una collection• Geospatial Indexes : Ricerca per posizione, per
intersezione o per distanza a partire da un punto
Prossimo Webinar : Introduzione ad Aggregation Framework
• Consente agli sviluppatori di– Modificare, trasformare ed estrarre dati.– Applicare funzioni analitiche standard, dai totali e le medie fino
alla deviazione standard.• Lo vedrete in azione su un set di dati pubblici.
19 Luglio 2016, 11:00 CET.