{"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\/it\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti","title":{"rendered":"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/86ef928e6741022b2c0e5885a031408a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h2>Parola di apertura<\/h2>\n<p>\nHo presentato questa relazione in inglese alla conferenza GopherCon Russia 2019 a Mosca e in russo durante il meetup a Nizhny Novgorod. Si parla di bitmap index, meno comune del B-tree, ma altrettanto interessante. Condivido <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/WvlUH6MjUuI?list=PL3xVZC4USRNSO_kb2lh_J_no6C-KJ7Phg\">la registrazione<\/a><\/noindex> della mia presentazione alla conferenza in inglese e la trascrizione in russo.<\/p>\n<p>Analizzeremo come \u00e8 strutturato il bitmap index, quando \u00e8 migliore, quando \u00e8 peggiore rispetto ad altri indici e in quali casi \u00e8 significativamente pi\u00f9 veloce; vedremo in quali popolari DBMS sono gi\u00e0 presenti bitmap index; cercheremo di scrivere il nostro in Go. E come \"dessert\", utilizzeremo librerie gi\u00e0 pronte per creare un nostro database altamente specializzato e ultraveloce.<\/p>\n<p>Spero davvero che i miei sforzi risultino utili e interessanti per voi. Cominciamo!<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Introduzione<\/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=\"Guarda il 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>Ciao a tutti! Sono le sei di sera, siamo tutti super stanchi. \u00c8 un momento meraviglioso per parlare di noiosa teoria degli indici nei database, vero? Non preoccupatevi, avr\u00f2 un paio di righe di codice sorgente qui e l\u00e0. \ud83d\ude42<\/p>\n<p>Senza scherzi, la presentazione \u00e8 piena di informazioni e il nostro tempo \u00e8 limitato. Iniziamo.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/e778e13727700f0335a4b5558a0d8db3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nOggi parler\u00f2 di:<\/p>\n<ul>\n<li>cosa sono gli indici;\n<\/li>\n<li>cosa \u00e8 un bitmap index;\n<\/li>\n<li>dove viene utilizzato e dove NON viene utilizzato e perch\u00e9;\n<\/li>\n<li>una semplice implementazione in Go e un po' di lotta con il compilatore;\n<\/li>\n<li>un'implementazione leggermente meno semplice, ma molto pi\u00f9 performante in Go-assembly;\n<\/li>\n<li>\"problemi\" dei bitmap index;\n<\/li>\n<li>implementazioni esistenti.\n<\/li>\n<\/ul>\n<h2>Allora, cosa sono gli indici?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/b80e5b990c44814afe9150a9a82351fd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUn indice \u00e8 una struttura dati separata che manteniamo e aggiorniamo in aggiunta ai dati principali. Viene utilizzato per accelerare le ricerche. Senza indici, la ricerca richiederebbe una scansione completa dei dati (un processo noto come full scan), e questo processo ha una complessit\u00e0 algoritmica lineare. Ma i database di solito contengono enormi quantit\u00e0 di dati e la complessit\u00e0 lineare \u00e8 troppo lenta. Idealmente, vorremmo ottenere una complessit\u00e0 logaritmica o costante.<\/p>\n<p>\u00c8 un argomento vasto e complesso, ricco di sfumature e compromessi, ma, dopo aver osservato decenni di sviluppo e ricerca su vari database, sono pronto ad affermare che ci sono solo alcuni approcci ampiamente utilizzati per la creazione di indici nei database.<\/p>\n<p><img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/08a74dbb365035cd99bc94d72644a1b7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIl primo approccio consiste nella riduzione gerarchica dell'area di ricerca, dividendo l'area di ricerca in parti pi\u00f9 piccole.<\/p>\n<p>Di solito lo facciamo utilizzando vari tipi di alberi. Un esempio pu\u00f2 essere una grande scatola con materiali nel tuo armadio, che contiene scatole pi\u00f9 piccole con materiali divisi per vari argomenti. Se hai bisogno di materiali, sicuramente li cercherai nella scatola con la scritta \"Materiali\", e non in quella con scritto \"Biscotti\", giusto?<\/p>\n<p><img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/423fac47c748980b18af434644af4dae.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIl secondo approccio consiste nell'individuare immediatamente l'elemento necessario o il gruppo di elementi. Lo facciamo con le hash map o con gli indici inversi. L'uso delle hash map \u00e8 molto simile all'esempio precedente, solo che invece di avere una scatola con scatole, nel tuo armadio hai un mucchio di piccole scatole con oggetti finali.<\/p>\n<p><img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/088fed0a2a0feea4a23edbf0ca654805.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIl terzo approccio \u00e8 quello di eliminare la necessit\u00e0 di cercare. Questo lo facciamo utilizzando i filtri di Bloom o i filtri cuckoo. I primi forniscono una risposta istantanea, liberandoti dalla necessit\u00e0 di effettuare una ricerca.<\/p>\n<p><img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/493bc4f20baacc0a5dc0faf15cc46285.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nL'ultimo approccio consiste nell'utilizzare appieno tutte le potenzialit\u00e0 offerte dall'hardware moderno. Questo \u00e8 esattamente ci\u00f2 che facciamo negli indici bitmap. S\u00ec, quando li usiamo a volte dobbiamo scorrere l'intero indice, ma lo facciamo in modo super efficiente.<\/p>\n<p>Come ho gi\u00e0 detto, il tema degli indici del database \u00e8 vasto e pieno di compromessi. Questo significa che a volte possiamo usare pi\u00f9 approcci contemporaneamente: se abbiamo bisogno di accelerare ulteriormente la ricerca o se \u00e8 necessario coprire tutti i possibili tipi di ricerca.<\/p>\n<p>Oggi parler\u00f2 dell'approccio meno conosciuto tra quelli menzionati: gli indici bitmap.<\/p>\n<h2>Chi sono io per parlare di questo argomento?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/42a9d17a507c392bc202254a92dfaf41.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLavoro come team leader in Badoo (forse conosci meglio un nostro altro prodotto: Bumble). Abbiamo gi\u00e0 oltre 400 milioni di utenti in tutto il mondo e molte funzionalit\u00e0 che si occupano di trovare la migliore corrispondenza per loro. Lo facciamo attraverso servizi personalizzati, che utilizzano anche indici bitmap.<\/p>\n<h2>Allora, che cos'\u00e8 un indice bitmap?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/14f20f3697a20c02f6b3510dc7f0ae4d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nGli indici bitmap, come suggerisce il nome, utilizzano bitmap o bitset per implementare un indice di ricerca. Da un'altezza di volo d'uccello, questo indice consiste in una o pi\u00f9 di queste bitmap che rappresentano alcune entit\u00e0 (come le persone) e le loro propriet\u00e0 o parametri (et\u00e0, colore degli occhi, ecc.), e in un algoritmo che utilizza operazioni bit a bit (AND, OR, NOT) per rispondere a una query di ricerca.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/f815720330a51b1f0798e45d23160d3b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nCi viene detto che gli indici bitmap sono i pi\u00f9 adatti e molto efficienti nei casi in cui ci sia una ricerca che unisce richieste su pi\u00f9 colonne con bassa cardinalit\u00e0 (immaginate \"colore degli occhi\" o \"stato civile\" rispetto a qualcosa come \"distanza dal centro citt\u00e0\"). Ma pi\u00f9 tardi mostrer\u00f2 che funzionano egregiamente anche con colonne ad alta cardinalit\u00e0.<\/p>\n<p>Consideriamo un esempio semplice di indice bitmap.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/33fe23476e0931c10345d7175b83d68b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nImmaginate di avere un elenco di ristoranti a Mosca con propriet\u00e0 binarie come queste:<\/p>\n<ul>\n<li>vicino alla metropolitana (near metro);\n<\/li>\n<li>ha parcheggio privato (has private parking);\n<\/li>\n<li>ha veranda (has terrace);\n<\/li>\n<li>accetta prenotazioni (accepts reservations);\n<\/li>\n<li>vegan friendly (adatto ai vegetariani);\n<\/li>\n<li>costoso (expensive).\n<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/fcbad539ea12f79a9d06966ce308637e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAssegniamo a ciascun ristorante un numero progressivo a partire da 0 e riserviamo spazio per 6 bitmap (una per ogni caratteristica). Successivamente, riempiremo queste bitmap a seconda che il ristorante abbia o meno la caratteristica in questione. Se il ristorante 4 ha una veranda, il bit n\u00b04 nella bitmap \"ha veranda\" sar\u00e0 impostato su 1 (se non c'\u00e8 veranda, sar\u00e0 0).<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/3709c426617d4364f392ee6b68f92b00.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nOra abbiamo l'indice bitmap pi\u00f9 semplice possibile e possiamo utilizzarlo per rispondere a query come:<\/p>\n<ul>\n<li>\"Mostrami i ristoranti adatti ai vegetariani\";\n<\/li>\n<li>\"Mostrami i ristoranti economici con veranda, dove posso prenotare un tavolo.\"\n<\/li>\n<\/ul>\n<p><img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/90acb0f890686bd52c3db1fc667f0b0b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/0fd0b7fe9f7b7039022ad5c79fe873bc.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nCome? Vediamo. La prima query \u00e8 molto semplice. Tutto ci\u00f2 di cui abbiamo bisogno \u00e8 prendere la bitmap \"adatto ai vegetariani\" e trasformarla in un elenco di ristoranti i cui bit sono attivi.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/ef4a5cfd658ff4ef8bc0c638c4522d11.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/9cc175bae55c16018fdf5ff95517a61a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLa seconda query \u00e8 un po' pi\u00f9 complessa. Dobbiamo utilizzare l'operazione bit a bit NOT sulla bitmap \"costosa\" per ottenere un elenco di ristoranti economici, poi fare un AND con la bitmap \"prenotabile\" e fare un altro AND con la bitmap \"con veranda\". La bitmap risultante conterr\u00e0 un elenco di locali che soddisfano tutti i nostri criteri. In questo esempio, si tratta solo del ristorante \"Giovent\u00f9\".<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/f1cdda0cbf7f15278553899cf876c17e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/126b50e0f622b6e36c461cd74e708c38.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nC'\u00e8 molta teoria qui, ma non preoccupatevi, vedremo il codice molto presto.<\/p>\n<h2>Dove vengono utilizzati gli indici bitmap?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/406132236c71a4f66ae79957b6e633b3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSe cercate su Google gli indici bitmap, il 90% delle risposte saranno in qualche modo collegate a Oracle DB. Ma anche gli altri DBMS sicuramente supportano questa caratteristica interessante, vero? Non proprio. <\/p>\n<p>Facciamo un elenco dei principali sospettati.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/d18d66451a8a26b0ddf121f8ec0204cd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMySQL non supporta ancora gli indici bitmap, ma c'\u00e8 una proposta per aggiungere questa opzione (<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 non supporta gli indici bitmap, ma utilizza bitmap semplici e operazioni bit a bit per unire i risultati della ricerca su altri indici.<\/p>\n<p>Tarantool ha indici bitset, supporta ricerche semplici su di essi.<\/p>\n<p>Redis ha semplici campi bit<noindex><a rel=\"nofollow\" href=\"https:\/\/redis.io\/commands\/bitfield\"> (https:\/\/redis.io\/commands\/bitfield<\/a><\/noindex>) senza possibilit\u00e0 di ricerca su di essi.<\/p>\n<p>MongoDB non supporta ancora gli indici bitmap, ma c'\u00e8 anche una proposta per aggiungere questa opzione. <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 utilizza bitmap all'interno<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 in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/232d335963603d6e6dec98839fc9f486.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>Ma nella nostra casa \u00e8 arrivato un nuovo vicino: Pilosa. \u00c8 un nuovo database non relazionale, scritto in Go. Contiene solo indici bitmap e basa tutto su di essi. Ne parleremo pi\u00f9 tardi.\n<\/li>\n<\/ul>\n<h2>Implementazione in Go<\/h2>\n<p>\nMa perch\u00e9 gli indici bitmap sono cos\u00ec raramente utilizzati? Prima di rispondere a questa domanda, vorrei mostrarvi l'implementazione di un semplice indice bitmap in Go.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/ae7f4c1a4a740fe709b05dfaee27ac9b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLe bitmap, in sostanza, sono rappresentate semplicemente come pezzi di dati. In Go usiamo un array di byte per questo.<\/p>\n<p>Abbiamo una bitmap per una caratteristica del ristorante, e ogni bit nella bitmap indica se un determinato ristorante ha o meno quella caratteristica.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/1ab628ee15887d6b3c6c99855aa610c8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAvremo bisogno di due funzioni ausiliarie. Una verr\u00e0 utilizzata per riempire le nostre bitmap con dati casuali. Casuali, ma con una certa probabilit\u00e0 che il ristorante possieda ciascuna caratteristica. Ad esempio, ritengo che a Mosca ci siano pochissimi ristoranti in cui non sia possibile prenotare un tavolo, e mi sembra che circa il 20% dei locali sia adatto ai vegetariani.<\/p>\n<p>La seconda funzione convertir\u00e0 la bitmap in un elenco di ristoranti.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/ab9c87a0ba63750116e2e7968f842a9a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/498cf7a33611d99b90197d4ee82e2834.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPer rispondere alla richiesta \"Mostrami ristoranti economici con veranda in cui sia possibile prenotare un tavolo\", avremo bisogno di due operazioni bitwise: NOT e AND.<\/p>\n<p>Possiamo semplificare un po' il nostro codice, utilizzando un'operazione AND NOT pi\u00f9 complessa.<\/p>\n<p>Abbiamo funzioni per ciascuna di queste operazioni. Entrambe percorrono le slice, prendono gli elementi corrispondenti da ciascuna, li combinano con un'operazione bitwise e mettono il risultato in una slice di output.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/ec5652a34f0370dfb03df199f341f153.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEd \u00e8 cos\u00ec che possiamo utilizzare le nostre bitmap e le funzioni per rispondere alla richiesta di ricerca.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/cf9500ccfe75995a6008191c16729689.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLe prestazioni non sono cos\u00ec elevate, anche se le funzioni sono molto semplici e abbiamo risparmiato parecchio non restituendo una nuova slice di output ogni volta che la funzione viene chiamata.<\/p>\n<p>Profilando un po' con pprof, ho notato che il compilatore Go ha trascurato una ottimizzazione molto semplice ma fondamentale: l'inlining delle funzioni.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/9092f5ba3940d0a4f3fbfa90b364d716.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIl fatto \u00e8 che il compilatore Go teme terribilmente i cicli che attraversano le slice e si rifiuta categoricamente di inlinare le funzioni che contengono tali cicli.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/d1bddd62b61b367dd1f680f223fa0ce7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMa io non ho paura e posso ingannare il compilatore, utilizzando goto invece di un ciclo, come ai vecchi tempi.<\/p>\n<p><img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/5b1c3cb26b923972686047910ecd1c31.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/1ca31d12dc90931b674c6a86a4ea23bd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nE, come puoi vedere, ora il compilatore inlinando la nostra funzione con piacere! Alla fine riusciamo a risparmiare circa 2 microsecondi. Non male!<\/p>\n<p><img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/bdd6735d16082573e600bffe2cdd5662.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIl secondo collo di bottiglia \u00e8 facile da vedere se si guarda attentamente all'output assembly. Il compilatore ha aggiunto un controllo dei limiti della slice direttamente all'interno del nostro ciclo pi\u00f9 caldo. Il punto \u00e8 che Go \u00e8 un linguaggio sicuro, il compilatore teme che i miei tre argomenti (tre slice) abbiano dimensioni diverse. Infatti, ci sarebbe una possibilit\u00e0 teorica di overflow del buffer.<\/p>\n<p>Calmiamo il compilatore, mostrandogli che tutti i nostri slice hanno la stessa dimensione. Possiamo fare ci\u00f2 aggiungendo un semplice controllo all'inizio della nostra funzione.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/59b4ce687a11dd653e9f12fc3130d89a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nVedendo questo, il compilatore felice salta il controllo, e noi risparmiamo ben 500 nanosecondi.<\/p>\n<h2>Batch grandi<\/h2>\n<p>\nOkay, siamo riusciti a estrarre una certa performance dalla nostra semplice implementazione, ma questo risultato \u00e8, di fatto, molto peggiore di quanto potrebbe essere con l'hardware attuale.<\/p>\n<p>Tutto ci\u00f2 che facciamo sono operazioni bitwise di base, e i nostri processori le eseguono in modo molto efficiente. Purtroppo, per\u00f2, \u00abnutriamo\u00bb il nostro processore con piccoli pezzi di lavoro. Le nostre funzioni eseguono operazioni byte per byte. Possiamo facilmente ottimizzare il nostro codice affinch\u00e9 lavori con pezzi di 8 byte, usando slice di UInt64.<\/p>\n<p><img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/8d1b60ba4b7046c836601631cadd0b6a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCome potete vedere, questo piccolo cambiamento ha accelerato il nostro programma di otto volte grazie all'aumento del batch di otto volte. Il guadagno, si pu\u00f2 dire, \u00e8 lineare.<\/p>\n<p><img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/0fc663412d04dd38b927de5c8776f69d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Implementazione in assembly<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/b3ef133167b89da983356b1c7389aecd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMa non \u00e8 finita qui. I nostri processori possono lavorare con pezzi di 16, 32 e persino 64 byte. Queste \u00aboperazioni ampie\u00bb sono chiamate single instruction multiple data (SIMD; una istruzione, molti dati), e il processo di trasformazione del codice in modo che utilizzi tali operazioni \u00e8 denominato vettorizzazione.<\/p>\n<p>Sfortunatamente, il compilatore Go non \u00e8 un campione di vettorizzazione. Attualmente, l'unico modo per vettorizzare il codice in Go \u00e8 di prendere e scrivere manualmente le operazioni dei dati utilizzando l'assembly Go.<\/p>\n<p><img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/91278be45df67e1f9572d68fab7ebad1.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nL'assembly Go \u00e8 una bestia strana. Sapete sicuramente che l'assembly \u00e8 qualcosa di fortemente legato all'architettura del computer per cui scrivete, ma in Go non \u00e8 cos\u00ec. L'assembly Go \u00e8 pi\u00f9 simile a un IRL (intermediate representation language) o linguaggio di rappresentazione intermedia: \u00e8 praticamente indipendente dalla piattaforma. Rob Pike ha tenuto un eccellente <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=KINIAgRpkDA\">relazione<\/a><\/noindex> su questo argomento qualche anno fa al GopherCon a Denver.<\/p>\n<p>In aggiunta a ci\u00f2, Go utilizza un formato insolito chiamato Plan 9, che si differenzia dai formati standardizzati AT&amp;T e Intel.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/526f75eb18edfc2f851f2725e9d6f69e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSi pu\u00f2 affermare con certezza che scrivere manualmente in assembly Go non \u00e8 un compito molto divertente.<\/p>\n<p>Ma, fortunatamente, ci sono gi\u00e0 due strumenti di alto livello che ci aiutano a scrivere assembly Go: PeachPy e avo. Entruti gli strumenti generano assembly Go da un codice di livello superiore, scritto rispettivamente in Python e Go.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/b8a7aa2c585b805e9b1f2ada186b84e8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nQuesti strumenti semplificano cose come l'allocazione dei registri (selezione di un registro del processore), la scrittura di cicli e, in generale, semplificano il processo di ingresso nel mondo della programmazione in assembly in Go.<\/p>\n<p>Utilizzeremo avo, quindi i nostri programmi saranno quasi normali programmi Go.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/128e4adef14e5f2cf00fb5b6302ef58e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEcco come appare l'esempio pi\u00f9 semplice di un programma avo. Abbiamo una funzione main() che definisce al suo interno la funzione Add(), il cui scopo \u00e8 sommare due numeri. Qui sono presenti funzioni ausiliarie per ottenere i parametri per nome e per ottenere uno dei registri del processore liberi e adatti. Ogni operazione del processore ha una corrispondente funzione in avo, come si pu\u00f2 vedere in ADDQ. Infine, vediamo una funzione ausiliaria per memorizzare il valore risultante.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/01ccaa6aa6d394ef598ea2dbc9257d87.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEseguendo go generate, eseguiremo il programma in avo e alla fine verranno generati due file:<\/p>\n<ul>\n<li>add.s con il codice risultante in assembly Go;\n<\/li>\n<li>stub.go con le intestazioni delle funzioni per collegare i due mondi: Go e assembly.\n<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/72a9443776ecf45eef6fb97a4e08acba.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nOra che abbiamo visto cosa e come fa avo, diamo un'occhiata alle nostre funzioni. Ho implementato sia le versioni scalari che quelle vettoriali (SIMD) delle funzioni.<\/p>\n<p>Iniziamo a guardare le versioni scalari.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/ec31dbb8b97b9d7c1012a120fa18cdaf.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nCome nell'esempio precedente, chiediamo di fornirci un registro di uso generale libero e corretto, non dobbiamo calcolare offset e dimensioni per gli argomenti. Tutto questo \u00e8 gestito da avo per noi.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/88085e927dd943ea0f808a28fb3ccf9b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIn precedenza, utilizzavamo etichette e goto (o salti) per migliorare le prestazioni e per ingannare il compilatore Go, ma adesso lo facciamo fin dall'inizio. Il fatto \u00e8 che i cicli sono un concetto di livello superiore. In assembly, abbiamo solo etichette e salti.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/9a4181248eb279d89c1445a820b06649.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIl codice rimanente dovrebbe essere gi\u00e0 familiare e chiaro. Emuliamo un ciclo con etichette e salti, prendiamo una piccola parte di dati da entrambe le nostre fette, li uniamo tramite un'operazione bitwise (AND NOT in questo caso) e poi mettiamo il risultato nella fetta risultante. Tutto qui.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/19275ead27f63092fc6596bed38a8d03.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEcco come appare il codice finale in assembly. Non abbiamo dovuto calcolare offset e dimensioni (evidenziati in verde) o tenere traccia dei registri utilizzati (evidenziati in rosso).<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/ed68528a6f852634a5b536670c6315f0.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSe confrontiamo le prestazioni dell'implementazione in assembly con quelle della migliore implementazione in Go, vediamo che sono equivalenti. E questo \u00e8 prevedibile. Non abbiamo fatto nulla di speciale: abbiamo semplicemente riprodotto ci\u00f2 che farebbe il compilatore Go.<\/p>\n<p>Sfortunatamente, non possiamo costringere il compilatore ad applicare inline le nostre funzioni scritte in assembly. Al momento, il compilatore Go non ha questa possibilit\u00e0, anche se la richiesta di aggiungerla esiste gi\u00e0 da tempo.<\/p>\n<p>Proprio per questo motivo \u00e8 impossibile ottenere vantaggi da piccole funzioni in assembly. Dobbiamo scrivere funzioni pi\u00f9 grandi, oppure utilizzare il nuovo pacchetto math\/bits, oppure evitare totalmente l'assembly.<\/p>\n<p>Ora diamo un'occhiata alle versioni vettoriali delle nostre funzioni.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/7f67c3cc855908fb47c7900d6e5d7f54.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPer questo esempio ho deciso di utilizzare AVX2, quindi useremo operazioni che lavorano con blocchi da 32 byte. La struttura del codice \u00e8 molto simile a quella della versione scalare: caricamento dei parametri, richiesta di un registro generale libero e cos\u00ec via.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/021e0424a0d733ec7db9edeb98ce1f65.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nUna delle novit\u00e0 riguarda il fatto che le operazioni vettoriali pi\u00f9 ampie utilizzano registri speciali e pi\u00f9 ampi. Nel caso di blocchi da 32 byte, si tratta di registri con il prefisso Y. Ecco perch\u00e9 vedi la funzione YMM() nel codice. Se avessi usato AVX-512 con blocchi da 64 bit, il prefisso sarebbe stato Z.<\/p>\n<p>La seconda novit\u00e0 riguarda l'ottimizzazione che ho deciso di utilizzare, chiamata espansione del ciclo (loop unrolling), ovvero eseguire otto operazioni del ciclo manualmente prima di tornare all'inizio del ciclo. Questa ottimizzazione riduce il numero di branch nel codice e \u00e8 limitata dal numero di registri liberi disponibili.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/f54631d9e8c69f6f70ecace3133ae1e8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nE riguardo alle prestazioni? Sono fantastiche! Abbiamo ottenuto un'accelerazione di circa sette volte rispetto alla migliore soluzione in Go. Impressionante, vero?<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/d7e85c933eecb243cfb49225b4d92c6c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMa anche questa implementazione potrebbe essere potenzialmente accelerata utilizzando AVX-512, prefetching o JIT (just-in-time compiler) per il pianificatore delle query. Ma questa \u00e8 sicuramente materia per una presentazione a parte.<\/p>\n<h2>Problemi degli indici bitmap<\/h2>\n<p>\nOra che abbiamo esaminato una semplice implementazione dell'indice bitmap in Go e una molto pi\u00f9 performante in assembly, parliamo finalmente del motivo per cui gli indici bitmap sono cos\u00ec raramente utilizzati.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/83d36a5c92ba90fd680fe8afb6cfc11f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nNei vecchi studi scientifici si menzionano tre problemi degli indici bitmap, ma studi pi\u00f9 recenti e io stesso affermiamo che non sono pi\u00f9 attuali. Non approfondiamo ciascuno di questi problemi, ma li consideriamo superficialmente.<\/p>\n<h2>Il problema dell'alta cardinalit\u00e0<\/h2>\n<p>\nDunque, ci viene detto che gli indici bitmap sono adatti solo per campi con bassa cardinalit\u00e0, cio\u00e8 quelli che hanno pochi valori (ad esempio, sesso o colore degli occhi), e la ragione \u00e8 che la rappresentazione comune di tali campi (un bit per valore) nel caso di alta cardinalit\u00e0 occuperebbe troppo spazio e, inoltre, questi indici bitmap sarebbero scarsamente (raramente) popolati.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/0787efc4d2cb4ea4d404ca7888b33697.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/44ab4bc7c25d14fe2f53caf5d9da399d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nA volte possiamo utilizzare un'altra rappresentazione, ad esempio quella standard che usiamo per rappresentare i numeri. Ma \u00e8 stata l'emergere di algoritmi di compressione a cambiare tutto. Negli ultimi decenni, scienziati e ricercatori hanno ideato un gran numero di algoritmi di compressione per bitmap. Il loro principale vantaggio \u00e8 che non \u00e8 necessario decomprimere i bitmap per eseguire operazioni bit a bit: possiamo effettuare operazioni bit a bit direttamente sui bitmap compressi.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/ecb54fbf15aa11271bbbab01ecbda880.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nUltimamente sono emersi anche approcci ibridi, come i bitmap roaring. Essi utilizzano contemporaneamente tre rappresentazioni diverse per i bitmap: i bitmap stessi, gli array e le cosiddette sequenze di bit \u2014 bilanciando tra di esse per massimizzare le prestazioni e minimizzare il consumo di memoria.<\/p>\n<p>Puoi incontrare bitmap roaring nelle applicazioni pi\u00f9 popolari. Gi\u00e0 esistono un'enorme quantit\u00e0 di implementazioni per i pi\u00f9 svariati linguaggi di programmazione, incluse oltre tre implementazioni per Go.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/de2adfebc431ff48c996247b453f02ae.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nUn altro approccio che pu\u00f2 aiutarci a gestire un'alta cardinalit\u00e0 \u00e8 chiamato raggruppamento (binning). Immagina di avere un campo che rappresenta l'altezza di una persona. L'altezza \u00e8 un numero con virgola mobile, ma noi umani non la consideriamo in questo modo. Non c'\u00e8 differenza per noi tra un'altezza di 185,2 cm e una di 185,3 cm.<\/p>\n<p>In effetti, possiamo raggruppare valori simili in gruppi all'interno di 1 cm.<\/p>\n<p>E se sappiamo anche che ci sono molto poche persone che hanno un'altezza inferiore a 50 cm e superiore a 250 cm, allora possiamo, in sostanza, trasformare un campo con una cardinalit\u00e0 infinita in un campo con una cardinalit\u00e0 di circa 200 valori.<\/p>\n<p>Certo, se necessario, possiamo effettuare un'ulteriore filtrazione anche in seguito.<\/p>\n<h2>Problema di grande capacit\u00e0 di elaborazione<\/h2>\n<p>\nIl problema degli indici bitmap \u00e8 che il loro aggiornamento pu\u00f2 essere molto costoso.<\/p>\n<p>I database devono consentire l'aggiornamento dei dati nel momento in cui centinaia di altre query stanno cercando in questi dati. Abbiamo bisogno di lock per evitare problemi di accesso concorrente ai dati o altri problemi di accesso condiviso. Dove c'\u00e8 un grande lock, c'\u00e8 un problema: la contention da lock, quando quel lock diventa un collo di bottiglia.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/0ae1bf925542d286f8b7b245c160a35e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nQuesto problema pu\u00f2 essere risolto o aggirato tramite lo sharding o l'uso di indici versionati.<\/p>\n<p>Lo sharding \u00e8 una cosa semplice e ben nota. Puoi shardare un indice bitmap proprio come shardaresti qualsiasi altro dato. Invece di un grande lock avrai molti piccoli lock e cos\u00ec facendo eliminerai la contention da lock.<\/p>\n<p>Un secondo modo per risolvere il problema \u00e8 utilizzare indici versionati. Puoi avere una copia dell'indice che utilizzi per cercare o leggere, e una per scrivere o aggiornare. E ogni tot tempo (ad esempio, ogni 100 ms o 500 ms) le duplicati e scambi le loro posizioni. Naturalmente, questo approccio \u00e8 applicabile solo nei casi in cui la tua applicazione pu\u00f2 lavorare con un indice di ricerca leggermente in ritardo.<\/p>\n<p>Questi due approcci possono essere utilizzati simultaneamente: puoi avere un indice versionato shardato.<\/p>\n<h2>Query pi\u00f9 complesse<\/h2>\n<p>L'ultimo problema degli indici bitmap \u00e8 che, come ci dicono, non si adattano bene a tipi di query pi\u00f9 complessi, ad esempio le query \"per intervallo\".<\/p>\n<p>E in effetti, se ci pensi, le operazioni bitwise come AND, OR, ecc. non si adattano molto bene a richieste come \"Mostrami gli hotel con prezzi delle stanze da 200 a 300 dollari a notte\".<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/7bc2e129cad46fb5875c2b3018c39ff7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nUna soluzione ingenua e molto poco saggia sarebbe prendere i risultati per ogni valore in dollari e combinarli usando l'operazione OR.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/b9f8fc7945caa1866f8e0cfa8a04bd98.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nUna soluzione leggermente pi\u00f9 corretta sarebbe utilizzare il raggruppamento. Ad esempio, in gruppi da 50 dollari. Questo accelererebbe il nostro processo di 50 volte.<\/p>\n<p>Ma il problema si risolve facilmente utilizzando una rappresentazione creata appositamente per questo tipo di richieste. Nei lavori scientifici viene chiamata bitmap codificata per intervallo.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/644a420628b21f220a7af1ff15c4031f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIn tale rappresentazione non impostiamo semplicemente un bit per un valore specifico (ad esempio, 200), ma impostiamo quel valore e tutto ci\u00f2 che \u00e8 superiore. 200 e oltre. Lo stesso vale per 300: 300 e oltre. E cos\u00ec via.<\/p>\n<p>Utilizzando questa rappresentazione, possiamo rispondere a questo tipo di ricerca passando attraverso l'indice solo due volte. Prima otteniamo un elenco di hotel in cui il costo della camera \u00e8 inferiore a 300 dollari, e poi eliminiamo quelli in cui il costo della camera \u00e8 inferiore a 199 dollari. Fatto.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/cc2bb58d7d7a51495c62ec7da81e2d12.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nRimarrete sorpresi, ma anche le richieste geografiche sono possibili con l'uso di indici bitmap. Il trucco consiste nell'utilizzare una rappresentazione geografica che circonda le vostre coordinate con una figura geometrica. Ad esempio, S2 di Google. La figura deve poter essere rappresentata da tre o pi\u00f9 linee intersecanti, che possono essere numerate. In questo modo possiamo trasformare la nostra richiesta geospaziale in pi\u00f9 richieste \"per intervallo\" (su queste linee numerate).<\/p>\n<h2>Soluzioni pronte<\/h2>\n<p>\nSpero di aver suscitato un po' il vostro interesse e che ora abbiate un altro strumento utile nel vostro arsenale. Se mai avrete bisogno di fare qualcosa di simile, saprete in quale direzione guardare.<\/p>\n<p>Tuttavia, non tutti hanno il tempo, la pazienza e le risorse per creare indici bitmap da zero. Soprattutto quelli pi\u00f9 avanzati, con l'uso di SIMD, ad esempio.<\/p>\n<p>Fortunatamente, ci sono alcune soluzioni pronte che possono aiutarvi.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/817b47cb189a758756b602ec9cf319e1.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Bitmap Roaring<\/h2>\n<p>\nPer prima cosa, c'\u00e8 la biblioteca di bitmap roaring di cui ho gi\u00e0 parlato. Contiene tutti i contenitori e le operazioni bit necessarie per creare un indice bitmap completo.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/57f61a51485c174666b52dc2063fabe8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSfortunatamente, al momento nessuna delle implementazioni in Go utilizza SIMD, il che significa che le implementazioni in Go sono meno performanti rispetto a quelle in C, ad esempio.<\/p>\n<h2>Pilosa<\/h2>\n<p>\nUn altro prodotto che pu\u00f2 aiutarvi \u00e8 il database Pilosa, il quale \u00e8 essenzialmente basato esclusivamente su indici bitmap. \u00c8 una soluzione relativamente nuova, ma sta conquistando consensi a una velocit\u00e0 incredibile.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/d3870a979e1e73d093fe5d5e9bb71cd8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPilosa utilizza bitmap roaring al suo interno e ti consente di usarli, semplificando e spiegando tutte quelle cose di cui ho parlato sopra: raggruppamento, bitmap codificati per intervallo, concetto di campo, ecc.<\/p>\n<p>Diamo un'occhiata veloce a un esempio di utilizzo di Pilosa per rispondere a una domanda che gi\u00e0 conosci.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/dfee7abfd653cc19d9aa8b64c64f3e4e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nL'esempio \u00e8 molto simile a quello che hai visto prima. Creiamo un client per il server di Pilosa, creiamo un indice e i campi necessari, poi riempiamo i nostri campi con dati casuali con probabilit\u00e0 e, infine, eseguiamo la richiesta familiare.<\/p>\n<p>Dopo di che utilizziamo NOT sul campo 'costoso', quindi intersechiamo il risultato (o AND) con il campo 'terrazza' e con il campo 'prenotazioni'. E infine, otteniamo il risultato finale.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/8d66c6d68019c2297b6c15b700f06a3a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSpero davvero che nel prossimo futuro anche nei database come MySQL e PostgreSQL ci sar\u00e0 questo nuovo tipo di indici \u2014 gli indici bitmap.<br \/>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/7a8e33d576c7fb6376a173ee038b4206.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Conclusione<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Indici Bitmap in Go: ricerca a velocit\u00e0 selvaggia\" src=\"\/wp-content\/uploads\/2019\/05\/c62caa9ad6f2d96056c80326f4fa9a0d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSe non ti sei ancora addormentato, grazie. Ho dovuto toccare molte tematiche a volo a causa del tempo limitato, ma spero che la presentazione sia stata utile e, forse, anche motivante.<\/p>\n<p>\u00c8 bene sapere degli indici bitmap, anche se al momento non ne hai bisogno. Siano un altro strumento nella tua cassetta degli attrezzi.<\/p>\n<p>Abbiamo esaminato vari trucchi per aumentare le prestazioni di Go e quelle cose con cui il compilatore Go non gestisce molto bene. Questo \u00e8 assolutamente utile da sapere per ogni programmatore Go.<\/p>\n<p>Questo \u00e8 tutto ci\u00f2 che volevo raccontarti. Grazie!<br \/>\n<br \/>Fonte: <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.1.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\/it\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\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\/it\/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-index in Go: ricerca a velocit\u00e0 incredibile | ProHoster","description":"Parola di apertura Ho fatto un intervento con.","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","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\/it\/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\/it\/wp-json\/wp\/v2\/posts\/33793","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=33793"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/33793\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media\/25469"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=33793"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=33793"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=33793"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}