{"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\/nl\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti","title":{"rendered":"Bitmap-indexen in Go: zoeken met hoge snelheid","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/86ef928e6741022b2c0e5885a031408a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h2>Inleidende opmerking<\/h2>\n<p>\nIk heb deze presentatie in het Engels gepresenteerd op de GopherCon Rusland 2019 in Moskou en in het Russisch tijdens de meetup in Nizhny Novgorod. Het gaat over de bitmap-index \u2014 minder vaak voorkomend dan de B-tree, maar zeker niet minder interessant. Ik deel <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/WvlUH6MjUuI?list=PL3xVZC4USRNSO_kb2lh_J_no6C-KJ7Phg\">de opname<\/a><\/noindex> van de presentatie op de conferentie in het Engels en de tekstuele transcriptie in het Russisch.<\/p>\n<p>We gaan bekijken hoe een bitmap-index werkt, wanneer deze beter is, wanneer slechter dan andere indexen, en in welke gevallen hij aanzienlijk sneller is; we zullen zien in welke populaire DBMS al bitmap-indexen bestaan; en we zullen proberen onze eigen index te schrijven in Go. En als 'toetje' gaan we gebruik maken van kant-en-klare bibliotheken om onze eigen super snelle gespecialiseerde database te maken.<\/p>\n<p>Ik hoop dat mijn inspanningen nuttig en interessant voor jullie zullen zijn. Laten we beginnen!<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Inleiding<\/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=\"Video afspelen\" 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>Hallo allemaal! Het is nu zes uur 's avonds, we zijn allemaal super vermoeid. Geweldige tijd om over de saaie theorie van database-indexen te praten, nietwaar? Maak je geen zorgen, ik zal hier en daar een paar stukjes broncode delen. \ud83d\ude42<\/p>\n<p>Als we serieus zijn, dan is de presentatie vol met informatie en hebben we niet zo veel tijd. Dus laten we beginnen.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/e778e13727700f0335a4b5558a0d8db3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nVandaag ga ik het volgende bespreken:<\/p>\n<ul>\n<li>wat indexen zijn;\n<\/li>\n<li>wat een bitmap-index is;\n<\/li>\n<li>waar deze wordt gebruikt en waar hij NIET wordt gebruikt en waarom;\n<\/li>\n<li>een eenvoudige implementatie in Go en wat worstelen met de compiler;\n<\/li>\n<li>een iets minder eenvoudige, maar veel productievere implementatie in Go-assembler;\n<\/li>\n<li>de 'problemen' van bitmap-indexen;\n<\/li>\n<li>bestaande implementaties.\n<\/li>\n<\/ul>\n<h2>Wat zijn indexen?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/b80e5b990c44814afe9150a9a82351fd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEen index is een aparte datastructuur die we behouden en bijwerken naast de hoofdata. Deze wordt gebruikt om zoekopdrachten te versnellen. Zonder indexen zou een zoekopdracht een volledige doorlooptijd over de data vereisen (een proces dat full scan wordt genoemd), en dit proces heeft een lineaire algoritmische complexiteit. Maar databases bevatten meestal enorme hoeveelheden data en lineaire complexiteit is veel te traag. Idealiter willen we logaritmische of constante complexiteit.<\/p>\n<p>Dit is een enorm complex onderwerp, vol nuances en compromissen, maar na tientallen jaren ontwikkeling en onderzoek naar verschillende databases ben ik bereid te stellen dat er maar een paar breed gebruikte benaderingen zijn voor het cre\u00ebren van database-indexen.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/08a74dbb365035cd99bc94d72644a1b7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDe eerste benadering bestaat uit het hi\u00ebrarchisch verkleinen van het zoekgebied, het opdelen van het zoekgebied in kleinere delen.<\/p>\n<p>Gewoonlijk doen we dit met behulp van verschillende soorten bomen. Een voorbeeld hiervan is een grote doos met materialen in uw kast, waarin kleinere dozen met materialen zijn verdeeld op verschillende thema's. Als u naar materialen zoekt, zult u zeker in de doos met het label \"Materialen\" kijken en niet in de doos met het label \"Koekjes\", toch?<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/423fac47c748980b18af434644af4dae.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDe tweede benadering is om meteen het benodigde element of de groep elementen te identificeren. We doen dit met hash-mappen of in omgekeerde indexen. Het gebruik van hash-mappen is heel vergelijkbaar met het vorige voorbeeld, alleen hebt u in uw kast een hoop kleine dozen met de uiteindelijke items in plaats van een doos met dozen.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/088fed0a2a0feea4a23edbf0ca654805.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDe derde benadering is om de noodzaak van zoeken te elimineren. Dit doen we met behulp van Bloom-filters of cuckoo-filters. De eerste geven onmiddellijk antwoord, zodat u niet hoeft te zoeken.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/493bc4f20baacc0a5dc0faf15cc46285.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDe laatste benadering is om de volledige capaciteit van moderne hardware te benutten. Dit doen we met bitmap-indexen. Ja, bij het gebruik ervan moet je soms door de hele index gaan, maar we doen dit super effici\u00ebnt.<\/p>\n<p>Zoals ik al zei, is het onderwerp van database-indexen uitgebreid en vol compromissen. Dit betekent dat we soms meerdere benaderingen tegelijk kunnen gebruiken: als we de zoektocht nog verder willen versnellen of als we alle mogelijke zoektypes moeten dekken.<\/p>\n<p>Vandaag ga ik het hebben over de minste bekende aanpak van de genoemde \u2014 de bitmap-indexen.<\/p>\n<h2>Wie ben ik om over dit onderwerp te praten?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/42a9d17a507c392bc202254a92dfaf41.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIk ben teamleider bij Badoo (misschien kent u een ander product van ons \u2014 Bumble). We hebben inmiddels meer dan 400 miljoen gebruikers wereldwijd en veel functies die het beste paar voor hen selecteren. Dit doen we met behulp van maatwerkdiensten die ook bitmap-indexen gebruiken.<\/p>\n<h2>Wat is een bitmap-index eigenlijk?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/14f20f3697a20c02f6b3510dc7f0ae4d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nBitmap-indexen, zoals de naam al doet vermoeden, gebruiken bitmaps of bitsets om een zoekindex te implementeren. Van een vogelvluchtperspectief bestaat deze index uit een of meerdere van dergelijke bitmaps, die entiteiten (zoals mensen) en hun eigenschappen of parameters (leeftijd, oogkleur, enz.) vertegenwoordigen, en een algoritme dat bitbewerkingen (AND, OR, NOT) gebruikt om op een zoekopdracht te reageren.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/f815720330a51b1f0798e45d23160d3b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEr wordt gezegd dat bitmap-indexen het beste en zeer effici\u00ebnt zijn in situaties waarin er gezocht wordt met gecombineerde verzoeken over meerdere kolommen met een lage cardinaliteit (denk aan 'oogkleur' of 'burgerlijke staat' in vergelijking met iets als 'afstand tot het stadscentrum'). Maar later zal ik laten zien dat ze ook uitstekend werken voor kolommen met een hoge cardinaliteit.<\/p>\n<p>Laten we een eenvoudig voorbeeld van een bitmap-index bekijken.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/33fe23476e0931c10345d7175b83d68b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nStel je voor dat we een lijst hebben van Moskou-restaurants met binaire eigenschappen zoals deze:<\/p>\n<ul>\n<li>dichtbij de metro (near metro);\n<\/li>\n<li>heeft priv\u00e9-parking (has private parking);\n<\/li>\n<li>heeft een terras (has terrace);\n<\/li>\n<li>reserveren mogelijk (accepts reservations);\n<\/li>\n<li>geschikt voor vegetari\u00ebrs (vegan friendly);\n<\/li>\n<li>duur (expensive).\n<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/fcbad539ea12f79a9d06966ce308637e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLaten we elke restaurant een volgnummer geven, beginnend bij 0, en geheugen toewijzen voor 6 bitmaps (\u00e9\u00e9n voor elke eigenschap). Vervolgens vullen we deze bitmaps in afhankelijk van of het restaurant deze eigenschap heeft of niet. Als restaurant 4 een terras heeft, dan wordt bit nummer 4 in de bitmap 'heeft een terras' ingesteld op 1 (als er geen terras is, dan op 0).<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/3709c426617d4364f392ee6b68f92b00.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nNu hebben we de simpelste bitmap-index die mogelijk is, en we kunnen deze gebruiken om te antwoorden op verzoeken zoals:<\/p>\n<ul>\n<li>\"Laat me de restaurants zien die geschikt zijn voor vegetari\u00ebrs\";\n<\/li>\n<li>\"Laat me de goedkope restaurants met een terras zien, waar ik een tafel kan reserveren.\"\n<\/li>\n<\/ul>\n<p><img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/90acb0f890686bd52c3db1fc667f0b0b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/0fd0b7fe9f7b7039022ad5c79fe873bc.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nHoe? Laten we kijken. De eerste vraag is heel eenvoudig. Alles wat we nodig hebben, is de bitmap 'geschikt voor vegetari\u00ebrs' om te veranderen in een lijst van restaurants wiens bits zijn ingesteld.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/ef4a5cfd658ff4ef8bc0c638c4522d11.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/9cc175bae55c16018fdf5ff95517a61a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDe tweede vraag is iets moeilijker. We moeten de bitwise NOT-operatie op de bitmap 'duur' gebruiken om een lijst van goedkope restaurants te krijgen, vervolgens AND-en we deze met de bitmap 'reserveren mogelijk' en AND-en we het resultaat met de bitmap 'veranda aanwezig'. De resulterende bitmap bevat een lijst van zaken die aan al onze criteria voldoen. In dit geval is dat alleen restaurant 'Juno'.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/f1cdda0cbf7f15278553899cf876c17e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/126b50e0f622b6e36c461cd74e708c38.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nHier is veel theorie, maar maak je geen zorgen, we zullen heel snel de code zien.<\/p>\n<h2>Waar worden bitmap-indexen gebruikt?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/406132236c71a4f66ae79957b6e633b3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAls je 'bitmap-indexen' googelt, zullen 90% van de antwoorden op de een of andere manier gerelateerd zijn aan Oracle DB. Maar andere DBMS'en ondersteunen ongetwijfeld ook zo'n gaaf ding, toch? Niet helemaal. <\/p>\n<p>Laten we de lijst van hoofdverdachten doorlopen.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/d18d66451a8a26b0ddf121f8ec0204cd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMySQL ondersteunt nog geen bitmap-indexen, maar er is een voorstel om deze optie toe te voegen (<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 ondersteunt bitmap-indexen niet, maar gebruikt eenvoudige bitmaps en bitbewerkingen om de zoekresultaten van verschillende andere indexen te combineren.<\/p>\n<p>Tarantool heeft bitset-indexen, het ondersteunt eenvoudige zoekopdrachten erop.<\/p>\n<p>Redis heeft eenvoudige bitvelden<noindex><a rel=\"nofollow\" href=\"https:\/\/redis.io\/commands\/bitfield\"> (https:\/\/redis.io\/commands\/bitfield<\/a><\/noindex>) zonder zoekmogelijkheden.<\/p>\n<p>MongoDB ondersteunt nog geen bitmap-indexen, maar er is ook een voorstel om deze optie toe te voegen. <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 gebruikt bitmaps binnenin<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=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/232d335963603d6e6dec98839fc9f486.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>Maar er is een nieuwe buur in ons huis: Pilosa. Dit is een nieuwe niet-relationele database, geschreven in Go. Het bevat alleen bitmap-indexen en is volledig daarop gebaseerd. We zullen het er later over hebben.\n<\/li>\n<\/ul>\n<h2>Implementatie in Go<\/h2>\n<p>\nMaar waarom worden bitmap-indexen zo zelden gebruikt? Voordat ik deze vraag beantwoord, wil ik je een implementatie van een zeer eenvoudige bitmap-index in Go laten zien.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/ae7f4c1a4a740fe709b05dfaee27ac9b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nBitmaps worden in wezen eenvoudig voorgesteld als datablokjes. Laten we in Go hiervoor gebruikmaken van byte-slices.<\/p>\n<p>We hebben \u00e9\u00e9n bitmap voor \u00e9\u00e9n restaurantkenmerk, en elke bit in de bitmap geeft aan of een specifiek restaurant dat kenmerk heeft of niet.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/1ab628ee15887d6b3c6c99855aa610c8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nWe hebben twee hulpfuncties nodig. E\u00e9n zal worden gebruikt om onze bitmaps met willekeurige gegevens te vullen. Willekeurige gegevens, maar met een bepaalde waarschijnlijkheid dat een restaurant elk kenmerk heeft. Bijvoorbeeld, ik denk dat er in Moskou heel weinig restaurants zijn waar je geen tafel kunt reserveren, en ik denk dat ongeveer 20% van de etablissementen geschikt is voor vegetari\u00ebrs.<\/p>\n<p>De tweede functie zal de bitmap omzetten in een lijst van restaurants.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/ab9c87a0ba63750116e2e7968f842a9a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/498cf7a33611d99b90197d4ee82e2834.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nOm te beantwoorden op de vraag 'Toon me goedkope restaurants met een veranda waar je een tafel kunt reserveren', hebben we twee bitoperaties nodig: NOT en AND.<\/p>\n<p>We kunnen onze code een beetje vereenvoudigen door gebruik te maken van een geavanceerdere operatie AND NOT.<\/p>\n<p>We hebben functies voor elke van deze bewerkingen. Beide gaan over slices, nemen de corresponderende elementen uit elk en combineren ze met een bitoperatie, waarna het resultaat in de resultaat slice wordt geplaatst.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/ec5652a34f0370dfb03df199f341f153.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEn nu kunnen we onze bitmaps en functies gebruiken om op het zoekverzoek te reageren.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/cf9500ccfe75995a6008191c16729689.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDe prestaties zijn niet zo hoog, ook al zijn de functies heel eenvoudig en hebben we goed bespaard door niet bij elke functie-aanroep een nieuwe resultaten slice terug te geven.<\/p>\n<p>Na wat profilering met pprof merkte ik dat de Go-compiler een heel eenvoudige, maar belangrijke optimalisatie miste: function inlining.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/9092f5ba3940d0a4f3fbfa90b364d716.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nHet probleem is dat de Go-compiler bang is voor lussen die over slices gaan, en categorisch weigert om functies in te line te zetten die zulke lussen bevatten.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/d1bddd62b61b367dd1f680f223fa0ce7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMaar ik ben daar niet bang voor en kan de compiler bedriegen door goto in plaats van een lus te gebruiken, zoals in de goede oude tijd.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/5b1c3cb26b923972686047910ecd1c31.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/1ca31d12dc90931b674c6a86a4ea23bd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEn zoals je kunt zien, inline de compiler nu onze functie met plezier! Uiteindelijk besparen we ongeveer 2 microseconden. Niet slecht!<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/bdd6735d16082573e600bffe2cdd5662.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nHet tweede knelpunt is gemakkelijk te zien als je goed naar de assembly-output kijkt. De compiler heeft een slice-bereikcontrole toegevoegd in onze heetste lus. Het punt is dat Go een veilige taal is; de compiler is bezorgd dat mijn drie argumenten (drie slices) verschillende groottes hebben. Er zou dan theoretisch de mogelijkheid kunnen zijn van een buffer overflow.<\/p>\n<p>Laten we de compiler geruststellen door hem te laten zien dat alle slices dezelfde grootte hebben. We kunnen dit doen door een eenvoudige controle aan het begin van onze functie toe te voegen.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/59b4ce687a11dd653e9f12fc3130d89a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDaarop laat de compiler blij de controle voorbijgaan, en zo besparen we nog eens 500 nanoseconden.<\/p>\n<h2>Grote batches<\/h2>\n<p>\nOk\u00e9, we hebben enige prestaties uit onze eenvoudige implementatie gehaald, maar dit resultaat is eigenlijk veel slechter dan mogelijk met de huidige hardware.<\/p>\n<p>Alles wat we doen, zijn basis bitbewerkingen, en onze processoren voeren deze zeer effici\u00ebnt uit. Maar helaas 'voeden' we onze processor met heel kleine stukjes werk. Onze functies voeren operaties byte voor byte uit. We kunnen onze code heel eenvoudig tweaken zodat deze met 8-byte stukken werkt door UInt64-slices te gebruiken.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/8d1b60ba4b7046c836601631cadd0b6a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nZoals je kunt zien, heeft deze kleine wijziging ons programma acht keer versneld door de batchgrootte acht keer te vergroten. De winst kan als lineair worden beschouwd.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/0fc663412d04dd38b927de5c8776f69d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Implementatie in assembly<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/b3ef133167b89da983356b1c7389aecd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMaar dit is nog niet het einde. Onze processoren kunnen werken met stukken van 16, 32 en zelfs 64 byte. Dergelijke 'brede' operaties worden single instruction multiple data (SIMD) genoemd, en het proces van het transformeren van code zodat deze dergelijke operaties gebruikt, wordt vectorisatie genoemd.<\/p>\n<p>Helaas is de Go-compiler geen ster in vectorisatie. Op dit moment is de enige manier om code in Go te vectoriseren door de gegevensbewerkingen handmatig met Go-assembly te schrijven.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/91278be45df67e1f9572d68fab7ebad1.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nGo-assembly is een vreemd beest. Je weet waarschijnlijk dat assembly sterk aan de architectuur van de computer is gekoppeld waarvoor je schrijft, maar in Go is dat niet het geval. Go-assembly lijkt meer op IRL (intermediate representation language) of een tussenliggende taal: het is vrijwel platformonafhankelijk. Rob Pike heeft enkele jaren geleden een uitstekende <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=KINIAgRpkDA\">presentatie<\/a><\/noindex> lezing hierover gegeven op GopherCon in Denver.<\/p>\n<p>Daarnaast gebruikt Go een ongebruikelijk formaat, Plan 9, dat verschilt van de algemeen erkende formaten AT&amp;T en Intel.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/526f75eb18edfc2f851f2725e9d6f69e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nJe kunt met zekerheid zeggen dat het schrijven van Go-assembly met de hand geen geweldige tijdverdrijf is.<\/p>\n<p>Maar gelukkig zijn er al twee krachtige tools die ons helpen bij het schrijven van Go-assembly: PeachPy en avo. Beide tools genereren Go-assembly uit hoger niveau code, geschreven in respectievelijk Python en Go.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/b8a7aa2c585b805e9b1f2ada186b84e8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDeze hulpprogramma's vereenvoudigen zaken zoals registerallocatie, het schrijven van lussen, en maken over het algemeen de toegang tot de wereld van assemblertaalprogrammering in Go gemakkelijker.<\/p>\n<p>We zullen avo gebruiken, zodat onze programma's bijna gewone Go-programma's zullen zijn.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/128e4adef14e5f2cf00fb5b6302ef58e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nZo ziet het eenvoudigste voorbeeld van een avo-programma eruit. We hebben een functie main() die daarin de functie Add() definieert, die bedoeld is om twee getallen op te tellen. Hier zijn hulpfuncties aanwezig voor het verkrijgen van parameters op basis van naam en het verkrijgen van een van de beschikbare en geschikte registers. Voor elke processorbewerking is er een overeenkomstige functie in avo, zoals te zien is bij ADDQ. En tenslotte zien we een hulpfunctie voor het opslaan van de resulterende waarde.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/01ccaa6aa6d394ef598ea2dbc9257d87.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDoor go generate aan te roepen, voeren we het programma op avo uit en er worden uiteindelijk twee bestanden gegenereerd:<\/p>\n<ul>\n<li>add.s met de resulterende code in Go-assemblertaal;\n<\/li>\n<li>stub.go met functiekopteksten voor de verbinding tussen de twee werelden: Go en assembler.\n<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/72a9443776ecf45eef6fb97a4e08acba.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nNu we hebben gezien wat avo doet, laten we naar onze functies kijken. Ik heb zowel de scalare als de vectorversies (SIMD) van de functies ge\u00efmplementeerd.<\/p>\n<p>Laten we eerst naar de scalare versies kijken.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/ec31dbb8b97b9d7c1012a120fa18cdaf.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nZoals in het vorige voorbeeld vragen we om een vrij en correct algemeen register, hoeven we geen offset en grootte voor argumenten te berekenen. Dit doet avo allemaal voor ons.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/88085e927dd943ea0f808a28fb3ccf9b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEerder gebruikten we labels en goto (of sprongen) om de prestaties te verbeteren en de Go-compiler te misleiden, maar nu doen we dit vanaf het begin. Het punt is dat lussen een hoger niveau begrip zijn. In assembler hebben we slechts labels en sprongen.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/9a4181248eb279d89c1445a820b06649.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDe resterende code zou je al bekend en begrijpelijk moeten zijn. We emuleren de lus met labels en sprongen, nemen een klein deel van de gegevens uit onze twee slices, combineren deze met een bitbewerking (AND NOT in dit geval) en plaatsen vervolgens het resultaat in de resulterende slice. Dat is alles.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/19275ead27f63092fc6596bed38a8d03.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nZo ziet de uiteindelijke code in assembler eruit. We hoefden geen offsets en groottes te berekenen (gemarkeerd in groen) of toezicht te houden op de gebruikte registers (gemarkeerd in rood).<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/ed68528a6f852634a5b536670c6315f0.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAls we de prestaties van de implementatie in assembly vergelijken met die van de beste implementatie in Go, zien we dat ze gelijk zijn. Dat is te verwachten. We hebben immers niets bijzonders gedaan \u2014 we hebben alleen gereproduceerd wat de Go-compiler zou doen.<\/p>\n<p>Helaas kunnen we de compiler niet dwingen om onze in assembly geschreven functies inline te maken. De Go-compiler heeft momenteel niet de mogelijkheid om dit te doen, hoewel het verzoek om deze functie al geruime tijd bestaat.<\/p>\n<p>Daarom is het onmogelijk om enige voordelen te halen uit kleine functies in assembly. We moeten ofwel grote functies schrijven, of de nieuwe package math\/bits gebruiken, of assembly vermijden.<\/p>\n<p>Laten we nu eens kijken naar de vectorversies van onze functies.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/7f67c3cc855908fb47c7900d6e5d7f54.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nVoor dit voorbeeld heb ik besloten om AVX2 toe te passen, dus we zullen bewerkingen gebruiken die werken met 32-byte blokken. De structuur van de code lijkt erg op die van de scalairvariant: parameters laden, verzoeken om een vrije algemene register, enzovoort.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/021e0424a0d733ec7db9edeb98ce1f65.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEen van de nieuwigheden is dat bredere vectorbewerkingen speciale brede registers gebruiken. Voor 32-byte blokken zijn dit de registers met de prefix Y. Daarom zie je de functie YMM() in de code. Als ik AVX-512 met 64-bit blokken had gebruikt, zou de prefix Z zijn.<\/p>\n<p>Een tweede nieuwigheid is dat ik besloot een optimalisatie toe te passen die loop unrolling wordt genoemd, dat wil zeggen, acht loopbewerkingen handmatig te doen voordat ik naar het begin van de loop spring. Deze optimalisatie vermindert het aantal branches in de code en is beperkt door het aantal beschikbare vrije registers.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/f54631d9e8c69f6f70ecace3133ae1e8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMaar hoe zit het met de prestaties? Die zijn geweldig! We hebben een versnellingsfactor van ongeveer zeven keer bereikt in vergelijking met de beste oplossing in Go. Indrukwekkend, nietwaar?<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/d7e85c933eecb243cfb49225b4d92c6c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMaar zelfs deze implementatie zou potentieel versneld kunnen worden met behulp van AVX-512, prefetching of JIT (just-in-time compiler) voor de query planner. Maar dat is zeker een onderwerp voor een aparte presentatie.<\/p>\n<h2>Problemen met bitmap-indexen<\/h2>\n<p>\nNu we de eenvoudige implementatie van bitmap-indexen in Go en de veel productievere implementatie in assembly hebben bekeken, laten we eindelijk bespreken waarom bitmap-indexen zo zelden worden gebruikt.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/83d36a5c92ba90fd680fe8afb6cfc11f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIn oude wetenschappelijke werken worden drie problemen van bitmap-indexen genoemd, maar recentere studies en ik beweren dat deze al verouderd zijn. Laten we niet te diep op elk van deze problemen ingaan, maar een oppervlakkige beschouwing geven.<\/p>\n<h2>Probleem van hoge cardinaliteit<\/h2>\n<p>\nMen zegt ons dus dat bitmap-indexen alleen geschikt zijn voor velden met een lage cardinaliteit, dat wil zeggen velden met weinig waarden (zoals geslacht of oogkleur), en de reden is dat de gebruikelijke representatie van dergelijke velden (\u00e9\u00e9n bit per waarde) in het geval van hoge cardinaliteit te veel ruimte zou innemen en bovendien deze bitmap-indexen slecht (zelden) gevuld zouden zijn.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/0787efc4d2cb4ea4d404ca7888b33697.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/44ab4bc7c25d14fe2f53caf5d9da399d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSoms kunnen we een andere representatie gebruiken, bijvoorbeeld de standaardrepresentatie die we voor getallen gebruiken. Maar het was de ontwikkeling van compressie-algoritmen die alles veranderde. In de afgelopen decennia hebben wetenschappers en onderzoekers een groot aantal compressie-algoritmen voor bitmap-gegevens bedacht. Hun belangrijkste voordeel is dat we de bitmaps niet hoeven te decomprimeren om bitbewerkingen uit te voeren \u2014 we kunnen bitbewerkingen direct op de gecomprimeerde bitmaps uitvoeren.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/ecb54fbf15aa11271bbbab01ecbda880.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nOnlangs zijn ook hybride benaderingen ontstaan, zoals roaring bitmaps. Ze gebruiken tegelijkertijd drie verschillende representaties voor bitmaps \u2014 echte bitmaps, arrays en zogenaamde bit runs \u2014 en balanceren tussen deze om de prestaties te maximaliseren en het geheugenverbruik te minimaliseren.<\/p>\n<p>Je kunt roaring bitmaps tegenkomen in de meest populaire applicaties. Er zijn al talloze implementaties voor verschillende programmeertalen, waaronder meer dan drie implementaties voor Go.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/de2adfebc431ff48c996247b453f02ae.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEen andere aanpak die ons kan helpen omgaan met hoge cardinaliteit, heet groepering (binning). Stel je voor dat je een veld hebt dat de lengte van een persoon vertegenwoordigt. Lengte is een getal met een decimale komma, maar wij mensen denken daar niet zo over. Voor ons maakt het niet uit of iemand 185,2 cm of 185,3 cm lang is.<\/p>\n<p>Dus we kunnen vergelijkbare waarden binnen 1 cm groeperen.<\/p>\n<p>En als we ook weten dat er zeer weinig mensen zijn die een lengte hebben van minder dan 50 cm of meer dan 250 cm, kunnen we het veld met oneindige cardinaliteit in feite omzetten in een veld met ongeveer 200 waarden.<\/p>\n<p>Natuurlijk kunnen we indien nodig extra filtering toepassen.<\/p>\n<h2>Het probleem van hoge doorvoersnelheid<\/h2>\n<p>\nEen volgend probleem van bitmap-indexen is dat hun bijwerking zeer kostbaar kan zijn.<\/p>\n<p>Databases moeten in staat zijn om gegevens bij te werken op het moment dat potentieel honderden andere aanvragen deze gegevens doorzoeken. We hebben locks nodig om problemen met gelijktijdige toegang tot gegevens of andere problemen met gedeelde toegang te vermijden. En waar er \u00e9\u00e9n grote lock is, is er een probleem \u2014 lock contention, wanneer die lock een bottleneck wordt.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/0ae1bf925542d286f8b7b245c160a35e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDit probleem kan worden opgelost of omzeild door sharding of door het gebruik van versieversie-indexen.<\/p>\n<p>Sharding is een eenvoudige en algemeen bekende techniek. U kunt een bitmap-index sharden zoals u andere gegevens zou sharden. In plaats van \u00e9\u00e9n grote lock krijgt u verschillende kleine locks en voorkomt u zo lock contention.<\/p>\n<p>Een tweede manier om het probleem op te lossen, is door versieversie-indexen te gebruiken. U kunt \u00e9\u00e9n kopie van de index hebben die u gebruikt voor zoeken of lezen, en \u00e9\u00e9n voor schrijven of bijwerken. En om de paar tijdseenheden (bijvoorbeeld elke 100 ms of 500 ms) dupliceert u ze en verwisselt u ze. Dit is natuurlijk alleen toepasbaar als uw applicatie kan werken met een iets achterlopende zoekindex.<\/p>\n<p>Deze twee benaderingen kunnen tegelijkertijd worden gebruikt: u kunt een gedistribueerde versieversie-index hebben.<\/p>\n<h2>Complexere queries<\/h2>\n<p>Het laatste probleem van bitmap-indexen is dat, zoals ons wordt verteld, ze slecht geschikt zijn voor complexere soorten queries, zoals 'tussen'-queries.<\/p>\n<p>En dat is waar, als je erover nadenkt, zijn bitbewerkingen zoals AND, OR enz. niet echt geschikt voor queries als 'Toon mij hotels met kamerprijzen van 200 tot 300 dollar per nacht'.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/7bc2e129cad46fb5875c2b3018c39ff7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEen na\u00efeve en zeer onredelijke oplossing zou zijn om resultaten voor elke dollarwaarde te nemen en deze samen te voegen met een bitbewerkingsoperatie OR.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/b9f8fc7945caa1866f8e0cfa8a04bd98.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEen iets meer correcte oplossing zou zijn om te groeperen. Bijvoorbeeld in groepen van 50 dollar. Dit zou ons proces met 50 keer versnellen.<\/p>\n<p>Maar het probleem kan ook eenvoudig worden opgelost door gebruik te maken van een representatie die speciaal is gemaakt voor dit soort verzoeken. In wetenschappelijke werken wordt dit range-encoded bitmaps genoemd.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/644a420628b21f220a7af1ff15c4031f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIn zo'n representatie stellen we niet gewoon een bit in voor een bepaalde waarde (bijvoorbeeld 200), maar stellen we deze waarde in en alles wat daarboven ligt. 200 en hoger. Hetzelfde geldt voor 300: 300 en hoger. En ga zo verder.<\/p>\n<p>Door deze representatie te gebruiken, kunnen we dit soort zoekopdrachten beantwoorden door slechts twee keer door de index te gaan. Eerst krijgen we een lijst met hotels waar de kamerprijs minder is dan 300 dollar, en vervolgens verwijderen we de hotels waar de kamerprijs minder is dan 199 dollar. Klaar.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/cc2bb58d7d7a51495c62ec7da81e2d12.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nJe zult het misschien niet geloven, maar zelfs geografische verzoeken zijn mogelijk met bitmap-indexen. De truc is om een georepresentatie te gebruiken die je co\u00f6rdinaat omringt met een geometrische figuur. Bijvoorbeeld, S2 van Google. De figuur moet kunnen worden voorgesteld als drie of meer intersecterende rechte lijnen die genummerd kunnen worden. Op deze manier kunnen we ons geografische verzoek omzetten in verschillende \"interval\" verzoeken (langs deze genummerde lijnen).<\/p>\n<h2>Kant-en-klare oplossingen<\/h2>\n<p>\nIk hoop dat ik je een beetje heb ge\u00efnteresseerd en dat je een nuttige tool aan je arsenaal hebt toegevoegd. Als je ooit zoiets moet doen, weet je in welke richting je moet kijken.<\/p>\n<p>Echter, niet iedereen heeft de tijd, geduld en middelen om bitmap-indexen vanaf nul op te bouwen. Vooral de geavanceerdere, met behulp van SIMD, bijvoorbeeld.<\/p>\n<p>Gelukkig zijn er een aantal kant-en-klare oplossingen die je kunnen helpen.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/817b47cb189a758756b602ec9cf319e1.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Roaring bitmaps<\/h2>\n<p>\nTen eerste is er de roaring bitmaps-bibliotheek waar ik het al over had. Deze bevat alle benodigde containers en bitbewerkingen die je nodig hebt om een volledige bitmap-index te maken.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/57f61a51485c174666b52dc2063fabe8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nHelaas maakt geen van de Go-implementaties op dit moment gebruik van SIMD, wat betekent dat de Go-implementaties minder effici\u00ebnt zijn dan bijvoorbeeld de implementaties in C.<\/p>\n<h2>Pilosa<\/h2>\n<p>\nEen ander product dat je kan helpen is de database Pilosa, die in wezen alleen bitmap-indexen heeft. Dit is een relatief nieuwe oplossing, maar het verovert snel de harten.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/d3870a979e1e73d093fe5d5e9bb71cd8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPilosa maakt gebruik van roaring bitmaps en biedt je de mogelijkheid om deze te gebruiken, en vereenvoudigt en verklaart alles wat ik eerder heb besproken: groepering, range-gecodeerde bitmaps, het concept van een veld, enzovoort.<\/p>\n<p>Laten we snel kijken naar een voorbeeld van het gebruik van Pilosa om een vraag te beantwoorden die je al bekend is.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/dfee7abfd653cc19d9aa8b64c64f3e4e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nHet voorbeeld lijkt sterk op wat je eerder hebt gezien. We maken een client voor de Pilosa-server, cre\u00ebren een index en de benodigde velden, vullen vervolgens onze velden met willekeurige gegevens op basis van kansen en tenslotte voeren we de bekende query uit.<\/p>\n<p>Daarna gebruiken we NOT op het veld 'expensive', kruisen vervolgens het resultaat (of AND) met het veld 'terrace' en met het veld 'reservations'. En uiteindelijk krijgen we het eindresultaat.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/8d66c6d68019c2297b6c15b700f06a3a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIk hoop echt dat in de nabije toekomst dit nieuwe type indexen \u2014 bitmap-indexen \u2014 ook beschikbaar komt in databases zoals MySQL en PostgreSQL.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/7a8e33d576c7fb6376a173ee038b4206.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Conclusie<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-indexen in Go: zoeken met hoge snelheid\" src=\"\/wp-content\/uploads\/2019\/05\/c62caa9ad6f2d96056c80326f4fa9a0d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAls je nog niet in slaap bent gevallen, bedankt. Ik moest verschillende onderwerpen vluchtig aanstippen vanwege de beperkte tijd, maar ik hoop dat de presentatie nuttig en misschien zelfs inspirerend was.<\/p>\n<p>Het is goed om iets te weten over bitmap-indexen, zelfs als je ze op dit moment niet nodig hebt. Laat ze een extra gereedschap in je gereedschapskist zijn.<\/p>\n<p>We hebben verschillende trucs bekeken om de prestaties voor Go te verbeteren en de dingen waarmee de Go-compiler momenteel nog niet zo goed overweg kan. Dit is absoluut nuttig om te weten voor elke Go-programmeur.<\/p>\n<p>Dat is alles wat ik wilde vertellen. Dank je!<br \/>\n<br \/>Bron: <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.3 - 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\/nl\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"nl_NL\" \/>\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\/nl\/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-indexen in Go: zoeken met hoge snelheid | ProHoster","description":"Inleiding Ik heb mijn presentatie gehouden.","canonical_url":"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"nl_NL","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\/nl\/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\/nl\/wp-json\/wp\/v2\/posts\/33793","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/comments?post=33793"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts\/33793\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media\/25469"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media?parent=33793"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/categories?post=33793"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/tags?post=33793"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}