12. Notre système (I)
Recherche
Paris
http://www.parisnet.com/images/parismap_new.gif
4
13. Notre système (I)
Recherche
Paris
http://www.parisnet.com/images/parismap_new.gif
4
14. Notre système (I)
Recherche
Bistro
Paris
http://www.parisnet.com/images/parismap_new.gif
4
15. Notre système (I)
Recherche
Bistro
Bistro du Bastille
Bistro de Mer
Mon grand Bistro
MongoDB bistro
Boulanger Bistro
Jean Bistro votre Plombier
...
Paris
http://www.parisnet.com/images/parismap_new.gif
4
16. Notre système (II)
POI : Point of Interest
TOUTE LA FRANCE !!!
http://lh3.ggpht.com/_ViFLVzjIPSk/TR7lvqmu8lI/AAAAAAAAEAg/dHEuf1Dvz6o/Map_France_French-cities.gif
5
17. Notre système (II)
POI : Point of Interest
Monuments
TOUTE LA FRANCE !!!
http://lh3.ggpht.com/_ViFLVzjIPSk/TR7lvqmu8lI/AAAAAAAAEAg/dHEuf1Dvz6o/Map_France_French-cities.gif
5
18. Notre système (II)
POI : Point of Interest
Monuments
Mairies
TOUTE LA FRANCE !!!
http://lh3.ggpht.com/_ViFLVzjIPSk/TR7lvqmu8lI/AAAAAAAAEAg/dHEuf1Dvz6o/Map_France_French-cities.gif
5
19. Notre système (II)
POI : Point of Interest
Monuments
Mairies
Médecins
TOUTE LA FRANCE !!!
http://lh3.ggpht.com/_ViFLVzjIPSk/TR7lvqmu8lI/AAAAAAAAEAg/dHEuf1Dvz6o/Map_France_French-cities.gif
5
20. Notre système (II)
POI : Point of Interest
Monuments
Mairies
Médecins
Restaurants
TOUTE LA FRANCE !!!
http://lh3.ggpht.com/_ViFLVzjIPSk/TR7lvqmu8lI/AAAAAAAAEAg/dHEuf1Dvz6o/Map_France_French-cities.gif
5
21. Notre système (II)
POI : Point of Interest
Monuments
Mairies
Médecins
Restaurants
...
TOUTE LA FRANCE !!!
http://lh3.ggpht.com/_ViFLVzjIPSk/TR7lvqmu8lI/AAAAAAAAEAg/dHEuf1Dvz6o/Map_France_French-cities.gif
5
22. Notre système (II)
POI : Point of Interest
Monuments
Mairies
Médecins
Restaurants
...
mais aussi le mode contributif
pour ajouter mes lieux
personnels ...
TOUTE LA FRANCE !!!
http://lh3.ggpht.com/_ViFLVzjIPSk/TR7lvqmu8lI/AAAAAAAAEAg/dHEuf1Dvz6o/Map_France_French-cities.gif
5
25. Notre système (III)
En bref :
Modèle de données très hétérogène
Relations simples (1 - 1) et absence de
transactions complexes
6
26. Notre système (III)
En bref :
Modèle de données très hétérogène
Relations simples (1 - 1) et absence de
transactions complexes
Recherche par mot-clé (full-text à venir)
6
27. Notre système (III)
En bref :
Modèle de données très hétérogène
Relations simples (1 - 1) et absence de
transactions complexes
Recherche par mot-clé (full-text à venir)
Recherche spatiale
6
28. Notre système (III)
En bref :
Modèle de données très hétérogène
Relations simples (1 - 1) et absence de
transactions complexes
Recherche par mot-clé (full-text à venir)
Recherche spatiale
Fort trafic et performance en temps réel
6
29. Notre système (III)
En bref :
Modèle de données très hétérogène
Relations simples (1 - 1) et absence de
transactions complexes
Recherche par mot-clé (full-text à venir)
Recherche spatiale
Fort trafic et performance en temps réel
Scalabilité horizontale
6
30. Notre système (III)
En bref :
Modèle de données très hétérogène
Relations simples (1 - 1) et absence de
transactions complexes
Recherche par mot-clé (full-text à venir)
Recherche spatiale
Fort trafic et performance en temps réel
Scalabilité horizontale
Délais très courts de livraison
6
31. Notre système (III)
En bref :
Modèle de données très hétérogène
Relations simples (1 - 1) et absence de
transactions complexes
Recherche par mot-clé (full-text à venir)
Recherche spatiale
Fort trafic et performance en temps réel
Scalabilité horizontale
Délais très courts de livraison
Equipe Java
6
32. Notre système (IV)
HTTP Java Driver
...
REST BD de POI
Services XML
CSV
SOAP
REST
Sources ...
http://www.openclipart.org/
7
33. Geoentity Java
public class Geoentity { public class Message {
private String id; private String id;
private long updated; private String text;
private String name;
1 .. N private String userId;
private String userId; private long created;
}
private Set keywords;
private List<Message> messages; public class Location {
1 .. 1
private Location location; private double lat;
}
private double lng;
}
8
34. Geoentity Java
public class Geoentity { public class Message {
private String id; private String id;
private long updated; private String text;
private String name;
1 .. N private String userId;
private String userId; private long created;
}
private Set keywords;
private List<Message> messages; public class Location {
1 .. 1
private Location location; private double lat;
}
private double lng;
}
Une collection : «places»
8
36. Configurer la connexion (I)
Maven
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>2.5</version>
</dependency>
Suivez le projet sur GitHub !
9
37. Configurer la connexion (II)
IoC : Guice
@Singleton
public class MongoDB {
private Mongo mongo;
private DB db;
@Inject
public MongoDB(String host, int port, int nb) {
MongoOptions mongoOpts = new MongoOptions();
mongoOptions.connectionsPerHost = nb;
try {
mongo = new Mongo(new ServerAddress(host, port), mongoOpts);
} catch (Exception e) {
throw new RuntimeException(e);
}
db = mongo.getDB(DATABASE_NAME);
}
}
10
38. Configurer la connexion (II)
IoC : Guice
@Singleton
public class MongoDB {
private Mongo mongo;
private DB db;
@Inject Attention !
public MongoDB(String host, int port, int nb) {
MongoOptions mongoOpts = new MongoOptions();
mongoOptions.connectionsPerHost = nb;
try {
mongo = new Mongo(new ServerAddress(host, port), mongoOpts);
} catch (Exception e) {
throw new RuntimeException(e);
}
db = mongo.getDB(DATABASE_NAME);
}
}
10
39. Objet - BSON (I)
API driver Java (notre choix initial)
public DBObject toBasicDBObject() {
BasicDBObject dbObject = new BasicDBObject();
if (this.id != null && ObjectId.isValid(this.id)) {
dbObject.put("_id", new ObjectId(this.id));
}
dbObject.put("name", this.name);
dbObject.put("keywords", new BasicDBObject(this.hobbies));
...
dbObject.put("messages", messages);
return dbObject;
}
11
40. Objet - BSON (II)
Morphia (notre choix actuel)
@Entity(noClassnameStored = true) @Embedded
public class Geoentity { public class Message {
private String id; private String id;
...
private long updated;
... // get - set
private Set keywords; }
@Embedded
@Embedded
public class Location {
private List<Message> messages;
private double lat;
@Embedded
private Location location;
private double lng;
//get-set
//get - set
}
}
12
41. Objet - BSON (III)
Morphia Object Wrapper
@Singleton
public class MapperMorphia {
private Morphia morphia;
@Inject
public MapperMorphia() {
this.morphia = new Morphia();
this.morphia.mapPackage("com.myproject.model");
}
public <T extends Object> T from(Class<T> entityClass, DBObject dbObject) {
return this.morphia.fromDBObject(entityClass, dbObject);
}
public <T extends Object> DBObject toDBObject(T modelObject) {
return this.morphia.toDBObject(modelObject);
}
}
13
42. Objet - BSON (III)
Morphia Object Wrapper
@Singleton
public class MapperMorphia {
private Morphia morphia;
@Inject
public MapperMorphia() {
this.morphia = new Morphia();
this.morphia.mapPackage("com.myproject.model"); Attention !
}
public <T extends Object> T from(Class<T> entityClass, DBObject dbObject) {
return this.morphia.fromDBObject(entityClass, dbObject);
}
public <T extends Object> DBObject toDBObject(T modelObject) {
return this.morphia.toDBObject(modelObject);
}
}
13
43. Objet - BSON (IV)
Morphia Wrapper ... Re-Wrapper !
public class GeoentityMapper {
private MapperMorphia mapperMorphia;
@Inject
public GeoentityMapper(MapperMorphia mapperMorphia) {
this.mapperMorphia = mapperMorphia;
}
public BasicDBObject map(Geoentity geoentity) {
BasicDBObject dbObject = (BasicDBObject) mapperMorphia.toDBObject(geoentity);
if (!Strings.isNullOrEmpty(geoentity.getId())) {
dbObject.put("_id", new ObjectId(geoentity.getId()));
}
return dbObject;
}
public Geoentity map(BasicDBObject rootObject) {
return mapperMorphia.fromDBObject(Geoentity.class, rootObject);
}
}
14
44. Objet - BSON (IV)
Morphia Wrapper ... Re-Wrapper !
public class GeoentityMapper {
private MapperMorphia mapperMorphia;
@Inject
public GeoentityMapper(MapperMorphia mapperMorphia) {
this.mapperMorphia = mapperMorphia;
}
Pour ObjectId -> String !
public BasicDBObject map(Geoentity geoentity) {
BasicDBObject dbObject = (BasicDBObject) mapperMorphia.toDBObject(geoentity);
if (!Strings.isNullOrEmpty(geoentity.getId())) {
dbObject.put("_id", new ObjectId(geoentity.getId()));
}
return dbObject;
}
public Geoentity map(BasicDBObject rootObject) {
return mapperMorphia.fromDBObject(Geoentity.class, rootObject);
}
}
14
45. CRUD (I)
Créer un repository
public class GeoentityRepository {
private final MongoDB mongoDB;
private final GeoentityMapper geoentityMapper;
@Inject
public GeoentityRepository(MongoDB mongoDB, GeoentityMapper geoentityMapper) {
this.mongoDB = mongoDB;
this.geoentityMapper = geoentityMapper;
}
protected DBCollection getCollection() {
DBCollection collection = mongoDB.getDB().getCollection(NAME);
return collection;
}
// autres méthodes ici
}
15
51. CRUD (V)
Modifier un message et la date de mise à jour
> db.places.update({"_id" : ObjectId("foo") , "messages.id" :
"bar" }, {$set : { "message.$.text" : "my new text", "updated" :
"dateFoo"} })
DBObject searchQuery =
QueryBuilder.start("_id").is(new ObjectId(id))
.and("messages.id").is(messageId)
.get();
BasicDBObject updateObject =
new BasicDBObject("messages.$.text", "my new text");
updateObject.put("updated", Calendar.getInstance().getTimeInMillis());
DBObject modificatorQuery = new BasicDBObject("$set", updateObject);
getCollection().update(searchQuery, modificatorQuery);
19
52. Recherche textuelle
Recherche la valeur dans «name» OR «keywords»
> db.places.find({"name" : "foo" , $or : [{"keywords" : "bar"}]})
List<Geoentity> result = new ArrayList<Geoentity>();
QueryBuilder.start().queryBuilder.put("name").is("foo");
queryBuilder.or(new BasicDBObject("keywords", "bar"));
DBCursor dbCursor = queryBuilder.get().find();
while (dbCursor.hasNext()) {
result.add(geoentityMapper.map(dbCursor.next()));
}
20
53. Recherche Spatiale (II)
Near Search
public List<Geoentity> circleSearch(Coordinate coordinate,
Double radius) {
QueryBuilder queryBuilder = QueryBuilder.start().and(LOCATION)
.near(coordinate.getLatitude(),
coordinate.getLongitude(), radius);
...
getCollection().find( queryBuilder.get()) )
.limit(100)
.sort("importance");
21
54. Recherche Spatiale (II)
Near Search
35.000 éléments
public List<Geoentity> circleSearch(Coordinate coordinate,
Double radius) {
QueryBuilder queryBuilder = QueryBuilder.start().and(LOCATION)
.near(coordinate.getLatitude(),
coordinate.getLongitude(), radius);
...
getCollection().find( queryBuilder.get()) )
.limit(100)
.sort("importance");
21
55. Recherche Spatiale (II)
Near Search
limit(100) chargera 100
35.000 éléments et sort(«champ») triera les résultats
public List<Geoentity> circleSearch(Coordinate coordinate,
Double radius) {
QueryBuilder queryBuilder = QueryBuilder.start().and(LOCATION)
.near(coordinate.getLatitude(),
coordinate.getLongitude(), radius);
...
getCollection().find( queryBuilder.get()) )
.limit(100)
.sort("importance");
21
56. Recherche Spatiale (I)
BOX ou Circle Search
public List<Geoentity> boxSearch (Coordinate bottomLeft,
Coordinate topRight) {
QueryBuilder queryBuilder =
QueryBuilder.start().and(LOCATION)
.withinBox(bottomLeft.getLatitude(),
bottomLeft.getLongitude(),
topRight.getLatitude(),
topRight.getLongitude());
getCollection().find(queryBuilder.get()))
.limit(100)
22
57. Recherche Spatiale (I)
BOX ou Circle Search
public List<Geoentity> boxSearch (Coordinate bottomLeft,
Coordinate topRight) {
QueryBuilder queryBuilder =
QueryBuilder.start().and(LOCATION)
.withinBox(bottomLeft.getLatitude(),
bottomLeft.getLongitude(),
topRight.getLatitude(),
topRight.getLongitude());
getCollection().find(queryBuilder.get()))
.limit(100)
.sort("importance");
22
59. Recherche Spatiale (I)
BOX ou Circle Search
sort() charge les 35.000 éléments.
35.000 éléments Index 2D trie uniquement par
distance
public List<Geoentity> boxSearch (Coordinate bottomLeft,
Coordinate topRight) {
QueryBuilder queryBuilder =
QueryBuilder.start().and(LOCATION)
.withinBox(bottomLeft.getLatitude(),
bottomLeft.getLongitude(),
topRight.getLatitude(),
topRight.getLongitude());
getCollection().find(queryBuilder.get()))
.limit(100)
.sort("importance");
22
60. Indexation (I)
Avant de chercher, les indexes doivent exister
Index mot-clé
DBObject indexObject = BasicDBObjectBuilder.start()
.add("name", 1)
.add("updated", -1).get();
getCollection().ensureIndex(indexObject);
23
61. Indexation (II)
Index 2D
▶ valeur «2D»
▶ toujours le premier
public class Geoentity { public class Location {
private Location location; private double lat;
} private double lng;
}
DBObject indexObject2d = BasicDBObjectBuilder.start()
.add(LOCATION, "2d")
.add("keywords", 1).get();
getCollection().createIndex(indexObject2d);
24
62. Indexation (II)
Index 2D
▶ valeur «2D»
▶ toujours le premier
public class Geoentity { public class Location {
private Location location; private double lat;
} private double lng;
private double alt;
}
DBObject indexObject2d = BasicDBObjectBuilder.start()
.add(LOCATION, "2d")
.add("keywords", 1).get();
getCollection().createIndex(indexObject2d);
24
63. Indexation (II)
Index 2D
▶ valeur «2D»
▶ toujours le premier L’indexation n’aura pas d’effet
public class Geoentity { public class Location {
private Location location; private double lat;
} private double lng;
private double alt;
}
DBObject indexObject2d = BasicDBObjectBuilder.start()
.add(LOCATION, "2d")
.add("keywords", 1).get();
getCollection().createIndex(indexObject2d);
24
66. Conclusions
Prise en main de MongoDB rapide et ludique
Montée en compétence rapide
25
67. Conclusions
Prise en main de MongoDB rapide et ludique
Montée en compétence rapide
Adaptation naturelle à la philosophie
25
68. Conclusions
Prise en main de MongoDB rapide et ludique
Montée en compétence rapide
Adaptation naturelle à la philosophie
Test unitaires / d’intégration sont plus faciles à
maintenir
25
69. Conclusions
Prise en main de MongoDB rapide et ludique
Montée en compétence rapide
Adaptation naturelle à la philosophie
Test unitaires / d’intégration sont plus faciles à
maintenir
Fonctionne bien avec Java
25
70. Conclusions
Prise en main de MongoDB rapide et ludique
Montée en compétence rapide
Adaptation naturelle à la philosophie
Test unitaires / d’intégration sont plus faciles à
maintenir
Fonctionne bien avec Java
Le driver (avec et sans Morphia) reste un peu verbeux
mais il s’améliore en continu
25
71. Conclusions
Prise en main de MongoDB rapide et ludique
Montée en compétence rapide
Adaptation naturelle à la philosophie
Test unitaires / d’intégration sont plus faciles à
maintenir
Fonctionne bien avec Java
Le driver (avec et sans Morphia) reste un peu verbeux
mais il s’améliore en continu
Il est important de mener des tests de performance
au plus tôt dans le cycle de développement (JMeter)
25
72. Conclusions
Prise en main de MongoDB rapide et ludique
Montée en compétence rapide
Adaptation naturelle à la philosophie
Test unitaires / d’intégration sont plus faciles à
maintenir
Fonctionne bien avec Java
Le driver (avec et sans Morphia) reste un peu verbeux
mais il s’améliore en continu
Il est important de mener des tests de performance
au plus tôt dans le cycle de développement (JMeter)
Il faut bien connaître les options et la configuration
25