Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

 Illicotravel, c’est:  Un des plus gros comparateurs de voyages en France  450 000 VU/mois  30 millions de CA généré pour les partenaires  Bcp de développements internes ▪ Langage de script outillé fait maison ▪ Propre framework de composants JavaScript sur Mootools  Approx. 10 Go de données

Slide 3

Slide 3 text

 Nous vivons dans un monde hautement abstrait et confortable  POO  Les Objets se baladent sur le réseau en XML ou en JSON  Une grosse partie de notre travail consiste à rester dans ce monde parfait  Nous utilisons des librairies JavaScript qui nous affranchissent des soucis des navigateurs  Nous pouvons changer de serveur d’appli, nos servlets tournerons toujours  Nous nettoyons les données externes (les fichiers XML des voyagistes, les captures HTML des offres, …)

Slide 4

Slide 4 text

public PreparedStatement createPreparedStatement(Connection con) throws SQLException { String sql = "INSERT INTO vacation" + " (sourceId, creationDate, advertiserName, idFromAdvertiser, vacationType, title, extraInfo, shortDescription, longDescription, continentCode, countryCode, city, dayCount, nightCount, hotelName, smallImageUrl, bigImageUrl, detailUrl)" + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; PreparedStatement ps = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); ps.setString(1, vacation.getSourceId()); ps.setTimestamp(2, toTimestamp(vacation.getCreationDate())); ps.setString(3, vacation.getAdvertiserName()); ps.setString(4, vacation.getIdFromAdvertiser()); ps.setString(5, vacation.getVacationType()); ps.setString(6, vacation.getTitle()); ps.setString(7, vacation.getExtraInfo()); ps.setString(8, vacation.getShortDescription()); ps.setString(9, vacation.getLongDescription()); ps.setString(10, vacation.getContinentCode()); ps.setString(11, vacation.getCountry().getCode()); ps.setString(12, vacation.getCity()); ps.setInt(13, vacation.getDayCount()); ps.setInt(14, vacation.getNightCount()); ps.setString(15, vacation.getHotelName()); ps.setString(16, vacation.getSmallImageUrl()); ps.setString(17, vacation.getBigImageUrl()); ps.setString(18, vacation.getDetailUrl()); return ps; }

Slide 5

Slide 5 text

 Le monde SQL fourni des outils pour résoudre ces problèmes  ORM: Hibernate  Clustering ▪ MySQL Cluster ▪ Driver JDBC virtuel (Continuent)…  Loin du produit « évident » qu’on s'imagine pouvoir coder soi-même (avec du temps)

Slide 6

Slide 6 text

 Ancienne architecture (simplifiée) Front (Java) Front (Java) MySQL DAO (PHP) Load balancer (Apache) Cherchez l’erreur JSON/HTTP

Slide 7

Slide 7 text

 En gros, le choix était entre Cassandra et MongoDB  Cassandra: trop bas niveau  Une HashMap distribuée  Les index sont à gérer soi-même (en tout cas à l’époque). Et surtout…

Slide 8

Slide 8 text

prix, voyagiste, … voyagiste, description, … voyagiste, description, … prix par date et ville de départ > Et surtout…

Slide 9

Slide 9 text

Recherchez Jaspersoft indice big data

Slide 10

Slide 10 text

 Expérience personnelle  tout va bien (on parlera des gros Map/Reduce plus loin)  nous sommes en 1.8  2 révolutions en parallèle  NOSQL  RAM (OVH: 109,99 €/mois pour Xeon i7 – 24 Go)

Slide 11

Slide 11 text

 Verbosité en Java (petite structure)  Verbosité en Java (grosse structure)  Morphia et concurrence  Index  Grosses requêtes  Map/Reduce

Slide 12

Slide 12 text

JavaScript Object literal: var index = { city: 1, date: 1, price: 1} Custom class héritant de BasicDBObject DBObject index = new DBO("city", 1, "date", 1, "price", 1); Java Driver: DBObject index= new BasicDBObject(); index.put("city", 1); index.put("date", 1); index.put("price", 1) Java Driver + Google Guava DBObject index = new BasicDBObject(ImmutableMap.of( "city", 1, "date", 1, "price", 1));

Slide 13

Slide 13 text

Objet Car (location de voiture) Avec DBO (custom DBObject): DBObject index = new DBO( "brand", car.getBrand(), "model", car.getModel(), "gear", car.getGear(), "image", car.getImageUrl(), "price", car.getPrice(), …);

Slide 14

Slide 14 text

Solution évidente: Morphia (ODM) Quelques annotations + getMorphia().toDBObject(car) Puis…la version stockée commence à changer . les dates deviennent des string . des champs en plus, des champs en moins Que faire ?

Slide 15

Slide 15 text

 On passe Morphia et on modifie le résultat ?  On utilise notre custom DBO ? Et la lecture ? Les structures stockées sont...autre chose => On crée des classes représentant les données stockées. Eg: CarInDb

Slide 16

Slide 16 text

Problème:  Vision simpliste: "j'ai un Objet, je le lis en 1 ligne, je le modifie et je le sauve en 1 ligne"  Et si...2 users le font en même temps, le 2e peut écraser les modifs du 1er Solution:  Morphia uniquement en lecture  écriture fine utilisant $inc, $set, $push, ...

Slide 17

Slide 17 text

Problème: 1. les champs requêtés peuvent être très variables 2. L’ordre d’un index est important (MongoVUE anyone?), mais surtout: on ne peut pas sauter un champs

Slide 18

Slide 18 text

Solution: date city depCity | depCountry | airline price ... L'idéal On fait attention MongoUtils.index(col, "date", "city", "depCity" , "price"); MongoUtils.index(col, "date", "city" , "depCountry" , "price"); MongoUtils.index(col, "date", "city", "depCity" , "airline", "price"); MongoUtils.index(col, "date", "city" , "depCountry", "airline", "price");

Slide 19

Slide 19 text

 problème: gros scan de la collection => requête longue  eg: prix min des séjours par pays (30 sec)  Solutions: 1. background cache (code maison pour ehcache) 2. pattern: profiter du nombre élevé de requêtes en découpant une grosse requête en pls petites => bien gérer ses Randoms

Slide 20

Slide 20 text

 abstraction séduisante  puissance réelle  mais...  pas si instinctif que ça: ▪ SELECT min(price) FROM flights GROUP BY departure, arrival devient ▪ db.coll.group( { key: { departure:true, arrival:true }, reduce: function(obj,prev) { if(out.price > doc.price) { out.price = doc.price; }, });  pour un min, on n'a pas accès à l'objet associé  on se retrouve à générer du texte  perf. JS, non multi-core

Slide 21

Slide 21 text

l'idéal serait:  comme en JavaScript forEach / map / filter  comme en Java 8 avec les lambdas => framework d'aggrégation  language d'expression très limité, mais pas de JavaScript

Slide 22

Slide 22 text

Merci