Elasticsearch

"You Know, for Search"

Alessio Cimarelli

jenkin@dataninja.it

Roma, 6 dicembre 2016

{
    "name": "Isaac Asimov",
    "cluster_name": "dataninja",
    "version": {
        "number": "2.3.4",
        "build_hash": "e455fd0c13dceca8dbbdbb1665d068ae55dabe3f",
        "build_timestamp": "2016-06-30T11:24:31Z",
        "build_snapshot": false,
        "lucene_version": "5.5.0"
    },
    "tagline": "You Know, for Search"
}

Modello relazionale

Una tabella: relazione uno-a-uno

id nome cognome mail azienda
sb sara borroni lucelhc@gmail.com pangea
ac alessio cimarelli jenkin@dataninja.it dataninja
dg desirée gentilini d&g@pangea.it pangea

id,nome,cognome,mail,azienda
1,sara,borroni,lucelhc@gmail.com,pangea
2,alessio,cimarelli,jenkin@dataninja.it,dataninja

3,desirée,gentilini,d&g@pangea.it,pangea

Un csv

Modello relazionale

Una tabella: selezione, ordinamento, raggruppamento

azienda dipendenti
pangea 2
dataninja 1

SELECT azienda, COUNT(id) AS dipendenti

FROM persone

GROUP BY azienda

ORDER BY dipendenti DESC

Modello relazionale

Due tabelle: relazione uno-a-molti

id nome cognome mail azienda
sb sara borroni lucelhc@gmail.com pangea
ac alessio cimarelli jenkin@dataninja.it dataninja
dg desirée gentilini d&g@pangea.it pangea
id ragione sociale sede sito
pangea Pangea Formazione Roma www.pangeaformazione.it
dataninja Dataninja Bologna www.dataninja.it

Modello relazionale

Due tabelle: operazione di join

id nome cognome azienda sede
sb sara borroni pangea Roma
ac alessio cimarelli dataninja Bologna
dg desirée gentilini pangea Roma

SELECT persone.id, nome, cognome, azienda, sede

FROM persone JOIN aziende ON persone.azienda = aziende.id

ORDER BY cognome

Modello relazionale

Due tabelle: operazione di join

Modello relazionale

Tre tabelle: relazione molti-a-molti

id nome cognome mail
sb sara borroni lucelhc@gmail.com
ac alessio cimarelli jenkin@dataninja.it
dg desirée gentilini d&g@pangea.it
id descrizione
r Linguaggio R
py Linguaggio Python
id persona competenza
1 sb r
2 sb py
3 ac py

JSON

JavaScript Object Notation

id nome cognome mail azienda
sb sara borroni lucelhc@gmail.com pangea
ac alessio cimarelli jenkin@dataninja.it dataninja
[
  {
    "id": "sb",
    "nome": "sara",
    "cognome": "borroni",
    "mail": "lucelhc@gmail.com",
    "azienda": "pangea"
  },
  {
    "id": "ac",
    "nome": "alessio",
    "cognome": "cimarelli",
    "mail": "jenkin@dataninja.it",
    "azienda": "dataninja"
  }
]
{
  "id": ["sb","ac"],
  "nome": ["sara","alessio"],
  "cognome": ["borroni","cimarelli"],
  "mail": ["lucelhc@gmail.com","jenkin@dataninja.it"],
  "azienda": ["pangea","dataninja"]
}
{
  "keys": ["id","nome","cognome","mail","azienda"],
  "values": [
    ["sb","sara","borroni","lucelhc@gmail.com","pangea"],
    ["ac","alessio","cimarelli","jenkin@dataninja.it","dataninja"],
  ]
}

JSON

JavaScript Object Notation

id nome cognome mail azienda
sb sara borroni pangea
ac alessio cimarelli jenkin@dataninja.it dataninja
[
  {
    "id": "sb",
    "nome": "sara",
    "cognome": "borroni",
    "azienda": "pangea"
  },
  {
    "id": "ac",
    "nome": "alessio",
    "cognome": "cimarelli",
    "mail": "jenkin@dataninja.it",
    "azienda": "dataninja"
  }
]
[
  {
    "id": "sb",
    "nome": "sara",
    "cognome": "borroni",
    "azienda": "pangea",
    "competenze": ["r","py"]
  },
  {
    "id": "ac",
    "nome": "alessio",
    "cognome": "cimarelli",
    "mail": "jenkin@dataninja.it",
    "azienda": "dataninja",
    "competenze": ["py"]
  }
]

