ElasticSearch,

Woo, dit mais c'est pas le truc qui Buzz ?

Julien Deniau

Sommaire

  • Mapado en chiffres

  • Les débuts

  • Full text search

  • Migration complête

  • Le futur

Mapado

Qui sommes-nous ?

Mapado

Things to do, close to you

Recherche d'activités:

  • à une date plus ou moins précise (prochainement, ce week-end, demain, ce soir)

  • géolocalisé

Côté technique

Code:
Python: Datamining, réplication, scripts "offline", gestion de dates
PHP: site mapado.com, serveur d'image


Framework:
Symfony, Silex


Databases:
MongoDB, MySQL, ElasticSearch

Côté chiffres

  • Juillets 2013: Sortie du site public

  • 2: serveurs pour ElasticSearch

  • 10: serveurs au total

  • 100aines: sources différentes d'import de données

  • 750 000: documents dans MongoDB

  • 700 000: documents répliqués dans ElasticSearch

  • 21 000 000: requêtes sur ES

  • 400 000: requêtes / jour

  • 1: développeur sous Windows

  • 1: clavier dvorak

Début 2013: L'heure des choix

LAMP vaincra (ou presque)

Base de donnée maitre: MongoDB

Repliquée pour la recherche dans MySQL

Fiche activité: MongoDB

Résultat de recherche: MySQL

Schema MySQL

Recherche par date + geopoint

Le 8 mars 2013 à 20h30 2013-03-08 20:30:00 2013-03-08 20:30:00
Le 8 mars 2013 2013-03-08 00:00:00 2013-03-08 23:59:59
Du 8 au 10 mars 2013
de 10h à 12h
2013-03-08 10:00:00 2013-03-08 12:00:00
2013-03-09 10:00:00 2013-03-09 12:00:00
2013-03-10 10:00:00 2013-03-10 12:00:00
Tous les lundis 2013-01-07 00:00:00 2013-01-07 23:59:59
2013-01-14 00:00:00 2013-01-14 23:59:59
2013-01-21 00:00:00 2013-01-21 23:59:59
...

Fonctionne bien

jusqu'à...

Full text search

We need ElasticSearch !

Réplication

MongoDB → MySQL

+ MongoDB → ElasticSearch (mais sans les dates)

Mauvais choix

  • Deux bases de données à maintenir
  • Deux codes différents à faire évoluer

Probleme de "fenêtre geospaciale" avec MySQL

Que faire à Bron ≈ Que faire à Lyon

Abandon de MySQL

Function Score Query

{ "query": {
    "function_score: {
        "score_mode": "avg",
        "functions": [
            {
                "gauss": {
                    "lat_lng": { "origin": { "lat": 45.76749, "lon": 4.83433 } }
                }
            },
            {
                "gauss": {
                    "popularity": { "origin": 1, "scale": 0.1 }
                }
            }
        ]
    }
} }

Réplication MongoDB → ElasticSearch:

Utilisation des "Nested" pour gérer nos listes de dates

{
    "title": "Meetup Elasticsearch Lyon #1",
    "lat_lng": "45.7622013, 4.8621385",
    "schedule": [
        {
            "start_datetime": 2014-12-04 19:00:00,
            "end_datetime": 2014-12-04 19:00:00
        }
    ]
}

Filtre par date

Que faire prochainement ?

{ "filter" : {
    "nested" : {
        "path" : "schedule",
        "filter" : {
            "range" : {
                "schedule.start_datetime": {
                    "gte": 2014-12-04 19:30:00
                }
            }
        }
    }
} }
  • Une seule base de données
  • Une seule base de code

Temps de réponse ?

≈ 120 ms

Améliorer les performances

Axes d'améliorations

  • Ne pas analyser tous les champs (status, foreign key, etc.)
  • Ne pas indexer tous les champs (url d'image, slug, etc.)

Adapter les données au site

Formulaire simple → données simples

Term filter

Le 8 mars 2013 à 20h30 2013-03-08_night, 2013-03-08_fullday,
2013_year, 2013_year_night
Le 8 mars 2013 2013-03-08_day, 2013-03-08_night, 2013-03-08_fullday,
2013_year, 2013_year_day, 2013_year_night
Tous les lundis 2013-01-07_day, 2013-01-07_night, 2013-01-07_fullday,
2013-01-14_day, 2013-01-14_night, 2013-01-14_fullday,
2013-01-21_day, 2013-01-21_night, 2013-01-21_fullday,
2013_year, 2013_year_night, 2013_year_fullday,
etc.

Temps de réponse ?

≈ 4 ms \o/

Vers l'infini et au delà

Recommandation utilisateur

Script Score

Ajout de la prise en compte des interactions utilisateurs (stockés dans ES via Logstash)

{ "query": {
    "function_score: {
        "score_mode": "sum",
        "functions": [
            {
                "gauss": {
                    "lat_lng": { "origin": { "lat": 45.76749, "lon": 4.83433 } }
                }
            },
            {
                "script_score": {
                    "script": "user-popularity",
                    "params": { /* ... */ }
                }
            }
        ]
    }
} }

Temps de réponse ?

≈ 50 ms

Conclusion

  • Pas de regrets sur la migration MySQL → ES

  • Probablement l'outil qu'il nous fallait

  • On pense que c'est l'outil qu'il va nous falloir

  • ES pas votre base principale :
    Optimisez vos données pour votre utilisation

Merci, des questions ?

@j_deniau
jdeniau.github.io/retour-es