Rozrastáme sa, hľadáme programátora
Znalosť Elasticsearch ani REDIS nie je podmienkou
Viac info »
Elasticsearch
Elasticsearch je NoSQL vyhľadávací engine, ktorý využívajú stránky ako napr. Wikipedia, soundcloud, LinkedIn, uber, alebo ebay. Je distribuovaný, teda sa veľmi jednoducho škáluje, keď vám už výkon, alebo priestor nestačí. Jednoducho tak, že iba zapnete ďalší server.
Počet zobrazených stránok SAShE.sk
Pridanie ďalšieho serveru a vytvorenie clusteru navyše umožňuje plánovaný, alebo neplánovaný výpadok niekoľkých serverov - ostatné servery okamžite preberú úlohy vypadnutých nodov.
Elasticsearch všetky vkladané dáta indexuje, tak aby sa v nich dalo neskôr veľmi rýchlo hľadať. Narozdiel od MySQL sa toto indexovanie deje na pozadí, takže užívateľ naň nečaká. Nevýhoda z toho vyplývajúca, s ktorou treba počítať, je tá, že dáta nie sú k dispozícii okamžite po vložení, ale až po niekoľkých milisekundách. Ak teda na jednom riadku niečo vložíte, a v ďalšom to chcete nájsť, pravdepodobne sa vám to nepodarí. Odmenou za to bude to, že vyhľadávanie bude rýchle. Naozaj rýchle.
Ukážka dokumentu vo formáte JSON:
{ "string_id": "hematitovy-filigran-namornicke-koleso" , "login": "Petrilla" , "title_item": "N5247863_63063_20150325_68551.jpg" , "title_item_width": 1794 , "title_item_height": 1221 , "id_seller": 63063 , "maincategory": 58 , "subcategory": 61 , "sub2category": 136 , "price": 0.4 , "dostupnost": 1 , "material": [15, 156] , "color": 13 , "date_add": "2015-03-25T16:12:17" , "title": "Hematitový filigrán - námornícke koleso" , "text": "Jednoduchý ornamentálny filigrán s 3 vedúcimi otvormi vo farbe hematitu" , "keywords": "vianočný, veniec, vianoce, hnedý, ozdoby, babioles" , "count_likes": 163 }
Ktoré časti SAShE používajú Elasticsearch?
1. Našepkávač vyhľadávania
Pre dobre fungujúci našepkávač je klúčový dobre nastavený Tokenizer. Tokenizer je proces, ktorý vložený reťazec rozloží na tokeny a tieto tokeny potom zaindexuje.
Štandardný tokenizer napríklad frázu “čelenka na svadbu” rozloží na tri tokeny “čelenka” “na” a “svadbu”. Frázy nášho našepkávača ale nepoužívajú štandardný tokenizer, ale front side edgeNgram. Ten vytvorí oveľa viac tokenov, pre každú časť frázy jeden, pekne po písmenku - “č” “če” “čel” atď.
Návštevníkom sa potom vpisované frázy po každom stlačení klávesy, hľadajú práve v tomto indexe, a tým, že sú frázy zaindexované presne tak, ako ich užívateľ píše, je odozva hľadania veľmi rýchla.
Zaindexované frázy sú pri našepkávači rôzneho druhu, jednak sú to názvy kategórií a ich synonymá, ďalej predajcami vkladané kľúčové slová, ale tiež návštevníkmi často hľadané viacslovné frázy, na ktoré máme v databáze výrobkov relevantné výsledky.
2. Samotné vyhľadávanie vecí
Našepkávač teda pri písaní hľadá v predpripravených frázach, po odoslaní sa ale dotaz odošle na hlavný index výrobkov. Ten už používa štandardný tokenizér, vyhľadáva teda iba celé slová, navyše však používa slovenský hunspell filter.
Hunspell je opensource slovník používaný na opravu preklepov. Elasticserach má priamu podporu tohoto formátu slovníka a dokáže ho použiť na prevedenie slova na jeho základný tvar. Frázu “biela čelenka na svadbu” prevedie na tokeny “biely” “čelenka” “na” “svadba”.
Ukážka query danej frázy v daných poliach dokumenotov, odpoveď vráti aj fazety pre podkategóriu, prvých 24 výsledkov zoradených podľa dátumu pridania:
{ "query":{ "multi_match":{ "query":"+čelenka +na +svadbu", "fields":["title", "text", "keywords"], "operator":"and" } }, "aggs":{ "category":{ "terms":{ "field":"subcategory" } } }, "from":0, "size":24, "sort":[ { "date_add":"desc", "_score":"desc" } ] }
Taký istý proces sa vykoná aj s hľadanou frázou, čoho praktickým výsledkom je to, že návštevník nemusí skúšať skloňovať hľadanú frázu, ale mu vraciame vždy rovnaké výsledky.
Samozrejme pri indexovaní môžete použiť viacero tokenizerov, jeden nevyskloňovaný, jeden v základnom tvare a jeden s odstránenou diakritikou a pri vyhľadávaní podľa potreby mixovať výsledky. Elasticsearch má tiež podporu pre opravu preklepov vo vyhľadávanej fráze, alebo funkciu “Mysleli ste: “ ako ju poznáte z Googlu. Ak potrebujete vyhľadávať napríklad iba vo výrobkoch od svojich obľúbených predajcov, stačí ich mená poslať ako jeden string do query a či ich je 5 alebo 2000, elasticsearchu to nerobí vážnejšie problémy.
3. Fazety
Elasticsearch nie je len fulltext search engine, veľmi dobre si poradí aj so štruktúrovanými poľami dokumentu, vie teda veľmi rýchlo vyhľadávať napríklad podľa kategórie výrobku, alebo podľa ceny, vie spolu s výsledkami hľadania vracať aj fazety. Fazety sú zosumarizované počty (county) výsledkov podľa inej dimenzie vyhľadávania. Napríklad hľadáte frázu srdce v kategórii oblečenie a on spolu s výsledkami vyhľadávania vráti počty výsledkov vyhľadávania tejto frázy v podkategóriách oblečenia, môžete teda ukázať rozbalený zoznam a rovno vypísať Tričká - 359, Sukne - 266 atď. To všetko v reálnom čase v jednotkách milisekúnd.
4. Kolaboratívne filtrovanie
Elasticsearch používame aj na odporúčanie predajcov alebo výrobkov na základe podobnosti. Existuje na to priamo fukncia “More like this”. Táto vie priamo na základe podobnosti s jedným alebo viacerými dokumentmi odporučiť dokumenty ďalšie.
Podobnosť sa dá určovať jednak na základe obsahu dokumentov, teda pri výrobkoch napríklad podľa kategórie, farby, štýlu, kľúčových slov. Druhá možnosť je kolaboratívne, teda na základe aktivít ďalších používateľov. Tieto aktivity môžu byť napríklad prezretie výrobku, alebo označenie “páči sa mi” pri výrobku.
V praxi to potom funguje tak, že výrobok má pri sebe uložené id uživateľov, ktorí ho videli, lajkli, alebo zakúpili. Tieto id sú uložené oddelené medzerami jednoducho ako jeden reťazec. Elasticsearch sa postará pri indexácii o všetko potrebné.
{ "seller_login": "MeDada", "who_like_him": "328 335 1296 1456 1844 1962 2321 2329 2824 2882 2993 3379 3394 3414 3962 4004 4174 4408 4698 4800 4964 4981 5222 5420 5752 5776 6159 ...", "popularity": 404, "live_count": 87, "categories": "71", "materials": "36" }
Do more like this dotazu vložíte veci, ktoré užívateľ videl, elasticsearch sám vyberie vzorku signifikantných užívateľov (teda napríklad vylúči užívateľov, ktorí videli príliš málo, alebo príliš veľa vecí) ktorí videli tie isté veci, a vráti ďalšie veci, ktoré daní užívatelia videli, zoradené pekne podľa toho, koľkí z nich ich videli.
{ "query":{ "filtered":{ "query":{ "more_like_this":{ "fields":["who_like_him", "categories", "materials"], "like":[ - hľadaj podobných predajcov ako je ten s id 256398 { "_index":"similar-sellers", "_type":"seller", "_id":"256398" } ], "min_term_freq":1, "max_query_terms":500, "min_doc_freq":20, "minimum_should_match":"10%" } }, "filter":{ "bool":{ "must_not": { - ak ich lajkujem ja s ID 1, tak ich vylúč "term": { "who_like_him":"1" } }, "must":{ - zahrň iba predajcov s popularitou<1000 "range":{ "popularity":{ "gte":0, "lte":1000 } } } } } } }, "size": 5 }
Táto query sa dá kombinovať aj s obsahovou podobnosťou. Nakoniec je dobré z výsledku vylúčiť veci, ktoré užívateľ už videl.
Toto všetko vie elasticsearch vykonať v reálnom čase, v desiatkach milisekúnd. More like this query má parameter veľkosti vzorky, ktorým si určujete pomer presnosť/rýchlosť odozvy.
Kibana
K elasticsearchu existuje aj grafické rozhranie kibana, ktoré slúži na prehľadávanie a vizualizáciu dát. Môžete tak v reálnom čase vidieť rôzne prehľady a štatistiky.
Kibana a počty odoslaných správ za posledných 12 hodín
Dohľad nad clustrom zabezpečuje plugin do kibany marvel. V ňom vidíte počty dokumentov jednotlivých indexov, stav a rýchlosť indexácie a tiež stav a rýchlosť vyhľadávania. Vidíte tiež alokáciu jednotlivých častí indexov naprieč nodami, teda servermi. Pri rôznom vyťažení nodov elasticsearch sám alokuje a presúva indexy bezvýpadkovo zo servera na server.
REDIS
Kým máte jeden server, a potrebujete si niečo niekam v PHP uložiť, aby ste si to neskôr mohli prečítať, a potrebujete to fakt rýchlo, tak najrýchlejšia je APC. Napríklad potrebujete cestu k avataru používateľa podľa id. Joinovať tabuľku userov je od istého počtu užívateľov utrpenie a tak hľadáte niečo, nejakú cache.
APC je okrem iného aj jednoduchá key-value cache. Niečo vložíte pod nejakým kľúčom, neskôr to tam nájdete. Ak prečítanie z MySQL trvá 10 ms, z APC to trvá 0,003ms. Cesty k avatarom teda odtiaľ môžete čítať po jednom userovi, je to úplne v kľude. Samozrejme APC má aj svoje nevýhody, tá hlavná je, že APC nie je perzistentné, teda pri rôznych príležitostiach sa celé zmaže. Vačšinou ju používame ako cache typu - "pozri sa do APC či to tam je, ak to tam je tak OK, použi to, ak to tam nie je, vyber to z MySQL a ulož to tam, napríklad na 5 minút." Druhá hlavná nevýhoda APC je, že je čisto lokálne, nedá sa zdielať medzi servermi, toto sa často rieši použitím memcache. Ak chcete ísť ešte kúsok ďalej, je tu REDIS.
REDIS je rýchla pamäťová cache, ktorá pridáva k memcache niekoľko fukncií navyše. Redis používa napríklad aj Twitter, Pinterest, Snapchat alebo Instagram. REDIS nie je taký rýchly ako APC, povedzme, že vytiahnutie trvá 0,1ms, stále je to ale 100x rýchlejšie ako z MySQL, zvláda teda stovky tisíc requestov za sekundu. Do redisu si môžete dovoliť niečo začať ukladať rýchlosťou, ktorá by MySQL v momente poslala k zemi. REDIS je oproti memcache perzistentný, teda ukladá svoj obsah vo zvolených intervaloch na disk, ďalej má napríklad podporu množín, alebo zoznamov. Zoznamy sashe používa napríklad na ukladanie naposledy prezretých výrobkov, pre každého používateľa je vytvorený zoznam, do neho sa vloží id prezretej veci a zoznam sa skráti na veľkosť 20 záznamov. Fotka a url veci sa tiež vloží do REDISU. Pri každom kliku sa potom tento zoznam na jeden zreťazený request vytiahne. Celé to trvá ani nie milisekundu. Nad množinami vie REDIS veľmi rýchlo vytvárať napríklad prieniky. V REDISE máme množinu prihlásených uživateľov, a tiež napríklad množiny obľúbených predajcov každého uživateľa. Veľmi rýchlo tak vieme vytiahnuť zoznam všetkých tvojich obľúbených predajcov, ktorí sú práve prihlásení, alebo napr. spoločných obľúbených predajcov dvoch používateľov.
Ukážka zápisu veci do zoznamu prezretých vecí:
$redis->select(3); $redis->multi(Redis::PIPELINE) ->set("lvt:thing:".$thing['id'],json_encode(array($thing['string_id'],....))) ->lPush("lvt:list:".$key,$thing['id']) ->ltrim("lvt:list:".$key,0,19) ->expire("lvt:list:".$key,3600*24*1) ->lPush("lvt:global",$thing['id']) ->ltrim("lvt:global",0,9) ->exec();
V $key je identifikátor uživateľa, buď cez COOKIE, alebo SESSION
- Zvolí sa databáza č.3
- Naštartuje sa multiquery
- Uloží sa vec pod kľúčom lvt:thing:idveci
- Do uživateľovho listu lvt:list:idusera sa pripíše nazačiatok idveci
- Skrátime list na 20 záznamov
- Nastavíme expiráciu listu na 24 hodín
- Pripíšeme toto id aj do globálneho listu
- A skrátime tento globálny list na 10 záznamov
Rozrastáme sa, hľadáme programátora
Znalosť Elasticsearch ani REDIS nie je podmienkou
Viac info »