JSON

JavaScript Object Notation

id nome cognome mail azienda
sb sara borroni pangea
ac alessio cimarelli jenkin@dataninja.it dataninja
[
  {
    "id": "sb",
    "nome": "sara",
    "cognome": "borroni",
    "azienda": {
        "id": "pangea",
        "ragione sociale": "Pangea Formazione",
        "sede": "Roma"
    },
    "competenze": [
        { "id": "r", "descrizione": "Linguaggio R" },
        { "id": "py", "descrizione": "Linguaggio Python" }
    ]
  }
]

Elasticsearch is a search engine based on Lucene. It provides a distributed, multitenant-capable full-text search engine with an HTTP web interface and schema-free JSON documents. Elasticsearch is developed in Java and is released as open source under the terms of the Apache License.

First of all, DON’T PANIC. It will take 5 minutes to get the gist of what Elasticsearch is all about.

Search & Analyze Data in Real Time

Elasticsearch builds distributed capabilities on top of Apache Lucene to provide the most powerful full- text search capabilities available.

 Powerful, developer-friendly query API supports multilingual search, geolocation, contextual did-you-mean suggestions, autocomplete, and result snippets.

{  
  "size":25,
  "sort":[  
    {  
      "@timestamp":{  
        "order":"desc"
      }
    }
  ],
  "query":{  
    "bool":{  
      "must":{  
        "match":{  
          "title":"sismico"
        }
      },
      "must_not":{  
        "match":{  
          "title":"matrimoni"
        }
      }
    }
  },
  "aggs":{  
    "words":{  
      "terms":{  
        "field":"title",
        "size":25
      }
    },
    "locations":{  
      "terms":{  
        "field":"source.location",
        "size":0
      },
      "aggs":{  
        "words":{  
          "significant_terms":{  
            "field":"title",
            "min_doc_count":1,
            "size":25
          }
        },
        "hits":{  
          "top_hits":{  
            "size":25,
            "sort":[  
              {  
                "@timestamp":{  
                  "order":"desc"
                }
              }
            ]
          }
        }
      }
    }
  }
}

Elasticsearch allows you to start small and scale horizontally as you grow. Simply add more nodes, and let the cluster automatically take advantage of the extra hardware.

Elasticsearch clusters are resilient — they will detect new or failed nodes, and reorganize and rebalance data automatically, to ensure that your data is safe and accessible.

