{"id":33793,"date":"2019-10-31T21:54:42","date_gmt":"2019-10-31T18:54:42","guid":{"rendered":"https:\/\/prohoster.info\/blog\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti\/"},"modified":"2019-10-31T21:54:42","modified_gmt":"2019-10-31T18:54:42","slug":"bitmap-indeksy-v-go-poisk-na-dikoj-skorosti","status":"publish","type":"post","link":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti","title":{"rendered":"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/86ef928e6741022b2c0e5885a031408a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h2>Introducere<\/h2>\n<p>\nAm sus\u021binut aceast\u0103 prezentare \u00een limba englez\u0103 la conferin\u021ba GopherCon Rusia 2019 din Moscova \u0219i \u00een limba rus\u0103 la meet-up-ul din Nizhni Novgorod. Este vorba despre bitmap-index \u2014 mai pu\u021bin r\u0103sp\u00e2ndit dec\u00e2t B-tree, dar nu mai pu\u021bin interesant. \u00cemp\u0103rt\u0103\u0219esc <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/WvlUH6MjUuI?list=PL3xVZC4USRNSO_kb2lh_J_no6C-KJ7Phg\">\u00eenregistrarea<\/a><\/noindex> prezent\u0103rii de la conferin\u021b\u0103 \u00een limba englez\u0103 \u0219i transcrierea textului \u00een limba rus\u0103.<\/p>\n<p>Vom analiza cum func\u021bioneaz\u0103 bitmap-index, c\u00e2nd este mai bun, c\u00e2nd este mai pu\u021bin eficient dec\u00e2t celelalte indici \u0219i \u00een ce cazuri este semnificativ mai rapid dec\u00e2t ele; vom vedea \u00een ce SGBD populare exist\u0103 deja bitmap-indici; vom \u00eencerca s\u0103 scriem unul pe Go. Iar \"la desert\", ne vom folosi de biblioteci existente pentru a crea propria noastr\u0103 baz\u0103 de date super rapid\u0103 \u0219i specializat\u0103.<\/p>\n<p>Sper cu mare t\u0103rie c\u0103 eforturile mele se vor dovedi utile \u0219i interesante pentru voi. S\u0103 \u00eencepem!<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Introducere<\/h2>\n<p>\n<center><div class=\"youtube-placeholder\" data-id=\"WvlUH6MjUuI\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/WvlUH6MjUuI\/hqdefault.jpg\" alt=\"Reda\u021bi video\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><br \/>\n<noindex><a rel=\"nofollow\" href=\"http:\/\/bit.ly\/bitmapindexes\">http:\/\/bit.ly\/bitmapindexes<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/mkevac\/gopherconrussia2019\">https:\/\/github.com\/mkevac\/gopherconrussia2019<\/a><\/noindex><\/p>\n<p>Salut tuturor! Acum este ora \u0219ase seara, suntem cu to\u021bii foarte obosi\u021bi. Un moment minunat pentru a discuta despre teoria plictisitoare a indec\u0219ilor de baze de date, nu-i a\u0219a? Nu v\u0103 face\u021bi griji, voi avea c\u00e2teva linii de cod pe aici \u0219i pe acolo. \ud83d\ude42<\/p>\n<p>Serios vorbind, prezentarea este plin\u0103 de informa\u021bii, iar noi nu avem foarte mult timp. A\u0219a c\u0103 s\u0103 \u00eencepem.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/e778e13727700f0335a4b5558a0d8db3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAst\u0103zi voi vorbi despre urm\u0103toarele:<\/p>\n<ul>\n<li>ce sunt indec\u0219ii;\n<\/li>\n<li>ce este bitmap-index;\n<\/li>\n<li>unde este folosit \u0219i unde NU este folosit \u0219i de ce;\n<\/li>\n<li>o implementare simpl\u0103 pe Go \u0219i pu\u021bin\u0103 lupt\u0103 cu compilatorul;\n<\/li>\n<li>o implementare pu\u021bin mai complex\u0103, dar mult mai performant\u0103 pe asamblarea Go;\n<\/li>\n<li>\"problemele\" bitmap-indicilor;\n<\/li>\n<li>implement\u0103ri existente.\n<\/li>\n<\/ul>\n<h2>Ce sunt indec\u0219ii?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/b80e5b990c44814afe9150a9a82351fd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUn index este o structur\u0103 de date separat\u0103 pe care o p\u0103str\u0103m \u0219i o actualiz\u0103m pe l\u00e2ng\u0103 datele principale. Este utilizat\u0103 pentru a accelera c\u0103utarea. F\u0103r\u0103 indec\u0219i, c\u0103utarea ar necesita o trecere complet\u0103 prin date (proces numit full scan), iar acest proces are o complexitate algoritmic\u0103 liniar\u0103. Dar bazele de date con\u021bin de obicei o cantitate uria\u0219\u0103 de date \u0219i complexitatea liniar\u0103 este prea lent\u0103. \u00cen mod ideal, am dori s\u0103 ob\u021binem complexitate logaritmic\u0103 sau constant\u0103.<\/p>\n<p>Aceasta este o tem\u0103 uria\u0219\u0103 \u0219i complex\u0103, plin\u0103 de subtilit\u0103\u021bi \u0219i compromisuri, dar, av\u00e2nd \u00een vedere zeci de ani de dezvoltare \u0219i cercetare a diferitelor baze de date, sunt preg\u0103tit s\u0103 afirm c\u0103 exist\u0103 doar c\u00e2teva abord\u0103ri utilizate pe scar\u0103 larg\u0103 pentru crearea indec\u0219ilor de baze de date.<\/p>\n<p><img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/08a74dbb365035cd99bc94d72644a1b7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPrima abordare const\u0103 \u00een reducerea ierarhic\u0103 a domeniului de c\u0103utare, \u00eemp\u0103r\u021bind domeniul de c\u0103utare \u00een p\u0103r\u021bi mai mici.<\/p>\n<p>De obicei, facem asta folosind diverse tipuri de arbori. Un exemplu poate fi o cutie mare cu materiale \u00een dulapul t\u0103u, \u00een care se afl\u0103 cutii mai mici cu materiale \u00eemp\u0103r\u021bite pe diverse teme. Dac\u0103 ai nevoie de materiale, cu siguran\u021b\u0103 le vei c\u0103uta \u00een cutia cu eticheta \u201eMateriale\u201d, nu \u00een cea cu eticheta \u201eBiscui\u021bi\u201d, nu-i a\u0219a?<\/p>\n<p><img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/423fac47c748980b18af434644af4dae.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA doua abordare const\u0103 \u00een a eviden\u021bia imediat elementul sau grupul dorit de elemente. Facem asta \u00een hash maps sau \u00een indici inversa\u021bi. Utilizarea hash maps este foarte asem\u0103n\u0103toare cu exemplul anterior, doar c\u0103 \u00een dulapul t\u0103u ai o mul\u021bime de cutii mici cu obiecte finale.<\/p>\n<p><img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/088fed0a2a0feea4a23edbf0ca654805.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA treia abordare este de a sc\u0103pa de necesitatea c\u0103ut\u0103rii. Facem asta cu ajutorul filtrelor Bloom sau filtrelor cuckoo. Primele ofer\u0103 un r\u0103spuns instantaneu, eliber\u00e2ndu-te de necesitatea de a efectua o c\u0103utare.<\/p>\n<p><img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/493bc4f20baacc0a5dc0faf15cc46285.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUltima abordare const\u0103 \u00een a utiliza pe deplin toate capacit\u0103\u021bile pe care ni le ofer\u0103 hardware-ul modern. Asta facem cu indici bitmap. Da, \u00een utilizarea lor, uneori trebuie s\u0103 parcurgem \u00eentregul indice, dar o facem super eficient.<\/p>\n<p>A\u0219a cum am spus, tema indicilor de baze de date este vast\u0103 \u0219i plin\u0103 de compromisuri. Acest lucru \u00eenseamn\u0103 c\u0103 uneori putem folosi mai multe abord\u0103ri simultan: dac\u0103 trebuie s\u0103 acceler\u0103m \u0219i mai mult c\u0103utarea sau dac\u0103 este necesar s\u0103 acoperim toate tipurile posibile de c\u0103utare.<\/p>\n<p>Ast\u0103zi voi vorbi despre cea mai pu\u021bin cunoscut\u0103 abordare men\u021bionat\u0103 \u2014 despre indicii bitmap.<\/p>\n<h2>Cine sunt eu s\u0103 vorbesc despre acest subiect?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/42a9d17a507c392bc202254a92dfaf41.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLucrez ca team lead la Badoo (poate c\u0103 \u0219tii mai bine un alt produs al nostru \u2014 Bumble). Avem deja peste 400 de milioane de utilizatori \u00een \u00eentreaga lume \u0219i multe func\u021bionalit\u0103\u021bi care se ocup\u0103 de a le oferi cea mai bun\u0103 pereche. Facem asta cu ajutorul serviciilor personalizate, care folosesc inclusiv indicii bitmap.<\/p>\n<h2>A\u0219adar, ce este un indice bitmap?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/14f20f3697a20c02f6b3510dc7f0ae4d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIndexurile bitmap, a\u0219a cum sugereaz\u0103 \u0219i numele, folosesc bitmapuri sau bitseturi pentru a implementa un index de c\u0103utare. Dintr-o perspectiv\u0103 de ansamblu, acest index const\u0103 din unul sau mai multe astfel de bitmapuri, care reprezint\u0103 entit\u0103\u021bi (de exemplu, oameni) \u0219i propriet\u0103\u021bile sau parametrii acestora (v\u00e2rst\u0103, culoare a ochilor etc.), precum \u0219i dintr-un algoritm care folose\u0219te opera\u021bii pe bi\u021bi (AND, OR, NOT) pentru a r\u0103spunde la interog\u0103rile de c\u0103utare.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/f815720330a51b1f0798e45d23160d3b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSe spune c\u0103 indexurile bitmap sunt cele mai potrivite \u0219i foarte eficiente \u00een cazurile \u00een care exist\u0103 o c\u0103utare care combin\u0103 interog\u0103rile pe multe coloane cu cardinalitate mic\u0103 (imagineaz\u0103-\u021bi \u201eculoare a ochilor\u201d sau \u201estare civil\u0103\u201d \u00een contrast cu ceva de tip \u201edistan\u021b\u0103 fa\u021b\u0103 de centrul ora\u0219ului\u201d). Dar mai t\u00e2rziu voi ar\u0103ta c\u0103 acestea func\u021bioneaz\u0103 foarte bine \u0219i \u00een cazul coloanelor cu cardinalitate mare.<\/p>\n<p>S\u0103 lu\u0103m un exemplu simplu de index bitmap.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/33fe23476e0931c10345d7175b83d68b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nImagina\u021bi-v\u0103 c\u0103 avem o list\u0103 de restaurante din Moscova cu propriet\u0103\u021bi binare precum acestea:<\/p>\n<ul>\n<li>l\u00e2ng\u0103 metrou (near metro);\n<\/li>\n<li>are parcare privat\u0103 (has private parking);\n<\/li>\n<li>are teras\u0103 (has terrace);\n<\/li>\n<li>accept\u0103 rezerv\u0103ri (accepts reservations);\n<\/li>\n<li>potrivit pentru vegetarieni (vegan friendly);\n<\/li>\n<li>scump (expensive).\n<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/fcbad539ea12f79a9d06966ce308637e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nS\u0103 atribuim fiec\u0103rui restaurant un num\u0103r secven\u021bial \u00eencep\u00e2nd de la 0 \u0219i s\u0103 aloc\u0103m memorie pentru 6 bitmapuri (c\u00e2te unul pentru fiecare caracteristic\u0103). Apoi, vom completa aceste bitmapuri \u00een func\u021bie de faptul dac\u0103 restaurantul are sau nu aceast\u0103 proprietate. Dac\u0103 restaurantul 4 are teras\u0103, atunci bitul nr. 4 din bitmapul \u201eare teras\u0103\u201d va fi setat la 1 (dac\u0103 nu are teras\u0103, va fi 0).<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/3709c426617d4364f392ee6b68f92b00.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAcum avem cel mai simplu index bitmap posibil, iar acesta poate fi folosit pentru a r\u0103spunde la interog\u0103ri precum:<\/p>\n<ul>\n<li>\u201eArat\u0103-mi restaurantele potrivite pentru vegetarieni\u201d;\n<\/li>\n<li>\u201eArat\u0103-mi restaurantele ieftine cu teras\u0103, unde pot face rezerv\u0103ri\u201d.\n<\/li>\n<\/ul>\n<p><img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/90acb0f890686bd52c3db1fc667f0b0b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/0fd0b7fe9f7b7039022ad5c79fe873bc.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nCum? Hai s\u0103 vedem. Prima interogare este foarte simpl\u0103. Tot ce trebuie s\u0103 facem este s\u0103 lu\u0103m bitmapul \u201epotrivit pentru vegetarieni\u201d \u0219i s\u0103-l transform\u0103m \u00eentr-o list\u0103 de restaurante, al c\u0103ror bi\u021bi sunt seta\u021bi.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/ef4a5cfd658ff4ef8bc0c638c4522d11.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/9cc175bae55c16018fdf5ff95517a61a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nA doua interogare este pu\u021bin mai complex\u0103. Trebuie s\u0103 folosim opera\u021bia bitwise NOT pe bitmap-ul \u201ecostisitor\u201d pentru a ob\u021bine o list\u0103 de restaurante ieftine, apoi s\u0103-l AND-\u0103m cu bitmap-ul \u201ese poate rezerva o mas\u0103\u201d \u0219i s\u0103 AND-\u0103m rezultatul cu bitmap-ul \u201eare teras\u0103\u201d. Bitmap-ul rezultat va con\u021bine o list\u0103 de unit\u0103\u021bi care \u00eendeplinesc toate criteriile noastre. \u00cen acest exemplu, este doar restaurantul \u201eJuventus\u201d.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/f1cdda0cbf7f15278553899cf876c17e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/126b50e0f622b6e36c461cd74e708c38.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAici este foarte mult\u0103 teorie, dar nu v\u0103 face\u021bi griji, vom vedea codul foarte cur\u00e2nd.<\/p>\n<h2>Unde se folosesc indec\u0219ii bitmap?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/406132236c71a4f66ae79957b6e633b3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDac\u0103 \u201eg\u0103si\u021bi pe Google\u201d indec\u0219ii bitmap, 90% din r\u0103spunsuri vor fi, \u00eentr-un fel sau altul, legate de Oracle DB. Dar celelalte SGBD-uri cu siguran\u021b\u0103 suport\u0103 \u0219i aceast\u0103 caracteristic\u0103 tare, nu-i a\u0219a? Nu chiar. <\/p>\n<p>S\u0103 trecem \u00een revist\u0103 lista principalelor suspec\u021bi.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/d18d66451a8a26b0ddf121f8ec0204cd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMySQL \u00eenc\u0103 nu suport\u0103 indec\u0219ii bitmap, dar exist\u0103 o propunere pentru a ad\u0103uga aceast\u0103 op\u021biune (<noindex><a rel=\"nofollow\" href=\"https:\/\/dev.mysql.com\/worklog\/task\/?id=1524\">https:\/\/dev.mysql.com\/worklog\/task\/?id=1524<\/a><\/noindex>).<\/p>\n<p>PostgreSQL nu suport\u0103 indec\u0219ii bitmap, dar folose\u0219te bitmap-uri simple \u0219i opera\u021bii bitwise pentru a combina rezultatele c\u0103ut\u0103rii pe mai mul\u021bi al\u021bi indec\u0219i.<\/p>\n<p>Tarantool are indec\u0219i bitset, permite c\u0103utarea simpl\u0103 pe acestea.<\/p>\n<p>Redis are c\u00e2mpuri bit simple<noindex><a rel=\"nofollow\" href=\"https:\/\/redis.io\/commands\/bitfield\"> (https:\/\/redis.io\/commands\/bitfield<\/a><\/noindex>) f\u0103r\u0103 posibilitatea de c\u0103utare pe acestea.<\/p>\n<p>MongoDB \u00eenc\u0103 nu suport\u0103 indec\u0219ii bitmap, dar exist\u0103 de asemenea o propunere pentru a ad\u0103uga aceast\u0103 op\u021biune <noindex><a rel=\"nofollow\" href=\"https:\/\/jira.mongodb.org\/browse\/SERVER-1723\">https:\/\/jira.mongodb.org\/browse\/SERVER-1723<\/a><\/noindex><\/p>\n<p>Elasticsearch utilizeaz\u0103 bitmap-uri intern<noindex><a rel=\"nofollow\" href=\"https:\/\/www.elastic.co\/blog\/frame-of-reference-and-roaring-bitmaps\"> (https:\/\/www.elastic.co\/blog\/frame-of-reference-and-roaring-bitmaps<\/a><\/noindex>).<\/p>\n<p>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/232d335963603d6e6dec98839fc9f486.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>Dar \u00een casa noastr\u0103 a ap\u0103rut un nou vecin: Pilosa. Aceasta este o nou\u0103 baz\u0103 de date nerela\u021bional\u0103, scris\u0103 \u00een Go. Con\u021bine doar indec\u0219i bitmap \u0219i se bazeaz\u0103 pe ace\u0219tia. Vom discuta despre ea pu\u021bin mai t\u00e2rziu.\n<\/li>\n<\/ul>\n<h2>Implementare \u00een Go<\/h2>\n<p>\nDar de ce indec\u0219ii bitmap sunt at\u00e2t de rar folosi\u021bi? \u00cenainte de a r\u0103spunde la aceast\u0103 \u00eentrebare, a\u0219 dori s\u0103 v\u0103 demonstrez o implementare foarte simpl\u0103 a unui indec\u0219 bitmap \u00een Go.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/ae7f4c1a4a740fe709b05dfaee27ac9b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nBitmap-urile, \u00een esen\u021b\u0103, sunt reprezentate doar ca buc\u0103\u021bi de date. \u00cen Go, s\u0103 folosim pentru asta slice-uri de bytes.<\/p>\n<p>Avem un bitmap pentru o caracteristic\u0103 a restaurantului, iar fiecare bit din bitmap arat\u0103 dac\u0103 un anumit restaurant are aceast\u0103 proprietate sau nu.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/1ab628ee15887d6b3c6c99855aa610c8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAvem nevoie de dou\u0103 func\u021bii auxiliare. Una va fi utilizat\u0103 pentru a umple bitmapurile noastre cu date aleatorii. Aleatorii, dar cu o probabilitate definit\u0103 c\u0103 restaurantul are fiecare proprietate. De exemplu, cred c\u0103 \u00een Moscova sunt foarte pu\u021bine restaurante \u00een care nu se poate rezerva o mas\u0103 \u0219i mi se pare c\u0103 aproximativ 20% dintre loca\u021bii sunt potrivite pentru vegetarieni.<\/p>\n<p>A doua func\u021bie va transforma bitmapul \u00eentr-o list\u0103 de restaurante.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/ab9c87a0ba63750116e2e7968f842a9a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/498cf7a33611d99b90197d4ee82e2834.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPentru a r\u0103spunde la cererea \u201eArat\u0103-mi restaurantele ieftine care au teras\u0103 \u0219i \u00een care se poate rezerva o mas\u0103\u201d, avem nevoie de dou\u0103 opera\u021bii bitwise: NOT \u0219i AND.<\/p>\n<p>Putem simplifica un pic codul nostru, folosind o opera\u021bie AND NOT mai complex\u0103.<\/p>\n<p>Avem func\u021bii pentru fiecare dintre aceste opera\u021bii. Ambele parcurg slice-urile, iau elementele corespunz\u0103toare din fiecare, le combin\u0103 prin opera\u021bia bitwise \u0219i plaseaz\u0103 rezultatul \u00eentr-un slice de rezultate.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/ec5652a34f0370dfb03df199f341f153.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u0218i acum putem folosi bitmapurile \u0219i func\u021biile noastre pentru a r\u0103spunde la cererea de c\u0103utare.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/cf9500ccfe75995a6008191c16729689.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPerforman\u021ba nu este at\u00e2t de bun\u0103, chiar dac\u0103 func\u021biile sunt foarte simple \u0219i am economisit destul de bine pe faptul c\u0103 nu returnam un nou slice de rezultate la fiecare apel al func\u021biei.<\/p>\n<p>Dup\u0103 c\u00e2teva profil\u0103ri cu pprof, am observat c\u0103 compilatorul Go a ratat o optimizare foarte simpl\u0103, dar extrem de important\u0103: inlining-ul func\u021biei.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/9092f5ba3940d0a4f3fbfa90b364d716.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nProblema este c\u0103 compilatorul Go se teme teribil de buclele care parcurg slice-urile \u0219i refuz\u0103 categoric s\u0103 fac\u0103 inlining la func\u021biile care con\u021bin astfel de bucle.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/d1bddd62b61b367dd1f680f223fa0ce7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDar eu nu m\u0103 tem \u0219i pot s\u0103 p\u0103c\u0103lesc compilatorul, folosind goto \u00een loc de bucle, ca \u00een vremurile bune.<\/p>\n<p><img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/5b1c3cb26b923972686047910ecd1c31.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/1ca31d12dc90931b674c6a86a4ea23bd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u0218i, dup\u0103 cum vede\u021bi, acum compilatorul face cu bucurie inlining la func\u021bia noastr\u0103! \u00cen cele din urm\u0103, reu\u0219im s\u0103 economisim aproximativ 2 microsecunde. Nu e r\u0103u!<\/p>\n<p><img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/bdd6735d16082573e600bffe2cdd5662.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAl doilea loc restric\u021bionat nu este greu de observat dac\u0103 te ui\u021bi cu aten\u021bie la output-ul assemblerului. Compilatorul a ad\u0103ugat o verificare de limite pentru slice direct \u00een cel mai fierbinte ciclu al nostru. Problema este c\u0103 Go este un limbaj sigur, compilatorul se teme c\u0103 cei trei argumenti ai mei (cele trei slice-uri) au dimensiuni diferite. Aceasta ar putea crea o posibilitate teoretic\u0103 de apari\u021bie a a\u0219a-zisei dep\u0103\u0219iri de buffer (buffer overflow).<\/p>\n<p>Haide\u021bi s\u0103-l lini\u0219tim pe compilator, ar\u0103t\u00e2ndu-i c\u0103 toate slice-urile au aceea\u0219i dimensiune. Putem face acest lucru ad\u0103ug\u00e2nd o verificare simpl\u0103 la \u00eenceputul func\u021biei noastre.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/59b4ce687a11dd653e9f12fc3130d89a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nV\u0103z\u00e2nd aceasta, compilatorul trece cu bucurie peste verificare, iar noi economisim \u00eenc\u0103 500 de nanosecunde.<\/p>\n<h2>Loturi mari<\/h2>\n<p>\nOk, am reu\u0219it s\u0103 extragem o anumit\u0103 performan\u021b\u0103 din implementarea noastr\u0103 simpl\u0103, dar acest rezultat este, de fapt, mult mai slab dec\u00e2t ar putea fi cu hardware-ul actual.<\/p>\n<p>Tot ce facem sunt opera\u021bii de baz\u0103 cu bi\u021bi, iar procesoarele noastre le execut\u0103 foarte eficient. Dar, din p\u0103cate, \"hr\u0103nim\" procesorul nostru cu foarte mici buc\u0103\u021bi de lucru. Func\u021biile noastre efectueaz\u0103 opera\u021bii pe byte. Putem ajusta cu u\u0219urin\u021b\u0103 codul nostru pentru a lucra cu buc\u0103\u021bi de 8 byte, folosind slice-uri UInt64.<\/p>\n<p><img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/8d1b60ba4b7046c836601631cadd0b6a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDup\u0103 cum vede\u021bi, aceast\u0103 mic\u0103 modificare a accelerat programul nostru de opt ori prin cre\u0219terea lotului de opt ori. C\u00e2\u0219tigul este, s\u0103 spunem, liniar.<\/p>\n<p><img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/0fc663412d04dd38b927de5c8776f69d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Implementare \u00een assembler<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/b3ef133167b89da983356b1c7389aecd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDar acesta nu este sf\u00e2r\u0219itul. Procesoarele noastre pot lucra cu buc\u0103\u021bi de 16, 32 \u0219i chiar 64 de byte. Astfel de opera\u021bii \"late\" sunt numite single instruction multiple data (SIMD; o instruc\u021biune, multe date), iar procesul de transformare a codului astfel \u00eenc\u00e2t s\u0103 utilizeze aceste opera\u021bii se nume\u0219te vectorizare.<\/p>\n<p>Din p\u0103cate, compilatorul Go nu este cel mai bun \u00een ceea ce prive\u0219te vectorizarea. \u00cen prezent, singurul mod de a vectoriza codul \u00een Go este s\u0103 iei \u0219i s\u0103 a\u0219ezi manual opera\u021biile datelor folosind assembler Go.<\/p>\n<p><img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/91278be45df67e1f9572d68fab7ebad1.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAssemblerul Go este o fiin\u021b\u0103 ciudat\u0103. Probabil \u0219ti\u021bi c\u0103 assemblerul este ceva ce este foarte legat de arhitectura computerului pentru care scrie\u021bi, dar \u00een Go nu este a\u0219a. Assemblerul Go este mai asem\u0103n\u0103tor cu IRL (intermediate representation language) sau limbaj de reprezentare intermediar\u0103: este practic independent de platform\u0103. Rob Pike a avut o prezentare excelent\u0103 <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=KINIAgRpkDA\">cu o prezentare<\/a><\/noindex> pe aceast\u0103 tem\u0103 acum c\u00e2\u021biva ani la GopherCon \u00een Denver.<\/p>\n<p>\u00cen plus, Go folose\u0219te un format neobi\u0219nuit, Plan 9, diferit de formatele bine cunoscute AT&amp;T \u0219i Intel.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/526f75eb18edfc2f851f2725e9d6f69e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSe poate spune cu siguran\u021b\u0103 c\u0103 scrierea manual\u0103 a assemblerului Go nu este cea mai distractiv\u0103 activitate.<\/p>\n<p>Dar, din fericire, exist\u0103 deja dou\u0103 unelte de nivel \u00eenalt care ne ajut\u0103 \u00een scrierea assemblerului Go: PeachPy \u0219i avo. Ambele utilitare genereaz\u0103 assembler Go dintr-un cod de nivel mai \u00eenalt, scris \u00een Python \u0219i Go, respectiv.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/b8a7aa2c585b805e9b1f2ada186b84e8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAceste utilitare simplific\u0103 activit\u0103\u021bi precum alocarea registrelor (selectarea unui registru CPU), scrierea buclelor \u0219i, \u00een general, faciliteaz\u0103 procesul de intrare \u00een lumea program\u0103rii \u00eenasmblere \u00een Go.<\/p>\n<p>Vom folosi avo, astfel \u00eenc\u00e2t programele noastre vor fi aproape programe obi\u0219nuite \u00een Go.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/128e4adef14e5f2cf00fb5b6302ef58e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIat\u0103 cum arat\u0103 cel mai simplu exemplu de program avo. Avem o func\u021bie main() care define\u0219te \u00een interiorul ei func\u021bia Add(), a c\u0103rei semnifica\u021bie const\u0103 \u00een adunarea a dou\u0103 numere. Exist\u0103 func\u021bii auxiliare pentru ob\u021binerea parametrilor dup\u0103 nume \u0219i pentru ob\u021binerea unuia dintre registreele potrivite \u0219i disponibile. Fiecare opera\u021bie procesorare are o func\u021bie corespunz\u0103toare \u00een avo, a\u0219a cum se poate observa la ADDQ. \u0218i \u00een final, vedem o func\u021bie auxiliar\u0103 pentru salvarea valorii rezultate.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/01ccaa6aa6d394ef598ea2dbc9257d87.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nApelez go generate, vom rula programul pe avo \u0219i, \u00een final, vor fi generate dou\u0103 fi\u0219iere:<\/p>\n<ul>\n<li>add.s cu codul rezultat \u00eenasmblere pentru Go;\n<\/li>\n<li>stub.go cu antetele func\u021biilor pentru a lega cele dou\u0103 lumi: Go \u0219i asamblatorul.\n<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/72a9443776ecf45eef6fb97a4e08acba.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAcum, c\u0103 am v\u0103zut ce \u0219i cum face avo, haide\u021bi s\u0103 ne uit\u0103m la func\u021biile noastre. Am implementat at\u00e2t versiuni scalare, c\u00e2t \u0219i vectoriale (SIMD) ale func\u021biilor.<\/p>\n<p>\u00cencepem prin a privi versiunile scalare.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/ec31dbb8b97b9d7c1012a120fa18cdaf.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nA\u0219a cum am f\u0103cut \u00een exemplul anterior, cerem s\u0103 ni se ofere un registru general corespunz\u0103tor \u0219i liber, nu trebuie s\u0103 calcul\u0103m deplas\u0103rile \u0219i dimensiunile pentru argumente. Totul acesta \u00eel face avo pentru noi.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/88085e927dd943ea0f808a28fb3ccf9b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAnterior, am folosit etichete \u0219i goto (sau s\u0103rituri) pentru a \u00eembun\u0103t\u0103\u021bi performan\u021ba \u0219i pentru a p\u0103c\u0103li compilatorul Go, dar acum facem asta de la bun \u00eenceput. Ideea este c\u0103 buclele sunt un concept de nivel mai \u00eenalt. \u00cen asamblare, avem doar etichete \u0219i s\u0103rituri.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/9a4181248eb279d89c1445a820b06649.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nCodul r\u0103mas ar trebui s\u0103 fie deja familiar \u0219i u\u0219or de \u00een\u021beles. Emul\u0103m bucla cu etichete \u0219i s\u0103rituri, lu\u0103m o mic\u0103 parte de date din cele dou\u0103 slice-uri ale noastre, le combin\u0103m printr-o opera\u021bie pe bi\u021bi (AND NOT \u00een acest caz) \u0219i apoi plas\u0103m rezultatul \u00een slice-ul rezultat. Totul.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/19275ead27f63092fc6596bed38a8d03.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIat\u0103 cum arat\u0103 codul final \u00een asamblare. Nu a trebuit s\u0103 calcul\u0103m deplas\u0103rile \u0219i dimensiunile (evidentiate \u00een verde) sau s\u0103 urm\u0103rim registrele utilizate (eviden\u021biate \u00een ro\u0219u).<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/ed68528a6f852634a5b536670c6315f0.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDac\u0103 compar\u0103m performan\u021ba implement\u0103rii \u00een assembler cu performan\u021ba celei mai bune implement\u0103ri \u00een Go, vom observa c\u0103 este identic\u0103. \u0218i acest lucru era de a\u0219teptat. Nu am f\u0103cut nimic special \u2014 doar am reprodus ceea ce ar face compilatorul Go.<\/p>\n<p>Din p\u0103cate, nu putem for\u021ba compilatorul s\u0103 \u00eenlinieze func\u021biile noastre scrise \u00een assembler. Compilatorul Go nu are \u00een prezent aceast\u0103 capacitate, de\u0219i cererea de a o ad\u0103uga exist\u0103 de ceva timp.<\/p>\n<p>De aceea, nu putem ob\u021bine avantaje de la func\u021biile mici \u00een assembler. Trebuie s\u0103 scriem fie func\u021bii mari, fie s\u0103 utiliz\u0103m noul pachet math\/bits, fie s\u0103 evit\u0103m assemblerul complet.<\/p>\n<p>Acum s\u0103 ne uit\u0103m la versiunile vectoriale ale func\u021biilor noastre.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/7f67c3cc855908fb47c7900d6e5d7f54.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPentru acest exemplu am decis s\u0103 aplic AVX2, a\u0219a c\u0103 vom folosi opera\u021biuni care lucreaz\u0103 cu buc\u0103\u021bi de 32 de bi\u021bi. Structura codului este foarte asem\u0103n\u0103toare cu varianta scalar\u0103: \u00eenc\u0103rcarea parametrilor, cererea unui registru general liber \u0219i a\u0219a mai departe.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/021e0424a0d733ec7db9edeb98ce1f65.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nUna dintre nout\u0103\u021bi este c\u0103 opera\u021biunile vectoriale mai largi folosesc registre speciale largi. \u00cen cazul buc\u0103\u021bilor de 32 de bi\u021bi, acestea sunt registre cu prefix Y. De aceea vede\u021bi func\u021bia YMM() \u00een cod. Dac\u0103 a\u0219 fi folosit AVX-512 cu buc\u0103\u021bi de 64 de bi\u021bi, prefixul ar fi fost Z.<\/p>\n<p>A doua noutate se refer\u0103 la faptul c\u0103 am decis s\u0103 folosesc o optimizare numit\u0103 desf\u0103\u0219urarea buclei (loop unrolling), adic\u0103 s\u0103 efectuez manual opt opera\u021biuni de ciclu \u00eenainte de a s\u0103ri \u00eenapoi la \u00eenceputul buclei. Aceast\u0103 optimizare reduce num\u0103rul de ramific\u0103ri (branching) din cod, iar aceasta este limitat\u0103 de num\u0103rul de registre libere disponibile.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/f54631d9e8c69f6f70ecace3133ae1e8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDar ce putem spune despre performan\u021b\u0103? Este fantastic\u0103! Am ob\u021binut o accelerare de aproximativ \u0219apte ori comparativ cu cea mai bun\u0103 solu\u021bie din Go. Impresionant, nu?<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/d7e85c933eecb243cfb49225b4d92c6c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDar chiar \u0219i aceast\u0103 implementare ar putea fi poten\u021bial accelerat\u0103, folosind AVX-512, prefetching sau JIT (compilator just-in-time) pentru planificatorul de cereri. Dar aceasta este cu siguran\u021b\u0103 o tem\u0103 pentru o prezentare separat\u0103.<\/p>\n<h2>Problemele indicilor bitmap<\/h2>\n<p>\nAcum, c\u00e2nd am examinat deja implementarea simpl\u0103 a unui index bitmap \u00een Go \u0219i mult mai performant\u0103 \u00een assembler, s\u0103 discut\u0103m \u00een sf\u00e2r\u0219it despre motivul pentru care indicii bitmap sunt at\u00e2t de rar utiliza\u021bi.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/83d36a5c92ba90fd680fe8afb6cfc11f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u00cen lucr\u0103rile \u0219tiin\u021bifice vechi se men\u021bioneaz\u0103 trei probleme ale indexurilor bitmap, dar lucr\u0103ri \u0219tiin\u021bifice mai recente \u0219i eu sus\u021binem c\u0103 acestea nu mai sunt relevante. Nu ne vom ad\u00e2nci \u00een fiecare dintre aceste probleme, dar le vom analiza superficial.<\/p>\n<h2>Problema cardinalit\u0103\u021bii mari<\/h2>\n<p>\nA\u0219adar, ni se spune c\u0103 indexurile bitmap sunt potrivite doar pentru c\u00e2mpuri cu cardinalitate mic\u0103, adic\u0103 acelea care au pu\u021bine valori (de exemplu, genul sau culoarea ochilor), iar motivul este c\u0103 reprezentarea obi\u0219nuit\u0103 a acestor c\u00e2mpuri (un bit pe valoare) \u00een cazul cardinalit\u0103\u021bii mari va ocupa prea mult spa\u021biu \u0219i, mai mult, aceste indexuri bitmap vor fi slab (rar) umplute.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/0787efc4d2cb4ea4d404ca7888b33697.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/44ab4bc7c25d14fe2f53caf5d9da399d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nUneori putem folosi o alt\u0103 reprezentare, de exemplu, reprezentarea standard pe care o folosim pentru a reprezenta numere. Dar fix apari\u021bia algoritmilor de compresie a schimbat totul. \u00cen ultimele decenii, oamenii de \u0219tiin\u021b\u0103 \u0219i cercet\u0103torii au inven\u021bionat o mul\u021bime de algoritmi de compresie pentru bitmap-uri. Principalul lor avantaj este c\u0103 nu trebuie s\u0103 decomprim\u0103m bitmap-urile pentru a efectua opera\u021bii pe bi\u021bi \u2014 putem efectua opera\u021bii pe bi\u021bi direct asupra bitmap-urilor comprimate.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/ecb54fbf15aa11271bbbab01ecbda880.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u00cen ultima vreme au ap\u0103rut \u0219i abord\u0103ri hibride, cum ar fi bitmap-urile roaring. Acestea folosesc simultan trei reprezent\u0103ri diferite pentru bitmap-uri \u2014 propriu-zis bitmap-uri, aranjamente \u0219i a\u0219a-numitele bit runs \u2014 \u0219i echilibreaz\u0103 \u00eentre ele pentru a maximiza performan\u021ba \u0219i a minimiza consumul de memorie.<\/p>\n<p>Pute\u021bi \u00eent\u00e2lni bitmap-uri roaring \u00een cele mai populare aplica\u021bii. Deja exist\u0103 o mul\u021bime de implement\u0103ri pentru cele mai diverse limbaje de programare, inclusiv mai mult de trei implement\u0103ri pentru Go.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/de2adfebc431ff48c996247b453f02ae.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nO alt\u0103 abordare care ne poate ajuta s\u0103 facem fa\u021b\u0103 cardinalit\u0103\u021bii mari se nume\u0219te grupare (binning). Imagineaz\u0103-\u021bi c\u0103 ai un c\u00e2mp care reprezint\u0103 \u00een\u0103l\u021bimea unei persoane. \u00cen\u0103l\u021bimea este un num\u0103r cu virgul\u0103 mobil\u0103, dar noi, oamenii, nu ne g\u00e2ndim la ea \u00een acest mod. Pentru noi nu exist\u0103 o diferen\u021b\u0103 \u00eentre \u00een\u0103l\u021bimea de 185,2 cm \u0219i cea de 185,3 cm.<\/p>\n<p>A\u0219adar, putem grupa valori asem\u0103n\u0103toare \u00een grupuri \u00een intervalul de 1 cm.<\/p>\n<p>\u0218i dac\u0103 mai \u0219tim c\u0103 foarte pu\u021bini oameni au o \u00een\u0103l\u021bime mai mic\u0103 de 50 cm \u0219i mai mare de 250 cm, atunci, practic, putem transforma un c\u00e2mp cu cardinalitate infinit\u0103 \u00eentr-un c\u00e2mp cu o cardinalitate de aproximativ 200 de valori.<\/p>\n<p>Desigur, dac\u0103 este necesar, putem efectua o filtrare suplimentar\u0103 ulterior.<\/p>\n<h2>Problema l\u0103\u021bimii de band\u0103 mari<\/h2>\n<p>\nUrm\u0103toarea problem\u0103 a indexurilor bitmap este c\u0103 actualizarea lor poate fi foarte costisitoare.<\/p>\n<p>Bazele de date trebuie s\u0103 permit\u0103 actualizarea datelor \u00een momentul \u00een care pot exista sute de alte solicit\u0103ri care caut\u0103 aceste date. Avem nevoie de bloc\u0103ri pentru a evita problemele de acces concurent la date sau alte probleme de partajare. Iar acolo unde exist\u0103 o mare blocare, apare problema \u2014 contentia de blocare, c\u00e2nd acel blocaj devine un punct critic.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/0ae1bf925542d286f8b7b245c160a35e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAceast\u0103 problem\u0103 poate fi rezolvat\u0103 sau ocolit\u0103 prin sharding sau utilizarea indexurilor versionate.<\/p>\n<p>Shardingul este un concept simplu \u0219i bine cunoscut. Pute\u021bi s\u0103 shardui\u021bi un index bitmap a\u0219a cum a\u021bi shardui orice alte date. \u00cen loc de o mare blocare, ve\u021bi ob\u021bine o mul\u021bime de bloc\u0103ri mici \u0219i astfel ve\u021bi sc\u0103pa de contentia de blocare.<\/p>\n<p>O alt\u0103 metod\u0103 de a rezolva problema este utilizarea indexurilor versionate. Pute\u021bi avea o copie a indexului pe care o folosi\u021bi pentru c\u0103utare sau citire \u0219i una pentru scriere sau actualizare. \u0218i la un anumit interval de timp (de exemplu, la fiecare 100 ms sau 500 ms) le duplicati \u0219i schimba\u021bi \u00eentre ele. Evident, aceast\u0103 abordare se aplic\u0103 doar \u00een cazurile \u00een care aplica\u021bia dvs. poate func\u021biona cu un index de c\u0103utare u\u0219or \u00eent\u00e2rziat.<\/p>\n<p>Aceste dou\u0103 abord\u0103ri pot fi utilizate simultan: pute\u021bi avea un index versionat sharduit.<\/p>\n<h2>Interog\u0103ri mai complexe<\/h2>\n<p>Ultima problem\u0103 a indexurilor bitmap este c\u0103, dup\u0103 cum ni se spune, acestea nu se potrivesc bine pentru tipuri mai complexe de interog\u0103ri, cum ar fi interog\u0103rile \"pe interval\".<\/p>\n<p>\u0218i adev\u0103rat, dac\u0103 ne g\u00e2ndim, opera\u021biile bitare de tip AND, OR etc. nu se potrivesc bine pentru interog\u0103ri de tip \"Arat\u0103-mi hotelurile cu pre\u021bul camerei \u00eentre 200 \u0219i 300 de dolari pe noapte\".<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/7bc2e129cad46fb5875c2b3018c39ff7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nO solu\u021bie naiv\u0103 \u0219i foarte nechibzuit\u0103 ar fi fost s\u0103 ob\u021binem rezultatele pentru fiecare valoare \u00een dolari \u0219i s\u0103 le combin\u0103m folosind opera\u021bia de tip OR.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/b9f8fc7945caa1866f8e0cfa8a04bd98.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nO solu\u021bie pu\u021bin mai corect\u0103 ar fi fost utilizarea grup\u0103rii. De exemplu, \u00een grupuri de 50 de dolari. Acest lucru ar accelera procesul nostru de 50 de ori.<\/p>\n<p>Dar problema este, de asemenea, u\u0219or de rezolvat prin utilizarea unei reprezent\u0103ri create special pentru acest tip de interog\u0103ri. \u00cen lucr\u0103rile \u0219tiin\u021bifice, se nume\u0219te bitmap-uri codificate pe intervale.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/644a420628b21f220a7af1ff15c4031f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u00centr-o astfel de reprezentare, nu simplu set\u0103m un bit pentru o anumit\u0103 valoare (de exemplu, 200), ci set\u0103m acea valoare \u0219i tot ce este mai mare. 200 \u0219i mai sus. La fel \u0219i pentru 300: 300 \u0219i mai sus. \u0218i a\u0219a mai departe.<\/p>\n<p>Folosind aceast\u0103 reprezentare, putem r\u0103spunde la astfel de interog\u0103ri de c\u0103utare parcurg\u00e2nd indexul doar de dou\u0103 ori. Mai \u00eent\u00e2i, vom ob\u021bine lista hotelurilor, unde pre\u021bul este mai mic de 300 de dolari, apoi vom elimina din aceast\u0103 list\u0103 cele cu pre\u021bul mai mic de 199 dolari. Gata.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/cc2bb58d7d7a51495c62ec7da81e2d12.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nVei fi surprins, dar chiar \u0219i interog\u0103rile geo sunt posibile utiliz\u00e2nd indexuri bitmap. Trucul const\u0103 \u00een a folosi o reprezentare geografic\u0103 care \u00eenconjoar\u0103 coordonata ta cu o figur\u0103 geometric\u0103. De exemplu, S2 de la Google. Figura trebuie s\u0103 poat\u0103 fi reprezentat\u0103 prin trei sau mai multe linii intersectate care pot fi numerotate. Astfel, vom putea transforma interogarea noastr\u0103 geo \u00een mai multe interog\u0103ri \u201epe interval\u201d (pe aceste linii numerotate).<\/p>\n<h2>Solu\u021bii gata f\u0103cute<\/h2>\n<p>\nSper c\u0103 te-am interesat pu\u021bin \u0219i ai acum un instrument util \u00een arsenalul t\u0103u. Dac\u0103 vreodat\u0103 vei avea nevoie s\u0103 faci ceva similar, vei \u0219ti \u00een ce direc\u021bie s\u0103 cau\u021bi.<\/p>\n<p>Cu toate acestea, nu toat\u0103 lumea are timp, r\u0103bdare \u0219i resurse pentru a crea indexuri bitmap de la zero. \u00cen special cele mai avansate, utiliz\u00e2nd SIMD, de exemplu.<\/p>\n<p>Din fericire, exist\u0103 c\u00e2teva solu\u021bii gata f\u0103cute care te pot ajuta.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/817b47cb189a758756b602ec9cf319e1.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Bitmap-uri Roaring<\/h2>\n<p>\nMai \u00eent\u00e2i, exist\u0103 biblioteca de bitmap-uri roaring despre care am men\u021bionat deja. Aceasta con\u021bine toate containele \u0219i opera\u021biile bit necesare pentru a crea un index bitmap complet.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/57f61a51485c174666b52dc2063fabe8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDin p\u0103cate, \u00een prezent, niciuna dintre implement\u0103rile Go nu folose\u0219te SIMD, ceea ce \u00eenseamn\u0103 c\u0103 implement\u0103rile Go sunt mai pu\u021bin eficiente dec\u00e2t cele \u00een C, de exemplu.<\/p>\n<h2>Pilosa<\/h2>\n<p>\nUn alt produs care te poate ajuta este SGBD-ul Pilosa, care, \u00een esen\u021b\u0103, are doar indexuri bitmap. Este o solu\u021bie relativ nou\u0103, dar c\u00e2\u0219tig\u0103 popularitate cu o vitez\u0103 incredibil\u0103.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/d3870a979e1e73d093fe5d5e9bb71cd8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPilosa utilizeaz\u0103 bitmap-uri roaring \u00een interiorul s\u0103u \u0219i v\u0103 ofer\u0103 posibilitatea de a le folosi, simplific\u00e2nd \u0219i explic\u00e2nd toate acele lucruri despre care am vorbit mai sus: grupare, bitmap-uri codificate pe interval, no\u021biunea de c\u00e2mp etc.<\/p>\n<p>S\u0103 arunc\u0103m o privire rapid\u0103 asupra unui exemplu de utilizare a Pilosa pentru a r\u0103spunde la o \u00eentrebare pe care o cunoa\u0219te\u021bi deja.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/dfee7abfd653cc19d9aa8b64c64f3e4e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nExemplul este foarte similar cu ceea ce a\u021bi v\u0103zut \u00eenainte. Cre\u0103m un client pentru serverul Pilosa, cre\u0103m un index \u0219i c\u00e2mpurile necesare, apoi umplem c\u00e2mpurile noastre cu date aleatorii cu probabilit\u0103\u021bi \u0219i, \u00een final, efectuam interogarea cunoscut\u0103.<\/p>\n<p>Dup\u0103 aceasta, folosim NOT pe c\u00e2mpul \u201eexpensive\u201d, apoi intersec\u021bion\u0103m rezultatul (sau facem AND) cu c\u00e2mpul \u201eterrace\u201d \u0219i cu c\u00e2mpul \u201ereservations\u201d. \u0218i, \u00een final, ob\u021binem rezultatul final.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/8d66c6d68019c2297b6c15b700f06a3a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSper foarte mult c\u0103, \u00een viitorul apropiat, tipuri noi de indici \u2014 bitmap-indici \u2014 vor ap\u0103rea \u0219i \u00een SGBD-uri precum MySQL \u0219i PostgreSQL.<br \/>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/7a8e33d576c7fb6376a173ee038b4206.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Concluzie<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Indici bitmap \u00een Go: c\u0103utare cu vitez\u0103 fulger\" src=\"\/wp-content\/uploads\/2019\/05\/c62caa9ad6f2d96056c80326f4fa9a0d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDac\u0103 nu a\u021bi adormit \u00eenc\u0103, v\u0103 mul\u021bumesc. A trebuit s\u0103 ating pe scurt multe subiecte din cauza timpului limitat, dar sper c\u0103 prezentarea a fost util\u0103 \u0219i, poate, chiar motivant\u0103.<\/p>\n<p>Este bine s\u0103 cunoa\u0219te\u021bi bitmap-\u00eendici, chiar dac\u0103 acum nu v\u0103 sunt necesari. S\u0103 fie un alt instrument \u00een trusa dumneavoastr\u0103.<\/p>\n<p>Am discutat diferite trucuri pentru \u00eembun\u0103t\u0103\u021birea performan\u021bei \u00een Go \u0219i acele lucruri cu care compilatorul Go \u00eenc\u0103 nu se descurc\u0103 foarte bine. Aceasta este absolut ceva ce fiecare programator Go ar trebui s\u0103 know.<\/p>\n<p>Asta este tot ce am vrut s\u0103 \u00eemp\u0103rt\u0103\u0219esc. V\u0103 mul\u021bumesc!<br \/>\n<br \/>Sursa: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/badoo\/blog\/451938\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412\u0441\u0442\u0443\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u042f \u0432\u044b\u0441\u0442\u0443\u043f\u0438\u043b \u0441 \u044d\u0442\u0438\u043c \u0434\u043e\u043a\u043b\u0430\u0434\u043e\u043c \u043d\u0430 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c \u044f\u0437\u044b\u043a\u0435 \u043d\u0430 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438 GopherCon Russia 2019 \u0432 \u041c\u043e\u0441\u043a\u0432\u0435 \u0438 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c \u2014 \u043d\u0430 \u043c\u0438\u0442\u0430\u043f\u0435 \u0432 \u041d\u0438\u0436\u043d\u0435\u043c \u041d\u043e\u0432\u0433\u043e\u0440\u043e\u0434\u0435. \u0420\u0435\u0447\u044c \u0432 \u043d\u0451\u043c \u0438\u0434\u0451\u0442 \u043e bitmap-\u0438\u043d\u0434\u0435\u043a\u0441\u0435 \u2014 \u043c\u0435\u043d\u0435\u0435 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0451\u043d\u043d\u043e\u043c, \u0447\u0435\u043c B-tree, \u043d\u043e \u043d\u0435 \u043c\u0435\u043d\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u043c. \u0414\u0435\u043b\u044e\u0441\u044c \u0437\u0430\u043f\u0438\u0441\u044c\u044e \u0432\u044b\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044f \u043d\u0430 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438 \u043d\u0430 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c \u0438 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0439 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c. \u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":25469,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-33793","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412\u0441\u0442\u0443\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u042f \u0432\u044b\u0441\u0442\u0443\u043f\u0438\u043b \u0441.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"ro_RO\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47Bitmap-\u0438\u043d\u0434\u0435\u043a\u0441\u044b \u0432 Go: \u043f\u043e\u0438\u0441\u043a \u043d\u0430 \u0434\u0438\u043a\u043e\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412\u0441\u0442\u0443\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u042f \u0432\u044b\u0441\u0442\u0443\u043f\u0438\u043b \u0441.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:54:42+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:54:42+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Bitmap-indici \u00een Go: c\u0103utare cu vitez\u0103 nebun\u0103 | ProHoster","description":"Cuv\u00e2nt introductiv Am sus\u021binut.","canonical_url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"ro_RO","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47Bitmap-\u0438\u043d\u0434\u0435\u043a\u0441\u044b \u0432 Go: \u043f\u043e\u0438\u0441\u043a \u043d\u0430 \u0434\u0438\u043a\u043e\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 | ProHoster","og:description":"\u0412\u0441\u0442\u0443\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u042f \u0432\u044b\u0441\u0442\u0443\u043f\u0438\u043b \u0441.","og:url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:54:42+00:00","article:modified_time":"2019-10-31T18:54:42+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"33793","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 16:43:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 02:33:25","updated":"2026-01-21 16:43:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/33793","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/comments?post=33793"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/33793\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media\/25469"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media?parent=33793"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/categories?post=33793"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/tags?post=33793"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}