Skip to content

mmotel/es-facets

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 

Repository files navigation

#Elasticsearch - Faceted Search

##Spis treści

##Dane

GetGlue and Timestamped Event Data (ok. 11 GB, 19 831 300 json-ów, próbka 100 jsonów getglue101). Są to dane z IMDB z lat 2007–2012, tylko filmy i przedstawienia TV.

Przykładowy dokument json:

{
  "_id": ObjectId("5276918832cf3c2b84540440"),
  "comment": "",
  "modelName": "movies",
  "displayName": "",
  "title": "The Dark Knight",
  "timestamp": "2008-10-28T16:47:31Z",
  "image": "http://ia.media-imdb.com/images/...@@._V1._SX94_SY140_.jpg",
  "userId": "sippey",
  "private": "false",
  "director": "Christopher Nolan",
  "source": "http://www.imdb.com/title/tt0468569/",
  "version": "1",
  "link": "http://www.imdb.com/title/tt0468569/",
  "lastModified": "2011-12-16T19:39:33Z",
  "action": "Liked",
  "lctitle": "the dark knight",
  "objectKey": "movies/dark_knight/christopher_nolan"
}

##Przygotowanie danych do importu

Do masowego importu danych do Elasticsearch'a użyjemy Bulk API.

Bulk API wymaga "przeplatanych" JSON'ów o następującej strukturze:

{ "index": { "_type": "type name" } } //nazwa typu, do którego chcemy dodać dokument
{ "field": "content" ... } //dokument

Do wygenerowania "przeplatanych" JSON'ów użyjemy programu jq.

time cat getglue_sample.json | jq --compact-output '{ "index": { "_type": "imdb" } }, .' 
  > getglue_sample.bulk

####Wynik

Otrzymujemy "przeplatane" JSON'y:

{
  "index": {
    "_type": "imdb"
  }
}
{
  "objectKey": "tv_shows/criminal_minds",
  "hideVisits": "false",
  "modelName": "tv_shows",
  "displayName": "",
  "title": "Criminal Minds",
  "timestamp": "2008-08-01T06:58:14Z",
  "image": "http://cdn-1.nflximg.com/us/boxshots/large/70056671.jpg",
  "userId": "areilly",
  "visitCount": "1",
  "comment": "",
  "private": "false",
  "source": "http://www.netflix.com/Movie/Criminal_Minds_Season_1/70056671",
  "version": "2",
  "link": "http://www.netflix.com/Movie/Criminal_Minds_Season_1/70056671",
  "lastModified": "2011-12-16T19:41:19Z",
  "action": "Liked",
  "lctitle": "criminal minds"
}

Plik getglue_sample.bulk zawiera łącznie 39 662 600 dokumentów JSON.

####Czasy

real  30m34.117s
user  26m9.324s
sys   1m24.807s

W ciągu 30m34.117s wygenerowało się 39 662 600 dokumentów JSON. Co średnio daje ~21 626 wygenerowanych dokumentów JSON na sekundę.

##Import