{  
  "took":2,
  "timed_out":false,
  "_shards":{  
    "total":15,
    "successful":15,
    "failed":0
  },
  "hits":{  
    "total":15,
    "max_score":null,
    "hits":[  
      {  
        "_index":"albopop-v3-2016.08.26",
        "_type":"rss_item",
        "_id":"ebe289800f14c7f7c8a5ba24aefae037",
        "_score":null,
        "_source":{  
          "message":"<html><body><p>[6408/2016 Determinazioni dal 26/08/2016 al 10/09/2016] Scuola Primaria Meucci in località Coiano /Santa Lucia - Lavori di Miglioramento/Adeguamento sismico della palestra - Affidamento lavori aggiuntivi (variante inferiore al 5% importo contrattuale) alla ditta Iniziative Edili SRL - CUP: C37H13001290004 - C.I. 3073</p></body></html>\n",
          "@version":"1",
          "@timestamp":"2016-08-26T22:02:07.504Z",
          "Feed":"http://news.dataninja.it/public.php?op=rss&id=26&is_cat=1&key=9p9m74577d6e8948676",
          "id":"ebe289800f14c7f7c8a5ba24aefae037",
          "updated":"2016-08-26 02:00:00 +0200",
          "title":"[6408/2016 Determinazioni dal 26/08/2016 al 10/09/2016] Scuola Primaria Meucci in località Coiano /Santa Lucia - Lavori di Miglioramento/Adeguamento sismico della palestra - Affidamento lavori aggiuntivi (variante inferiore al 5% importo contrattuale) alla ditta Iniziative Edili SRL - CUP: C37H13001290004 - C.I. 3073",
          "link":"http://albopretorio.comune.prato.it/albopretoriobinj/AlboPretorio?servizio=dettaglio&idPratica=166066&",
          "author":"",
          "source":{  
            "id":"http://albopretorio.comune.prato.it",
            "link":"http://albopretorio.comune.prato.it",
            "updated":"2016-08-26 02:00:00 +0200",
            "title":"Albopop - Comune - Prato",
            "tags":[  
              "Albopop",
              "Comune",
              "Prato"
            ],
            "type":"Comune",
            "location":"Prato"
          }
        },
        "sort":[  
          1472248927504
        ]
      },
      {  
        "_index":"albopop-v3-2016.08.26",
        "_type":"rss_item",
        "_id":"7eacf976f189bf7a26e14ede516f6e61",
        "_score":null,
        "_source":{  
          "message":"<html><body><p>[6397/2016 Delibere (giunta, consiglio, circoscrizioni) dal 26/08/2016 al 10/09/2016] Protezione Civile - Autorizzazione all'attivazione dell'U.O.C. Protezione Civile del Comune di Prato e di altro personale dell'Amministrazione Comunale in supporto del Sistema di Protezione Civile Regionale/Nazionale per gli interventi di emergenza ed i servizi di soccorso a favore della popolazione colpita dagli eventi sismici del 24 agosto 2016 in zone del Lazio, Marche e Umbria</p></body></html>\n",
          "@version":"1",
          "@timestamp":"2016-08-26T11:02:05.144Z",
          "Feed":"http://news.dataninja.it/public.php?op=rss&id=26&is_cat=1&key=9p9m74577d6e8948676",
          "id":"7eacf976f189bf7a26e14ede516f6e61",
          "updated":"2016-08-26 02:00:00 +0200",
          "title":"[6397/2016 Delibere (giunta, consiglio, circoscrizioni) dal 26/08/2016 al 10/09/2016] Protezione Civile - Autorizzazione all'attivazione dell'U.O.C. Protezione Civile del Comune di Prato e di altro personale dell'Amministrazione Comunale in supporto del Sistema di Protezione Civile Regionale/Nazionale per gli interventi di emergenza ed i servizi di soccorso a favore della popolazione colpita dagli eventi sismici del 24 agosto 2016 in zone del Lazio, Marche e Umbria",
          "link":"http://albopretorio.comune.prato.it/albopretoriobinj/AlboPretorio?servizio=dettaglio&idPratica=166055&",
          "author":"",
          "source":{  
            "id":"http://albopretorio.comune.prato.it",
            "link":"http://albopretorio.comune.prato.it",
            "updated":"2016-08-26 02:00:00 +0200",
            "title":"Albopop - Comune - Prato",
            "tags":[  
              "Albopop",
              "Comune",
              "Prato"
            ],
            "type":"Comune",
            "location":"Prato"
          }
        },
        "sort":[  
          1472209325144
        ]
      }
    ]
  },
  "aggregations":{  
    "words":{  
      "doc_count_error_upper_bound":0,
      "sum_other_doc_count":173,
      "buckets":[  
        {  
          "key":"sismic",
          "doc_count":15
        },
        {  
          "key":"edific",
          "doc_count":12
        },
        {  
          "key":"event",
          "doc_count":11
        },
        {  
          "key":"via",
          "doc_count":11
        },
        {  
          "key":"benefic",
          "doc_count":10
        },
        {  
          "key":"contribut",
          "doc_count":10
        },
        {  
          "key":"danneggiat",
          "doc_count":10
        },
        {  
          "key":"immobiliar",
          "doc_count":10
        },
        {  
          "key":"magg",
          "doc_count":10
        },
        {  
          "key":"relativ",
          "doc_count":10
        }
      ]
    },
    "locations":{  
      "doc_count_error_upper_bound":0,
      "sum_other_doc_count":0,
      "buckets":[  
        {  
          "key":"Bondeno",
          "doc_count":6,
          "hits":{  
            "hits":{  
              "total":6,
              "max_score":null,
              "hits":[  
                {  
                  "_index":"albopop-v3-2016.08.25",
                  "_type":"rss_item",
                  "_id":"ed9af6518ef57fc9bb50ed7e78cf994e",
                  "_score":null,
                  "_source":{  
                    "message":"<html><body><img src=\"http://feeds.feedburner.com/~r/AlboPretorioComuneDiBondeno/~4/gLtsN74wzlM\" height=\"1\" width=\"1\" alt=\"\"></body></html>\n",
                    "@version":"1",
                    "@timestamp":"2016-08-25T13:02:04.486Z",
                    "Feed":"http://news.dataninja.it/public.php?op=rss&id=26&is_cat=1&key=9p9m74577d6e8948676",
                    "id":"ed9af6518ef57fc9bb50ed7e78cf994e",
                    "updated":"2016-08-25 00:00:00 +0200",
                    "title":"ASSEGNAZIONE DI CONTRIBUTI A BENEFICIO DI EDIFICI E UNITÀ IMMOBILIARI AD USO ABITATIVO DANNEGGIATI DAGLI EVENTI SISMICI DEL 20 E 29 MAGGIO 2012 RELATIVA AL FABBRICATO UBICATO IN SCORTICHINO, VIA ARGINE DIVERSIVO N. 351 E ACCATASTATO AL FG. 139, MAPPA",
                    "link":"http://feedproxy.google.com/~r/AlboPretorioComuneDiBondeno/~3/gLtsN74wzlM/mc_p_dettaglio.php",
                    "author":"",
                    "source":{  
                      "id":"http://blog.spaziogis.it/static/ods/data/albopop/bondeno/feed_rss.xml",
                      "link":"http://blog.spaziogis.it/static/ods/data/albopop/bondeno/feed_rss.xml",
                      "updated":"2016-08-25 00:00:00 +0200",
                      "title":"Albopop - Comune - Bondeno",
                      "tags":[  
                        "Albopop",
                        "Comune",
                        "Bondeno"
                      ],
                      "type":"Comune",
                      "location":"Bondeno"
                    }
                  },
                  "sort":[  
                    1472130124486
                  ]
                },
                {  
                  "_index":"albopop-v3-2016.08.25",
                  "_type":"rss_item",
                  "_id":"6be5b044b74929d8c0a3a2c64a014122",
                  "_score":null,
                  "_source":{  
                    "message":"<html><body><img src=\"http://feeds.feedburner.com/~r/AlboPretorioComuneDiBondeno/~4/L2_NjjlryrU\" height=\"1\" width=\"1\" alt=\"\"></body></html>\n",
                    "@version":"1",
                    "@timestamp":"2016-08-25T12:02:04.443Z",
                    "Feed":"http://news.dataninja.it/public.php?op=rss&id=26&is_cat=1&key=9p9m74577d6e8948676",
                    "id":"6be5b044b74929d8c0a3a2c64a014122",
                    "updated":"2016-08-25 00:00:00 +0200",
                    "title":"RIDETERMINAZIONE DEI CONTRIBUTI A SALDO A BENEFICIO DI EDIFICI E UNITÀ IMMOBILIARI AD USO PRODUTTIVO AGRICOLO DANNEGGIATI DAGLI EVENTI SISMICI DEL 20 E 29 MAGGIO 2012 RELATIVA ALLIMMOBILE UBICATO IN LOCALITA PONTE RODONI VIA VIRGILIANA SNC E ACCATAST",
                    "link":"http://feedproxy.google.com/~r/AlboPretorioComuneDiBondeno/~3/L2_NjjlryrU/mc_p_dettaglio.php",
                    "author":"",
                    "source":{  
                      "id":"http://blog.spaziogis.it/static/ods/data/albopop/bondeno/feed_rss.xml",
                      "link":"http://blog.spaziogis.it/static/ods/data/albopop/bondeno/feed_rss.xml",
                      "updated":"2016-08-25 00:00:00 +0200",
                      "title":"Albopop - Comune - Bondeno",
                      "tags":[  
                        "Albopop",
                        "Comune",
                        "Bondeno"
                      ],
                      "type":"Comune",
                      "location":"Bondeno"
                    }
                  },
                  "sort":[  
                    1472126524443
                  ]
                }
              ]
            }
          },
          "words":{  
            "doc_count":6,
            "buckets":[  
              {  
                "key":"sismic",
                "doc_count":6,
                "score":75.35000000000001,
                "bg_count":20
              },
              {  
                "key":"benefic",
                "doc_count":5,
                "score":54.9780701754386,
                "bg_count":19
              },
              {  
                "key":"danneggiat",
                "doc_count":5,
                "score":54.9780701754386,
                "bg_count":19
              },
              {  
                "key":"event",
                "doc_count":5,
                "score":52.187500000000014,
                "bg_count":20
              },
              {  
                "key":"subappalt",
                "doc_count":1,
                "score":42.24999999999999,
                "bg_count":1
              }
            ]
          }
        },
        {  
          "key":"Cento",
          "doc_count":5,
          "hits":{  
            "hits":{  
              "total":5,
              "max_score":null,
              "hits":[  
                {  
                  "_index":"albopop-v3-2016.08.19",
                  "_type":"rss_item",
                  "_id":"5ea4e7ea7b283a3ace1fbfece1b3d310",
                  "_score":null,
                  "_source":{  
                    "message":"<html><body><p>[1874/2016 ORDINANZE/ORDINANZE SINDACALI dal 19/08/2016 al 03/09/2016] ORDINANZA DI RIDETERMINAZIONE DEI CONTRIBUTI ED AUTORIZZAZIONE AL PAGAMENTO A SALDO A BENEFICIO DI EDIFICI E UNITÀ IMMOBILIARI AD USO ABITATIVO DANNEGGIATI DAGLI EVENTI SISMICI DEL 20 E 29 MAGGIO 2012 RELATIVA ALL’IMMOBILE UBICATO IN VIA BONDENESE [BUONACOMPRA] N. 135 E ACCATASTATO AL NCEU: FG.13 MAP.473 - PROPRIETA’ DI TASSINARI CRISTINA – CODICE C.U.P. F35C15001160008</p></body></html>\n",
                    "@version":"1",
                    "@timestamp":"2016-08-19T22:02:04.618Z",
                    "Feed":"http://news.dataninja.it/public.php?op=rss&id=26&is_cat=1&key=9p9m74577d6e8948676",
                    "id":"5ea4e7ea7b283a3ace1fbfece1b3d310",
                    "updated":"2016-08-19 02:00:00 +0200",
                    "title":"[1874/2016 ORDINANZE/ORDINANZE SINDACALI dal 19/08/2016 al 03/09/2016] ORDINANZA DI RIDETERMINAZIONE DEI CONTRIBUTI ED AUTORIZZAZIONE AL PAGAMENTO A SALDO A BENEFICIO DI EDIFICI E UNITÀ IMMOBILIARI AD USO ABITATIVO DANNEGGIATI DAGLI EVENTI SISMICI DEL 20 E 29 MAGGIO 2012 RELATIVA ALL’IMMOBILE UBICATO IN VIA BONDENESE [BUONACOMPRA] N. 135 E ACCATASTATO AL NCEU: FG.13 MAP.473 - PROPRIETA’ DI TASSINARI CRISTINA – CODICE C.U.P. F35C15001160008",
                    "link":"http://servizi.comune.cento.fe.it/web/trasparenza/albo-pretorio/-/papca/display/5100",
                    "author":"",
                    "source":{  
                      "id":"http://servizi.comune.cento.fe.it/web/trasparenza/albo-pretorio",
                      "link":"http://servizi.comune.cento.fe.it/web/trasparenza/albo-pretorio",
                      "updated":"2016-08-19 02:00:00 +0200",
                      "title":"Albopop - Comune - Cento",
                      "tags":[  
                        "Albopop",
                        "Comune",
                        "Cento"
                      ],
                      "type":"Comune",
                      "location":"Cento"
                    },
                    "cluster":"C111526949067320576333405191475842860414"
                  },
                  "sort":[  
                    1471644124618
                  ]
                },
                {  
                  "_index":"albopop-v3-2016.08.19",
                  "_type":"rss_item",
                  "_id":"9c9bed8bcbcde1d94a98cbb8e95b952b",
                  "_score":null,
                  "_source":{  
                    "message":"<html><body><p>[1872/2016 ORDINANZE/ORDINANZE SINDACALI dal 19/08/2016 al 03/09/2016] ASSEGNAZIONE DI CONTRIBUTI A BENEFICIO DI EDIFICI E UNITÀ IMMOBILIARI AD USO ABITATIVO DANNEGGIATI DAGLI EVENTI SISMICI DEL 20 E 29 MAGGIO 2012, RELATIVA ALL’IMMOBILE UBICATO IN VIA MARCONI GUGLIELMO N. 13 A CENTO (FE) E FG.51 MAPP.173 SUB.1, SUB.2, SUB.3, SUB.4 E SUB.5 - PROPRIETA’ DI BARONI EUGENIA E BARONI ALBERTINA – ORDINANZA DI INAGIBILITA’ N.556 DEL 27.07.2012 – CODICE CUP F35C16000900008</p></body></html>\n",
                    "@version":"1",
                    "@timestamp":"2016-08-19T22:02:04.618Z",
                    "Feed":"http://news.dataninja.it/public.php?op=rss&id=26&is_cat=1&key=9p9m74577d6e8948676",
                    "id":"9c9bed8bcbcde1d94a98cbb8e95b952b",
                    "updated":"2016-08-19 02:00:00 +0200",
                    "title":"[1872/2016 ORDINANZE/ORDINANZE SINDACALI dal 19/08/2016 al 03/09/2016] ASSEGNAZIONE DI CONTRIBUTI A BENEFICIO DI EDIFICI E UNITÀ IMMOBILIARI AD USO ABITATIVO DANNEGGIATI DAGLI EVENTI SISMICI DEL 20 E 29 MAGGIO 2012, RELATIVA ALL’IMMOBILE UBICATO IN VIA MARCONI GUGLIELMO N. 13 A CENTO (FE) E FG.51 MAPP.173 SUB.1, SUB.2, SUB.3, SUB.4 E SUB.5 - PROPRIETA’ DI BARONI EUGENIA E BARONI ALBERTINA – ORDINANZA DI INAGIBILITA’ N.556 DEL 27.07.2012 – CODICE CUP F35C16000900008",
                    "link":"http://servizi.comune.cento.fe.it/web/trasparenza/albo-pretorio/-/papca/display/5094",
                    "author":"",
                    "source":{  
                      "id":"http://servizi.comune.cento.fe.it/web/trasparenza/albo-pretorio",
                      "link":"http://servizi.comune.cento.fe.it/web/trasparenza/albo-pretorio",
                      "updated":"2016-08-19 02:00:00 +0200",
                      "title":"Albopop - Comune - Cento",
                      "tags":[  
                        "Albopop",
                        "Comune",
                        "Cento"
                      ],
                      "type":"Comune",
                      "location":"Cento"
                    },
                    "cluster":"C143941458368493638793515354312770439318"
                  },
                  "sort":[  
                    1471644124618
                  ]
                }
              ]
            }
          },
          "words":{  
            "doc_count":5,
            "buckets":[  
              {  
                "key":"unit",
                "doc_count":5,
                "score":59.60000000000001,
                "bg_count":5
              },
              {  
                "key":"event",
                "doc_count":5,
                "score":59.60000000000001,
                "bg_count":5
              },
              {  
                "key":"benefic",
                "doc_count":5,
                "score":59.60000000000001,
                "bg_count":5
              },
              {  
                "key":"danneggiat",
                "doc_count":5,
                "score":59.60000000000001,
                "bg_count":5
              },
              {  
                "key":"sismic",
                "doc_count":5,
                "score":49.5,
                "bg_count":6
              },
              {
            ]
          }
        }
      ]
    }
  }
}

HTTP e API RESTful

Architettura

Client - Server

Metodi

GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH

Modello request / response

Status, Header, Body

URI

[protocol]://[user]:[password]@[host]:[port]/[path]?[key]=[value]#[hash]

Gli ingredienti

Indici

Collezioni di documenti logicamente coerenti (es. persone e aziende, utenti Twitter e tweet, log giornalieri, ecc.) - aka database

Tipi

Collezioni di documenti omogenei (stessa struttura, stesso mapping) - aka tabelle

Documenti

Oggetti JSON arbitrari associati a un mapping - aka righe

Le query

Formati

Quasi tutto in JSON, sia le richieste che le risposte

Azioni

Index - Inserimento di nuovi documenti

Get - Recupero documenti indicizzati (semplice o paginato)

Delete - Rimozione

Update - Aggiornamento

Bulk: più azioni in una sola chiamata

Fonti e risorse

Source » Logstash » Elasticsearch » Kibana / Processor

GET albopop-v3-2016.09.01/_search?sort=@timestamp:desc

Alessio Cimarelli

@jenkin27

jenkin@dataninja.it

Made with Slides.com