Que signifie NoSQL ? Ce terme désigne une nouvelle catégorie de bases de données qui n'utilisent ni la notion relationnelle des SGBDR classiques, ni le langage SQL. NoSQL signifie en fait « Not Only SQL ».
Ces bases de données sont vraiment nées en 2009 (certaines existent depuis la fin des années 80) en réaction à la complexité des bases de données classiques et pour une utilisation dans l’« informatique dans les nuages » (cloud computing) du fait des nécessités de rapidité, de performance et des besoins en termes de charge et de volume de données (à titre d'exemple, toute la gestion du magasin en ligne Amazon est effectuée avec une base NoSQL).
Elles ont été créées et/ou sont actuellement utilisées par Google, Facebook, Ebay, Amazon, Twitter et autres pour leurs besoins propres. Elles ont des noms encore peu connus comme Google Big Table (Google), HBase (implémentation Open Source de la précédente), Amazon Simpledb (Amazon), Cassandra (Facebook, Open Source - Apache), CouchDB (Open Source - Apache), MongoDB (Open Source), Redis (Open Source) ou Project Voldemort (Linkedin, Open Source) etc. Elles sont, dans leur grande majorité, Open Source.
Principes
L'explication la plus claire (pour moi) sur leurs principes et leur utilité est fournie dans « NoSQL : 5 minutes pour comprendre » (blog.neoxia.com/nosql-5-minutes-pour-comprendre/), site auquel je renvoie le lecteur.
Ces bases peuvent être classées en quatre grandes familles:
- Clé-valeur (Key-value Stores): les données sont représentées par un couple clé/valeur. La valeur peut être une simple chaîne de caractères ou un objet sérialisé (ex. Voldemort);
- Orienté document (Document Oriented Databases) : les données ne sont pas stockées en termes de tables, de clés et de relations. Ici l'objet de base est la donnée elle-même, généralement au format JSON ou XML. Elle peut donc contenir n'importe quel nombre de champs, et ce, quelle que soit sa longueur, et chaque champ peut stocker un nombre quelconque d'éléments. Le modèle permet, avec une seule clé, de récupérer un ensemble de données structurées de manière hiérarchique. La même opération dans le monde relationnel impliquerait plusieurs jointures (ex. Apache CouchDB, MongoDB, eXist pour les bases XML);
- Orienté colonne (Columnar Databases) : les données sont organisées en fonction des colonnes et non des lignes c'est-à-dire que les tables ont un nombre de colonnes dynamique (à la différence des tables dans les bases de données classiques). Chaque ligne a donc une clé unique, mais un nombre différent de colonnes, ce qui permet d'éviter les colonnes ayant des valeurs NULL (ex. Google Bigtable, Hbase)
- Orienté graphe : modèle plus spécialisé, basé sur la théorie des graphes, avec des noeuds et des relations (arêtes) et les propriétés qui leur sont rattachées (la principale solution est Neo4J, que j'utilise, mais qui ne sera pas abordée dans la suite).
Cette absence de structure ou de typage ont un impact important sur le requêtage. En effet, toute l’intelligence portée auparavant par les requêtes SQL devra être portée par l’applicatif qui interroge la BD. Néanmoins, la communication avec la BD se résumera aux opérations PUT, GET et DELETE ((blog.neoxia.com/nosql-5-minutes-pour-comprendre/)
Pour de plus amples renseignements, voir les sites nosql-database.org/, nosql.mypopescu.com/ et blogs.neotechnology.com/emil/2009/11/nosql-scaling-to-size-and-scaling-to-complexity.html
Je constate simplement qu'il y a une grande variété de bases, relativement peu documentées, comme si tout d'un coup chacun voulait « sa » solution. Il me semble que le principe fondamental est celui de clé-valeur. Une base peut, en plus, être de type orientée document et/ou orientée colonne. Ainsi, Cassandra pourrait être décrite en terme de paires clé-valeur dont l'architecture est orientée colonne (oreilly.com/catalog/0636920010852).
Le nom choisi, NoSQL ( il aurait peut-être mieux fallu utiliser NotSQL), et l'abandon de l'aspect relationnel ont provoqué et provoquent toujours des débats passionnels, acharnés, voire plus, dans le monde des bases de données, mais, les aborder déborde du cadre de cet article, car je ne suis pas un spécialiste. Tout ce qui m'intéresse est d'en tester une dans le domaine géospatial.
Leur utilisation dans le domaine géospatial
Deux articles récents donnent quelques réponses :
- « NoNoSQL » (http://blog.cleverelephant.ca/2010/03/nonosql.html) de Paul Ramsey, un des créateurs de Postgis et de la société OpenGeo;
- « NoSQL Databases: What Geospatial Users Need to Know » (http://www.directionsmag.com/article...to-know/164635)
Paul Ramsey passe en revue les avantages et désavantages de ces solutions et une des conclusions du deuxième article est :
One other point about NoSQL use, per Paul Ramsey, is that it's likely many developers will use NoSQL for spatial functions without really using a database. Instead, they will use a local or hosted service. He offers these examples: storing data in Google Fusion tables, using the SimpleGeo API, and using the spatial types in the Google App Engine. "These are all instances of using them [NoSQL databases] without using them. You see the limitations immediately in the kinds of queries you are able to do (not so many) but you reap the benefit of pushing the infrastructure responsibility off to someone else"
Une des solutions renseignées par ces auteurs est SimpleGeo.
SimpleGeo
SimpleGeo est une jeune startup américaine dont le but est de créer un « AppStore ou un iTunes » des données géolocalisées. Elle offre à cet effet une plateforme complète permettant de stocker ses données géolocalisées (« Storage Engine ») en offrant tous les outils nécessaires pour les exploiter sur les applications (« Context Engine »). Celles-ci sont surtout orientées vers le système Apple iOS4 de l'iPhone et de l'iPad.
Le principe est simple, chacun peut placer librement sur la plateforme ses données géolocalisées. Celles-ci peuvent ensuite être gardées pour soi, partagées librement ou vendues. Un « GeoMarketplace » est disponible à cet effet, permettant d’accéder aux nombreuses données des partenaires de SimpleGeo mais aussi de vendre ses propres données géographiques. L'entreprise se rémunère en fonction du nombre d'appels effectués par une application qui l'utilise : gratuit jusqu'à un million, 400 $ pour 2 millions d'appels et ainsi de suite.
Les informations géolocalisées de Twitter, Flickr, Brighkite, Wikipedia et autres sont déjà disponibles avec d'autres types de données comme la météorologie en temps réel.
À peine lancée, SimpleGeo rencontre un grand succès aux États-Unis. Son discours commercial fait mouche : il suffit de quelques lignes de code pour qu'une entreprise soit en mesure d'intégrer un service de géolocalisation à une application tournant sur iPhone.
Ce qui m'intéresse ici, c'est qu'ils utilisent un système NoSQL (Cassandra) pour stocker les données et qu'il est possible de traiter les requêtes avec Python (entre autres langages, JavaScript, PHP, Ruby, Objective - C etc.).
SimpleGeo et Python
Les trois modules à installer sont sur le Python Package Index ou Pypi (pypi.python.org/pypi). Il s'agit de simplegeo-places, simplegeo-context (pour consulter les données) et simplegeo-shared (pour entrer les données). Ils sont écrits en pur Python et peuvent donc être installés avec easy_install ou pip sur toutes les plateformes (suivant les versions de Python, il y a des dépendances). Les versions expérimentales sont disponibles par git.
Il est aussi nécessaire de s'enregistrer sur le site de SimpleGeo (gratuit), ce qui vous donnera 2 clés d'utilisation pour vos scripts (OAUTHKEY et SECRET).
Une fois fait, le principe est simple. Le concept de base est la notion de feature. Une feature représente un objet spatial et toutes les informations qui lui sont associées (météo, entreprise, division administrative, etc..). Elle est composée d'un identifiant (SimpleGeo handle), d'une géométrie (geometry, points, polygones) et d'un ensemble de données supplémentaires (property) avec toutes les informations disponibles. Elle est codée au format GeoJSON.
simplegeo-context
Un premier exemple pour illustrer le propos (en me basant sur le tutoriel (simplegeo.com/docs/tutorials/python): je voudrai connaître ce qu'il y a aux alentours du point de coordonnées WGS84 37.770918,-122.494383 (tous les exemples sont fournis aux États-Unis, car il n'y a pas encore beaucoup de données géolocalisées pour la France ou la Belgique). Pour cela on utilise le module simplegeo-context. Le résultat des requêtes est retourné au format JSON.
requête
import simplegeo.context as context # création d'un client client = context.Client('votre code OAUTHKEY', 'votre code SECRET') # interrogation de la base, qu'est ce qu'on trouve autour du point de coordonnées # 37.770918,-122.494383 en WGS84 resultat = client.get_context(37.770918,-122.494383) # quel est la structure Python du résultat obtenu ? type(resultat) <type 'dict'>
- 4013 lectures
Le résultat est une (très) longue chaîne au format JSON, non représentée ici, car son type Python est celui d'un dictionnaire qu'il est possible d'analyser plus facilement :
analyse
#clés du dictionnaire print resultat.keys() ['query', 'demographics', 'features', 'timestamp'] examen des valeurs print resultat.values() .... (beaucoup au format JSON #sérions le problème: # examen clé par clé print resultat.get('query') {'latitude': Decimal('37.770918'), 'longitude': Decimal('-122.494383')} # c'est la requête envoyée print resultat.get('demographics') {'metro_score': 10},... print resultat.get('timestamp') 1299359675.83 # nombre de feature associées len(resultat.get('features')) 14 # comme il y a beaucoup de features, examinons la première print resultat.get('features')[0] {'attribution': '(c) OpenStreetMap (http://openstreetmap.org/) and contributors', 'name': 'Golden Gate Park', 'license': 'http://creativecommons.org/licenses/by-sa/2.0/', 'bounds': [Decimal('-122.510828'), Decimal('37.764158'), Decimal('-122.453292'), Decimal('37.774642')], 'href': 'http://api.simplegeo.com/1.0/features/SG_7L9nQHjsporBjZUz8KVt5t_37.768985_-122.481775.json', 'abbr': None, 'handle': 'SG_7L9nQHjsporBjZUz8KVt5t_37.768985_-122.481775', 'classifiers': [{'category': 'Park', 'type': 'Public Place', 'subcategory': None}]}
- 4114 lectures
Il y a donc plusieurs features aux alentours de ce point, mais comment une feature est-elle structurée ?
structure d'une feature
type(resultat.get('features')[0]) <type 'dict'> # c'est donc un dictionnaire dont on peut examiner le contenu print resultat.get('features')[0].get('handle') SG_7L9nQHjsporBjZUz8KVt5t_37.768985_-122.481775 # c'est l'identifiant de la feature dans la base OpenGeo print resultat.get('features')[0].get('classifiers') [{'category': 'Park', 'type': 'Public Place', 'subcategory': None}] # c'est donc un Parc, avec comme limites (bounds) print resultat.get('features')[0].get('bounds'): [Decimal('-122.510828'), Decimal('37.764158'), Decimal('-122.453292'), Decimal('37.774642')]
- 4506 lectures
Comment faire maintenant si je veux retrouver la géométrie de ce parc pour l'utiliser avec d'autres modules Python comme Shapely ou OGR ?
examen d'un des éléments
# par requête directe à partir de son identifiant essai= client.get_feature('SG_7L9nQHjsporBjZUz8KVt5t_37.768985_-122.481775') type(essai) <type 'instance'> essai <simplegeo.shared.Feature instance at 0x10101d1b8> # ce n'est pas ce que l'on veut dir(essai) ['__doc__', '__init__', '__module__', 'coordinates', 'from_dict', 'from_json', 'geomtype', 'id', 'properties', 'strict_lon_validation', 'to_dict', 'to_json'] # la documentation indique bien qu'il faut utiliser ici to_dict ou (to_json) essai= client.get_feature('SG_7L9nQHjsporBjZUz8KVt5t_37.768985_-122.481775').to_dict() type(essai) <type 'dict'> print essai.keys() ['geometry', 'type', 'id', 'properties'] print essai.get('geometry') {'type': 'Polygon', 'coordinates': [[(Decimal('-122.5108283'), Decimal('37.7712413')), (Decimal('-122.4715533'), Decimal('37.7730133')), (Decimal('-122.468124'), Decimal('37.7731839')),...} print essai.get('properties') {'attribution': '(c) OpenStreetMap (http://openstreetmap.org/) and contributors', 'name': 'Golden Gate Park', 'license': 'http://creativecommons.org/licenses/by-sa/2.0/', 'private': False, 'href': 'http://api.simplegeo.com/1.0/features/SG_7L9nQHjsporBjZUz8KVt5t_37.768985_-122.481775.json', 'abbr': None, 'handle': 'SG_7L9nQHjsporBjZUz8KVt5t_37.768985_-122.481775', 'classifiers': [{'category': 'Park', 'type': 'Public Place', 'subcategory': None}]}
- 5057 lectures
Le résultat est ici bien fourni au format GeoJSON standard (geometry etc.) que l'on pourra utiliser avec les autres modules. En pratique, il est possible de voir que les résultats obtenus par cette requête sont tous les polygones contenant le point recherché.
Ce résultat donne une première idée de la manière dont les données sont structurées dans la base SimpleGeo et des traitements nécessaires pour exploiter les résultats obtenus.
Mais je voudrai aller plus loin, sans traitement supplémentaire de ma part, pour trouver, par exemple, les hôtels autour de ce point (qui ne sont, en théorie, pas des polygones). Il faut alors utiliser simplegeo-places
simplegeo-places
La requête est alors la suivante :
requête hotels
import simplegeo.places as places client = places.Client('votre code OAUTHKEY', 'votre code SECRET') # recherche des hotels autour de ce point resultats = client.search(37.788081, -122.402147, query='hotel') # type du resultat type(resultats) <type 'list'> print len(resultats) 25
- 4510 lectures
Il y a donc 25 hôtels répertoriés aux alentours du point.
premier résultat
print resultats[0].to_dict() {'geometry': {'type': 'Point', 'coordinates': (Decimal('-122.401619'), Decimal('37.788213'))}, 'type': 'Feature', 'id': 'SG_47XBr8HAPbh7yFrsnpHURX_37.788269_122.401510@1293134755', 'properties': {'website': 'www.sfpalace.com', 'distance': Decimal('0.048664400718345879'), 'name': 'Palace Hotel', 'tags': ['operation', 'eating'], 'country': 'US', 'private': False, 'classifiers': [{'category': 'Travel', 'type': 'Entertainment', 'subcategory': 'Hotels & Motels'}], 'phone': '+1 415 512 1111', 'state': 'CA', 'href': 'http://api.simplegeo.com/1.0/features/SG_47XBr8HAPbh7yFrsnpHURX_37.788269_122.401510@1293134755.json', 'postcode': '94105', 'address': '2 New Montgomery St', 'owner': 'simplegeo', 'city': 'San Francisco'}}
- 3837 lectures
Les résultats obtenus sont bien des points avec, dans les propriétés, le nom de l'hôtel, son site Web ou la distance du point à l'hôtel (l'unité de mesure n'est cependant pas spécifiée), et d'autres éléments. En utilisant son id (SG_47XBr8HAPbh7yFrsnpHURX_37.788269_-122.401510@1293134755), il est alors possible de le retrouver avec simple-context:
hôtel choisi
client2=context.Client('votre code OAUTHKEY', 'votre code SECRET') essai=client.get_feature('SG_47XBr8HAPbh7yFrsnpHURX_37.788269_-122.401510@1293134755').to_dict() print essai {'geometry': {'type': 'Point', 'coordinates': (Decimal('-122.401619'), Decimal('37.788213'))}, 'type': 'Feature', 'id': 'SG_47XBr8HAPbh7yFrsnpHURX_37.788269_122.401510@1293134755', 'properties': {'website': 'www.sfpalace.com', 'city': 'San Francisco', 'name': 'Palace Hotel', 'tags': ['operation', 'eating'], 'country': 'US', 'private': False, 'phone': '+1 415 512 1111', 'state': 'CA', 'href': 'http://api.simplegeo.com/1.0/features/SG_47XBr8HAPbh7yFrsnpHURX_37.788269_-122.401510@1293134755.json', 'postcode': '94105', 'address': '2 New Montgomery St', 'owner': 'simplegeo', 'classifiers': [{'category': 'Travel', 'type': 'Entertainment', 'subcategory': 'Hotels & Motels'}]}}
- 5026 lectures
Ici, plus de distance (qui a donc été calculée par la requête), c'est l'identifiant brut de l'hôtel en question avec en href l'URL pour obtenir le résultat avec un navigateur (au format JSON)
api.simplegeo.com/1.0/features/SG_47XBr8HAPbh7yFrsnpHURX_37.788269_-122.401510@1293134755.json
Une feature de base est donc structurée de la manière suivante :
- un élément de type geometry;
- un élément de type d'objet
- un element id, qui est la clé pour retrouver l'objet (SimpleGeo handle);
- un élément properties, avec les propriétés associées
Le reste, distance, requête, etc. est effectué par la base et les outils SimpleGeo. Il y a aussi moyen de combiner les requêtes de diverses manières comme :
results = client.search(40.016983, -105.27753, query='coffee', category='restaurant')
Création d'une feature dans mon espace personnel (module simplegeo-shared)
Ces résultats nous indiquent maintenant comment créer une feature:
création d'une feature
import simplegeo.shared, simplegeo.places from simplegeo.shared import Feature client = simplegeo.places.Client('votre code OAUTHKEY', 'votre code SECRET') properties = {"province":"","city":"Paris","name":"Tour Eiffel","country":"FR", "phone":"", "address":"7 Av Anatole France","postcode":"75007"} f = simplegeo.places.Feature((48.85940, 2.29416), properties=properties) client.add_feature(f) 'SG_41gn625SLWoHJOeoPYJ81b_48.859400_2.294160@1299419564'
- 3406 lectures
qui nous indique l’identifiant de l'objet créé. On peut maintenant vérifier que l'objet existe bien dans la base SimpleGeo
contrôle
# contrôle avec simplegeo.places print client.get_feature('SG_41gn625SLWoHJOeoPYJ81b_48.859400_2.294160@1299419564').to_dict() {'geometry': {'type': 'Point', 'coordinates': (Decimal('2.29416'), Decimal('48.8594'))}, 'type': 'Feature', 'id':'SG_41gn625SLWoHJOeoPYJ81b_48.859400_2.294160@1299419564', 'properties': {'city': 'Paris', 'name': 'Tour Eiffel', 'country': 'FR', 'private': 'false', 'href': 'http://api.simplegeo.com/1.0/features/SG_41gn625SLWoHJOeoPYJ81b_48.859400_2.294160@1299419564.json', 'postcode': '75007', 'address': '7 Av Anatole France', 'owner': '6338', 'classifiers': []}} # contrôle avec simplegeo.context client2 =simplegeo.context.Client(''votre code OAUTHKEY', 'votre code SECRET') print client2.get_feature('SG_41gn625SLWoHJOeoPYJ81b_48.859400_2.294160@1299419564').to_dict() {'geometry': {'type': 'Point', 'coordinates': (Decimal('2.29416'), Decimal('48.8594'))}, 'type': 'Feature', 'id': 'SG_41gn625SLWoHJOeoPYJ81b_48.859400_2.294160@1299419564', 'properties': {'city': 'Paris', 'name': 'Tour Eiffel', 'country': 'FR', 'private': 'false', 'href': 'http://api.simplegeo.com/1.0/features/SG_41gn625SLWoHJOeoPYJ81b_48.859400_2.294160@1299419564.json', 'postcode': '75007', 'address': '7 Av Anatole France', 'owner': '6338', 'classifiers': []}}
- 3417 lectures
Et pour boucler la boucle avec la requête initiale
contrôle final avec la requête initiale
import simplegeo.context as context client = context.Client('votre code OAUTHKEY', 'votre code SECRET') client.get_context(48.859400,2.294160) # etc. # le processus ayant été expliqué, je vais directement contrôler si mon objet est bien # dans la base SimpleGeo avec la requête initiale essai= client.get_feature('SG_41gn625SLWoHJOeoPYJ81b_48.859400_2.294160@1299419564').to_dict() print essai {'geometry': {'type': 'Point', 'coordinates': (Decimal('2.29416'), Decimal('48.8594'))}, 'type': 'Feature', 'id':'SG_41gn625SLWoHJOeoPYJ81b_48.859400_2.294160@1299419564', 'properties': {'city': 'Paris', 'name': 'Tour Eiffel', 'country': 'FR', 'private': 'false', 'href': 'http://api.simplegeo.com/1.0/features/SG_41gn625SLWoHJOeoPYJ81b_48.859400_2.294160@1299419564.json', 'postcode': '75007', 'address': '7 Av Anatole France', 'owner': '6338', 'classifiers': []}}
- 3846 lectures
Autre manière de travailler
Il y a aussi moyen de travailler de manière différente, plus classique pour les SIGistes. Il est en effet possible de créer classiquement une couche (Layer) et d'y ajouter des éléments (Records). La couche doit cependant être créée à partir de l'interface graphique du site SimpleGeo. Les Records peuvent être rentrés en Python:
création d'un record
from simplegeo import Record r = Record('com.simplegeo.macouche', '4', 48.859400,2.294160) #nom de la couche,identifiant,latitude, longitude) client.add_record(r)
- 4214 lectures
Ceci permet d'importer directement les données depuis des shapefiles ou des fichiers CSV dans la base SimpleGeo (avec des scripts Python) mais seuls les points sont supportés pour l'instant (SimpleGeo travaille sur l'importation des polygones):
- shapefiles: « How to import 35,000 records in under two minutes » (developers.simplegeo.com/blog/2010/11/30/import-records/)
- fichiers CSV : « Finding (or Adding) Features in SimpleGeo Places » (developers.simplegeo.com/blog/2010/12/29/finding-or-adding-your-pois-in-simplegeo-places/)
Comment exploiter les résultats en ligne (Web Mapping) ?
Rien de plus simple, puisque SimpleGeo a développé sa propre librairie JavaScript Polymaps (Open Source) à cet effet :
developers.simplegeo.com/blog/2011/01/14/how-to-display-simplegeo-places-on-a-map/
Conclusions
Et voilà, que dire d'une base NoSQL ?
Sans vouloir entrer dans les controverses, je constate, en pratique, que SimpleGeo marche très bien. Rapide, sans nécessité de module spécialisé en Python (le module JSON est en standard depuis la version 2.6 et pour les versions antérieures il existe le module SimpleJSON), la base utilisée par SimpleGeo ne demande que des traitements simples pour être exploitée (contrairement aux bases de données relationnelles classiques). La seule chose qui me gêne un peu est la relative « verbosité » du format JSON-GeoJSON. On constate aussi que la plupart des traitements doivent être faits par l'application qui reçoit les données.
Il ne faut pas oublier que cette technologie est encore jeune et doit évoluer. Elle n'est certainement pas adaptée à tous les cas rencontrés et il est difficile, pour un non-spécialiste, de s'y retrouver dans la jungle des solutions... Il ne faut donc pas nécessairement sauter dedans à pieds joints... Pour l'instant, je la vois plutôt comme un outil complémentaire. On peut très bien utiliser l'un et l'autre et non, exclusivement, l'un ou l'autre.
L'aspect économique joue aussi, ainsi le fondateur de SimpleGeo:
Joe Stump of SimpleGeo concedes it's possible to use SQL/relational databases to do what NoSQL databases can. For him, the choice to use NoSQL is about money.
'I guess what I'm saying is that my decision to use NoSQL, and I'm guessing others' decisions to do so, has less to do with the fact that we can't squeeze a few thousand writes a second out of MySQL and more to do with management and cost overhead. NoSQL solutions allow us to serve absurd amounts of data for a really, really low price.'
www.directionsmag.com/articles/nosql-databases-what-geospatial-users-need-to-know/164635
De manière plus générale, pour ceux que ça intéresse en Python, il existe 2010.rmll.info/L-acces-aux-bases-NoSql-en-python.html, qui a pour but de présenter les principales bases NoSQL accessibles en Python, avec un tutoriel d’installation, une modélisation de schéma et un exemple d’application accédant aux données. nosql.mypopescu.com/post/276069660/nosql-libraries, déjà cité, indique pour chaque base de données les modules/librairies Python, Perl, C, NET#, Ruby, etc. disponibles.
Et enfin, pour vraiment débuter, il y a deux sympathiques petits modules Python,
- y_serial, qui permet de s'initier aux bases NoSQL de type clé-valeur avec..., SQLite;
- littletable, qui fait de même avec les bases de type orienté colonne.
Tous les traitements ont été effectués sur Mac OS X avec Python 2.6.1.
Site officiel : SimpleGeo
Site officiel : GeoJSON
Site officiel : PolyMaps
Site officiel : Cassandra (Apache)
Site officiel : y-serial (module Python)
Site officiel : littletable (module Python)
Autres Liens : NoSQL (Wikipedia)
Autres Liens : Cassandra (Wikipedia)
Autres Liens : Base de données orientée colonnes (Wikipedia)
Autres Liens : Python pour les Sigistes: comment installer un module externe (geojson, shapely ou gdal/ogr, par exemple) ?
licence Creative Commons Paternité-Pas d'Utilisation Commerciale-Partage des Conditions Initiales à l'Identique Commerciale 2.0 France
Commentaires
sympathiques modules Python
y_serial, qui permet de s'initier aux bases NoSQL de type clé-valeur:
https://github.com/rsvp/yserial
Et pour un manuel d'instruction:
http://nbviewer.ipython.org/urls/git.io/yserial-HOWTO.ipynb
Félicitations
Super article bien expliqué et documenté.
C'est un vrai plaisir de lire tes rubriques !
Arnaud
Poster un nouveau commentaire