Próba wykonania importu całego pliku getglue_sample.bulk (39 662 600 JSON'ów, 11,3 GB) konczy się niepowodzeniem.

curl -s -XPOST localhost:9200/data/_bulk --data-binary @getglue_sample.bulk

Po pierwsze polecenie curl próbuje wczytać cały plik do pamięci. Po drugie baza danych najprawdopodobniej nie jest w stanie przyjąć tak dużej ilości danych na raz, rzuca TooLongFrameException.

Aby rozwiązać oba te problemy dzielimy plik na części po 200 000 linii czyli 100 000 dokumnetów do dodoania.

split -l 200000 getglue_sample.bulk

A następnie dokonujemy importu w pętli:

time for i in x*; do curl -s -XPOST localhost:9200/data/_bulk --data-binary @$i > /dev/null; echo $i; done

####Wynik

Sprawdzamy ile obiektów zostało zapisanych w bazie.

curl -XGET 'http://localhost:9200/data/imdb/_count' ; echo
{"count":19766542,"_shards":{"total":1,"successful":1,"failed":0}}

Zaimportowało się 19 766 542. Brakuje 64 758 obiektów. Jak wynika z logu importu spowodowane jest to niepoprawnym formatem daty, co skutkowało odrzuceniem obiektu.

####Czasy

real  165m45.252s
user  0m7.414s
sys   0m28.627s

W czasie 165m45.252s (~2h45m) zaimportowało 19 766 542 obiektów. Co daje średnio ~1 987 insertów na sekundę. Czemu (nadal) tak wolno?

##Faceted Search

Do wykonania aggregacji w Elasticsearch użyjemy wyszukiwania fasetowego - facets search w ES.

Do wykonywania zapytań użyjemy programu curl:

curl -X POST "http://localhost:9200/data/_search?pretty=true" -d '{ "query": { } }'

###Faceted Search 1

Dziesięciu najaktywniejszych użytkowików

Wyszukiwanie fasetowe ma policzyć ile akcji wykonał każdy z użytkowników i zwrócić dziesięciu najaktywniejszych.

####Kod zapytania

{
    "query" : {
        "match_all" : {  }
    },
    "facets" : {
        "userId" : {
            "terms" : {
                "field" : "userId",
                "size" : 10
            }
        }
    }
}

Skrypt: tutaj.

####Wynik

{
  "facets": {
    "userId": {
      "terms": [
        { "count": 696750, "term": "lukewilliamss" },
        { "count": 68131,  "term": "demi_konti"    },
        { "count": 59257,  "term": "bangwid"       },
        { "count": 56044,  "term": "zenofmac"      },
        { "count": 55736,  "term": "agentdunham"   },
        { "count": 43153,  "term": "cillax"        },
        { "count": 42299,  "term": "tamtomo"       },
        { "count": 32824,  "term": "hblackwood"    },
        { "count": 32237,  "term": "ellen_turner"  },
        { "count": 32133,  "term": "husainholic"   }
      ],
      "other": 18648036,
      "total": 19766600,
      "missing": 0,
      "_type": "terms"
    }
  },
  "hits": {
    //...
  },
  "_shards": {
    "failed": 0,
    "successful": 1,
    "total": 1
  },
  "timed_out": false,
  "took": 6391
}

Pełny wynik wyszukiwania fasetowego: tutaj.

####Czasy

real  0m6.027s
user  0m0.009s
sys   0m0.012s

####Wykresy

facets search 1 chart 1

facets search 1 chart 2

###Faceted Search 2

Aktywność użytkowników według miesięcy

Wyszukiwanie fasetowe ma policzyć ile akcji wykonali użytkownicy w ciągu kolejnych miesięcy.

####Kod zapytania

{
    "query" : {
        "match_all" : {}
    },
    "facets" : {
        "histo1" : {
            "date_histogram" : {
                "field" : "timestamp",
                "interval" : "month"
            }
        }
    }
}

Skrypt: tutaj.

####Wynik

{
  "facets": {
    "histo1": {
      "entries": [
        { "count": 1,       "time": 1164931200000 },
        { "count": 2,       "time": 1167609600000 },
        { "count": 2,       "time": 1.170288e+12  },
        { "count": 1,       "time": 1172707200000 },
        { "count": 1,       "time": 1175385600000 },
        { "count": 1,       "time": 1196467200000 },
        { "count": 1,       "time": 1212278400000 },
        { "count": 2,       "time": 1214870400000 },
        { "count": 19,      "time": 1217548800000 },
        { "count": 28,      "time": 1220227200000 },
        { "count": 128,     "time": 1222819200000 },
        { "count": 294,     "time": 1225497600000 },
        { "count": 115,     "time": 1228089600000 },
        { "count": 282,     "time": 1.230768e+12  },
        { "count": 119,     "time": 1233446400000 },
        { "count": 218,     "time": 1235865600000 },
        { "count": 344,     "time": 1.238544e+12  },
        { "count": 389,     "time": 1.241136e+12  },
        { "count": 586,     "time": 1243814400000 },
        { "count": 808,     "time": 1246406400000 },
        { "count": 2301,    "time": 1249084800000 },
        { "count": 2748,    "time": 1251763200000 },
        { "count": 8904,    "time": 1254355200000 },
        { "count": 16751,   "time": 1257033600000 },
        { "count": 43289,   "time": 1259625600000 },
        { "count": 34958,   "time": 1.262304e+12  },
        { "count": 32006,   "time": 1264982400000 },
        { "count": 65592,   "time": 1267401600000 },
        { "count": 51768,   "time": 1.27008e+12   },
        { "count": 51585,   "time": 1.272672e+12  },
        { "count": 85401,   "time": 1275350400000 },
        { "count": 199294,  "time": 1277942400000 },
        { "count": 256512,  "time": 1280620800000 },
        { "count": 312460,  "time": 1283299200000 },
        { "count": 304326,  "time": 1285891200000 },
        { "count": 362662,  "time": 1288569600000 },
        { "count": 302035,  "time": 1291161600000 },
        { "count": 496329,  "time": 1.29384e+12   },
        { "count": 428525,  "time": 1296518400000 },
        { "count": 441130,  "time": 1298937600000 },
        { "count": 538690,  "time": 1.301616e+12  },
        { "count": 630517,  "time": 1.304208e+12  },
        { "count": 700685,  "time": 1306886400000 },
        { "count": 954233,  "time": 1309478400000 },
        { "count": 947335,  "time": 1312156800000 },
        { "count": 1148994, "time": 1314835200000 },
        { "count": 1503366, "time": 1317427200000 },
        { "count": 1810790, "time": 1320105600000 },
        { "count": 1088950, "time": 1322697600000 },
        { "count": 1145836, "time": 1.325376e+12  },
        { "count": 1382174, "time": 1328054400000 },
        { "count": 1643917, "time": 1.33056e+12   },
        { "count": 1687831, "time": 1333238400000 },
        { "count": 1081307, "time": 1335830400000 }
      ],
      "_type": "date_histogram"
    }
  },
  "hits": {
    //...
  },
  "_shards": {
    "failed": 0,
    "successful": 1,
    "total": 1
  },
  "timed_out": false,
  "took": 5870
}

Pełny wynik wyszukiwania fasetowego: tutaj.

####Czasy

real  0m11.661s
user  0m0.008s
sys   0m0.017s

####Konwersja dat

Czym są liczby w polu time? Jak można się domyślić to czas. A jak można przeczytać w dokumentacji typu Date w JavaScript jest to the number of milliseconds since midnight Jan 1, 1970. Aby zaprezentować wynik w bardziej czytelnej formie przeliczymy milisekundy na daty.

for(var i = 0; i < entries.length; i++){
  entries[i].time = new Date(entries[i].time);
  entries[i].time = (entries[i].time.getUTCMonth()+1) + "." + entries[i].time.getUTCFullYear();
};

Wynik wyszukiwania fasetowego po konwersji dat:

[ { count: 1,       time: '12.2006' },
  { count: 2,       time: '1.2007'  },
  { count: 2,       time: '2.2007'  },
  { count: 1,       time: '3.2007'  },
  { count: 1,       time: '4.2007'  },
  { count: 1,       time: '12.2007' },
  { count: 1,       time: '6.2008'  },
  { count: 2,       time: '7.2008'  },
  { count: 19,      time: '8.2008'  },
  { count: 28,      time: '9.2008'  },
  { count: 128,     time: '10.2008' },
  { count: 294,     time: '11.2008' },
  { count: 115,     time: '12.2008' },
  { count: 282,     time: '1.2009'  },
  { count: 119,     time: '2.2009'  },
  { count: 218,     time: '3.2009'  },
  { count: 344,     time: '4.2009'  },
  { count: 389,     time: '5.2009'  },
  { count: 586,     time: '6.2009'  },
  { count: 808,     time: '7.2009'  },
  { count: 2301,    time: '8.2009'  },
  { count: 2748,    time: '9.2009'  },
  { count: 8904,    time: '10.2009' },
  { count: 16751,   time: '11.2009' },
  { count: 43289,   time: '12.2009' },
  { count: 34958,   time: '1.2010'  },
  { count: 32006,   time: '2.2010'  },
  { count: 65592,   time: '3.2010'  },
  { count: 51768,   time: '4.2010'  },
  { count: 51585,   time: '5.2010'  },
  { count: 85401,   time: '6.2010'  },
  { count: 199294,  time: '7.2010'  },
  { count: 256512,  time: '8.2010'  },
  { count: 312460,  time: '9.2010'  },
  { count: 304326,  time: '10.2010' },
  { count: 362662,  time: '11.2010' },
  { count: 302035,  time: '12.2010' },
  { count: 496329,  time: '1.2011'  },
  { count: 428525,  time: '2.2011'  },
  { count: 441130,  time: '3.2011'  },
  { count: 538690,  time: '4.2011'  },
  { count: 630517,  time: '5.2011'  },
  { count: 700685,  time: '6.2011'  },
  { count: 954233,  time: '7.2011'  },
  { count: 947335,  time: '8.2011'  },
  { count: 1148994, time: '9.2011'  },
  { count: 1503366, time: '10.2011' },
  { count: 1810790, time: '11.2011' },
  { count: 1088950, time: '12.2011' },
  { count: 1145836, time: '1.2012'  },
  { count: 1382174, time: '2.2012'  },
  { count: 1643917, time: '3.2012'  },
  { count: 1687831, time: '4.2012'  },
  { count: 1081307, time: '5.2012'  } ]

####Wykresy

facets search 2 chart 1

facets search 2 chart 2

About

noSQL: Elasticsearch - Faceted Search

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages