{"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\/sv\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti","title":{"rendered":"Bitmap-index i Go: s\u00f6kning i vild hastighet","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/86ef928e6741022b2c0e5885a031408a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h2>Inledande ord<\/h2>\n<p>\nJag presenterade detta f\u00f6redrag p\u00e5 engelska vid GopherCon Russia 2019 i Moskva och p\u00e5 ryska vid meet-up i Nizjnij Novgorod. Det handlar om bitmap-index \u2014 ett som \u00e4r mindre vanligt \u00e4n B-tree, men inte mindre intressant. Jag delar med mig <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/WvlUH6MjUuI?list=PL3xVZC4USRNSO_kb2lh_J_no6C-KJ7Phg\">av en inspelning<\/a><\/noindex> fr\u00e5n f\u00f6redraget p\u00e5 konferensen p\u00e5 engelska och en texttranskription p\u00e5 ryska.<\/p>\n<p>Vi kommer att titta p\u00e5 hur bitmap-index \u00e4r uppbyggda, n\u00e4r de \u00e4r b\u00e4ttre, n\u00e4r de \u00e4r s\u00e4mre \u00e4n andra index och i vilka fall de \u00e4r betydligt snabbare; se vilka popul\u00e4ra DBMS som redan har bitmap-index; f\u00f6rs\u00f6ka skriva v\u00e5rt eget i Go. Som \"dessert\" kommer vi att anv\u00e4nda f\u00e4rdiga bibliotek f\u00f6r att skapa v\u00e5r supersnabba specialiserade databas.<\/p>\n<p>Jag hoppas verkligen att mitt arbete kommer att vara anv\u00e4ndbart och intressant f\u00f6r er. D\u00e5 k\u00f6r vi!<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Introduktion<\/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=\"Spela 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>Hej alla! Klockan \u00e4r sex p\u00e5 kv\u00e4llen, vi \u00e4r alla supertr\u00f6tta. En utm\u00e4rkt tid att prata om tr\u00e5kig teori kring databasindex, eller hur? Oroa er inte, jag har n\u00e5gra rader k\u00e4llkod h\u00e4r och d\u00e4r. \ud83d\ude42<\/p>\n<p>Om vi ska vara seri\u00f6sa \u00e4r f\u00f6redraget fyllt med information och vi har inte s\u00e5 mycket tid. L\u00e5t oss b\u00f6rja.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/e778e13727700f0335a4b5558a0d8db3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIdag kommer jag att prata om f\u00f6ljande:<\/p>\n<ul>\n<li>vad index \u00e4r;\n<\/li>\n<li>vad ett bitmap-index \u00e4r;\n<\/li>\n<li>var det anv\u00e4nds och var det INTE anv\u00e4nds och varf\u00f6r;\n<\/li>\n<li>en enkel implementering i Go och lite kamp med kompileraren;\n<\/li>\n<li>en n\u00e5got mindre enkel, men mycket mer effektiv implementering i GoAssembly;\n<\/li>\n<li>\"problem\" med bitmap-index;\n<\/li>\n<li>befintliga implementationer.\n<\/li>\n<\/ul>\n<h2>Vad \u00e4r d\u00e5 index?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/b80e5b990c44814afe9150a9a82351fd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEtt index \u00e4r en separat datastruktur som vi h\u00e5ller och uppdaterar i till\u00e4gg till huvuddata. Den anv\u00e4nds f\u00f6r att p\u00e5skynda s\u00f6kningen. Utan index skulle en s\u00f6kning kr\u00e4va en fullst\u00e4ndig genomg\u00e5ng av datan (en process kallad full scan), och denna process har linj\u00e4r algoritmisk komplexitet. Men databaser inneh\u00e5ller vanligtvis enorma m\u00e4ngder data och linj\u00e4r komplexitet \u00e4r f\u00f6r l\u00e5ngsam. Idealiskt sett vill vi ha logarithmisk eller konstant.<\/p>\n<p>Detta \u00e4r ett stort komplext \u00e4mne, fyllt med nyanser och kompromisser, men efter att ha sett p\u00e5 \u00e5ratal av utveckling och forskningen kring olika databaser \u00e4r jag beredd att p\u00e5st\u00e5 att det finns ett f\u00e5tal allm\u00e4nt anv\u00e4nda tillv\u00e4gag\u00e5ngss\u00e4tt f\u00f6r att skapa databaser.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/08a74dbb365035cd99bc94d72644a1b7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDen f\u00f6rsta metoden inneb\u00e4r hierarkisk minskning av s\u00f6komr\u00e5det, d\u00e4r s\u00f6komr\u00e5det delas upp i mindre delar.<\/p>\n<p>Vanligtvis g\u00f6r vi detta genom att anv\u00e4nda olika typer av tr\u00e4d. Ett exempel kan vara en stor l\u00e5da med material i ditt sk\u00e5p, som inneh\u00e5ller mindre l\u00e5dor med material uppdelade efter olika teman. Om du beh\u00f6ver material kommer du f\u00f6rmodligen att leta efter dem i l\u00e5dan som \u00e4r m\u00e4rkt \"Material\", och inte i den som har ordet \"Kakor\" p\u00e5 sig, eller hur?<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/423fac47c748980b18af434644af4dae.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDen andra metoden inneb\u00e4r att direkt identifiera det \u00f6nskade elementet eller en grupp av element. Vi g\u00f6r detta i hash maps eller omv\u00e4nda index. Anv\u00e4ndningen av hash maps liknar det f\u00f6reg\u00e5ende exemplet, men ist\u00e4llet f\u00f6r en l\u00e5da med l\u00e5dor har du en massa sm\u00e5 l\u00e5dor med slutliga objekt i ditt sk\u00e5p.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/088fed0a2a0feea4a23edbf0ca654805.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDen tredje metoden \u00e4r att eliminera behovet av s\u00f6kning. Detta g\u00f6r vi med hj\u00e4lp av Bloom-filter eller cuckoo-filter. De f\u00f6rsta ger svar \u00f6gonblickligen, vilket befriar dig fr\u00e5n att beh\u00f6va s\u00f6ka.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/493bc4f20baacc0a5dc0faf15cc46285.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDen sista metoden handlar om att utnyttja alla resurser som modern h\u00e5rdvara ger oss. Det \u00e4r just vad vi g\u00f6r med bitmap-index. Ja, n\u00e4r vi anv\u00e4nder dem m\u00e5ste vi ibland g\u00e5 igenom hela indexet, men vi g\u00f6r det supereffektivt.<\/p>\n<p>Som jag redan n\u00e4mnt \u00e4r temat databasindex omfattande och fyllt med kompromisser. Det betyder att vi ibland kan anv\u00e4nda flera metoder samtidigt: om vi beh\u00f6ver snabba upp s\u00f6kningen \u00e4nnu mer eller om vi beh\u00f6ver t\u00e4cka alla m\u00f6jliga typer av s\u00f6kningar.<\/p>\n<p>Idag kommer jag att prata om den minst k\u00e4nda metoden bland de n\u00e4mnda - bitmap-index.<\/p>\n<h2>Vem \u00e4r jag f\u00f6r att prata om detta \u00e4mne?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/42a9d17a507c392bc202254a92dfaf41.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nJag arbetar som teamledare p\u00e5 Badoo (kanske k\u00e4nner du b\u00e4ttre till v\u00e5r andra produkt - Bumble). Vi har redan \u00f6ver 400 miljoner anv\u00e4ndare v\u00e4rlden \u00f6ver och m\u00e5nga funktioner som arbetar med att matcha dem med den b\u00e4sta partnern. Vi g\u00f6r detta med hj\u00e4lp av skr\u00e4ddarsydda tj\u00e4nster, inklusive bitmap-index.<\/p>\n<h2>S\u00e5 vad \u00e4r ett bitmap-index?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/14f20f3697a20c02f6b3510dc7f0ae4d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nBitmap-indexar, som namnet antyder, anv\u00e4nder bitmaps eller bitset f\u00f6r att implementera ett s\u00f6kindex. I ett f\u00e5gelperspektiv best\u00e5r detta index av en eller flera s\u00e5dana bitmaps som representerar entiteter (som m\u00e4nniskor) och deras egenskaper eller parametrar (\u00e5lder, \u00f6gonf\u00e4rg etc.), samt en algoritm som anv\u00e4nder bitoperationer (OCH, ELLER, INTE) f\u00f6r att svara p\u00e5 s\u00f6kfr\u00e5gor.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/f815720330a51b1f0798e45d23160d3b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDet s\u00e4gs att bitmap-indexar \u00e4r allra mest l\u00e4mpliga och mycket effektiva f\u00f6r situationer d\u00e4r s\u00f6kningar kombinerar fr\u00e5gor \u00f6ver m\u00e5nga kolumner med l\u00e5g kardinalitet (t\u00e4nk dig \"\u00f6gonf\u00e4rg\" eller \"civilst\u00e5nd\" mot n\u00e5got som \"avst\u00e5nd fr\u00e5n stadens centrum\"). Men senare ska jag visa att de fungerar utm\u00e4rkt \u00e4ven med kolumner med h\u00f6g kardinalitet.<\/p>\n<p>L\u00e5t oss titta p\u00e5 ett enkelt exempel p\u00e5 ett bitmap-index.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/33fe23476e0931c10345d7175b83d68b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nT\u00e4nk dig att vi har en lista \u00f6ver restauranger i Moskva med bin\u00e4ra egenskaper som dessa:<\/p>\n<ul>\n<li>n\u00e4ra tunnelbanan (near metro);\n<\/li>\n<li>har privat parkering (has private parking);\n<\/li>\n<li>har terrass (has terrace);\n<\/li>\n<li>accepterar bokningar (accepts reservations);\n<\/li>\n<li>veganv\u00e4nlig (vegan friendly);\n<\/li>\n<li>dyr (expensive).\n<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/fcbad539ea12f79a9d06966ce308637e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nL\u00e5t oss ge varje restaurang ett ordningsnummer som b\u00f6rjar p\u00e5 0 och avs\u00e4tta minne f\u00f6r 6 bitmaps (en f\u00f6r varje egenskap). Sedan kommer vi att fylla dessa bitmaps beroende p\u00e5 om restaurangen har denna egenskap eller inte. Om restaurang 4 har en terrass, kommer bit nr 4 i bitmapen \"har terrass\" att s\u00e4ttas till 1 (om det inte finns en terrass, s\u00e4tts det till 0).<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/3709c426617d4364f392ee6b68f92b00.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nNu har vi det enklaste bitmap-indexet som finns, och vi kan anv\u00e4nda det f\u00f6r att svara p\u00e5 fr\u00e5gor som:<\/p>\n<ul>\n<li>\"Visa mig restauranger som \u00e4r veganv\u00e4nliga\";\n<\/li>\n<li>\"Visa mig prisv\u00e4rda restauranger med terrass d\u00e4r man kan boka bord.\"\n<\/li>\n<\/ul>\n<p><img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/90acb0f890686bd52c3db1fc667f0b0b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/0fd0b7fe9f7b7039022ad5c79fe873bc.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nHur? L\u00e5t oss titta. Den f\u00f6rsta fr\u00e5gan \u00e4r mycket enkel. Det vi beh\u00f6ver g\u00f6ra \u00e4r att ta bitmapen \"veganv\u00e4nlig\" och omvandla den till en lista \u00f6ver restauranger vars bitar \u00e4r satt.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/ef4a5cfd658ff4ef8bc0c638c4522d11.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/9cc175bae55c16018fdf5ff95517a61a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDen andra f\u00f6rfr\u00e5gan \u00e4r lite mer komplicerad. Vi beh\u00f6ver anv\u00e4nda bitoperat\u00f6ren NOT p\u00e5 bitmappen \"dyr\", f\u00f6r att f\u00e5 en lista \u00f6ver prisv\u00e4rda restauranger, och sedan AND:a den med bitmappen \"kan boka bord\" och AND:a resultatet med bitmappen \"har terrass\". Den resulterande bitmappen kommer att inneh\u00e5lla en lista \u00f6ver st\u00e4llen som uppfyller alla v\u00e5ra kriterier. I det h\u00e4r exemplet \u00e4r det endast restaurangen \"Ungdom\".<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/f1cdda0cbf7f15278553899cf876c17e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/126b50e0f622b6e36c461cd74e708c38.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDet finns mycket teori h\u00e4r, men oroa dig inte, vi kommer snart att se koden.<\/p>\n<h2>Var anv\u00e4nds bitmap-index?<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/406132236c71a4f66ae79957b6e633b3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nOm du \"googlar\" bitmap-index kommer 90% av svaren p\u00e5 ett eller annat s\u00e4tt att relatera till Oracle DB. Men andra databashanteringssystem st\u00f6djer s\u00e4kert ocks\u00e5 den h\u00e4r fantastiska funktionen, eller hur? Inte riktigt. <\/p>\n<p>L\u00e5t oss g\u00e5 igenom listan \u00f6ver huvudmisst\u00e4nkta.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/d18d66451a8a26b0ddf121f8ec0204cd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMySQL st\u00f6der \u00e4nnu inte bitmap-index, men det finns ett f\u00f6rslag om att l\u00e4gga till den h\u00e4r funktionen (<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 st\u00f6der inte bitmap-index, men anv\u00e4nder enkla bitmaps och bitoperationer f\u00f6r att kombinera s\u00f6kresultat fr\u00e5n flera andra index.<\/p>\n<p>Tarantool har bitset-index och st\u00f6der enkel s\u00f6kning med dem.<\/p>\n<p>Redis har enkla bitf\u00e4lt<noindex><a rel=\"nofollow\" href=\"https:\/\/redis.io\/commands\/bitfield\"> (https:\/\/redis.io\/commands\/bitfield<\/a><\/noindex>) utan m\u00f6jlighet till s\u00f6kning.<\/p>\n<p>MongoDB st\u00f6der \u00e4nnu inte bitmap-index, men det finns ocks\u00e5 ett f\u00f6rslag om att l\u00e4gga till denna funktion. <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 anv\u00e4nder bitmaps internt<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-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/232d335963603d6e6dec98839fc9f486.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>Men i v\u00e5rt hus har vi f\u00e5tt en ny granne: Pilosa. Det \u00e4r en ny icke-relationell databas skriven i Go. Den inneh\u00e5ller endast bitmap-index och bygger allt p\u00e5 dem. Vi kommer att prata om den lite senare.\n<\/li>\n<\/ul>\n<h2>Implementation i Go<\/h2>\n<p>\nMen varf\u00f6r anv\u00e4nds bitmap-index s\u00e5 s\u00e4llan? Innan jag svarar p\u00e5 den fr\u00e5gan skulle jag vilja visa dig en implementation av ett mycket enkelt bitmap-index i Go.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/ae7f4c1a4a740fe709b05dfaee27ac9b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nBitmaps representeras i grunden som bara bitar av data. I Go l\u00e5t oss anv\u00e4nda byte-slices f\u00f6r detta.<\/p>\n<p>Vi har en bitmap f\u00f6r en restaurangegenskap, och varje bit i bitmappen anger om en viss restaurang har den egenskapen eller inte.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/1ab628ee15887d6b3c6c99855aa610c8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nVi beh\u00f6ver tv\u00e5 hj\u00e4lpfunktioner. Den ena kommer att anv\u00e4ndas f\u00f6r att fylla v\u00e5ra bitmaps med slumpm\u00e4ssiga data. Slumpm\u00e4ssiga, men med en viss sannolikhet f\u00f6r att restaurangen har varje egenskap. Till exempel anser jag att det finns v\u00e4ldigt f\u00e5 restauranger i Moskva d\u00e4r man inte kan boka bord, och jag tror att ungef\u00e4r 20 % av st\u00e4llena \u00e4r l\u00e4mpliga f\u00f6r vegetarianer.<\/p>\n<p>Den andra funktionen kommer att konvertera bitmappen till en lista \u00f6ver restauranger.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/ab9c87a0ba63750116e2e7968f842a9a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/498cf7a33611d99b90197d4ee82e2834.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nF\u00f6r att svara p\u00e5 fr\u00e5gan \"Visa mig billiga restauranger som har en veranda och d\u00e4r man kan boka bord\" beh\u00f6ver vi tv\u00e5 bitoperationer: NOT och AND.<\/p>\n<p>Vi kan f\u00f6renkla v\u00e5r kod n\u00e5got genom att anv\u00e4nda en mer avancerad operation AND NOT.<\/p>\n<p>Vi har funktioner f\u00f6r var och en av dessa operationer. B\u00e5da g\u00e5r igenom skivor, tar motsvarande element fr\u00e5n varje, f\u00f6renar dem med en bitoperation och l\u00e4gger resultatet i en resultatlista.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/ec5652a34f0370dfb03df199f341f153.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nOch nu kan vi anv\u00e4nda v\u00e5ra bitmaps och funktioner f\u00f6r att svara p\u00e5 s\u00f6kfr\u00e5gan.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/cf9500ccfe75995a6008191c16729689.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPrestandan \u00e4r inte s\u00e5 h\u00f6g, trots att funktionerna \u00e4r mycket enkla och vi sparade en del resurser genom att inte returnera en ny resultatlista vid varje funktionsanrop.<\/p>\n<p>Efter att ha profilerat lite med pprof m\u00e4rkte jag att Go-kompilatorn missade en mycket enkel men viktig optimering: funktionsinlining.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/9092f5ba3940d0a4f3fbfa90b364d716.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nProblemet \u00e4r att Go-kompilatorn \u00e4r fruktansv\u00e4rt r\u00e4dd f\u00f6r loopar som g\u00e5r igenom skivor och v\u00e4grar kategoriskt att inlinera funktioner som inneh\u00e5ller s\u00e5dana loopar.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/d1bddd62b61b367dd1f680f223fa0ce7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMen jag \u00e4r inte r\u00e4dd och kan lura kompilatorn genom att anv\u00e4nda goto ist\u00e4llet f\u00f6r en loop, precis som p\u00e5 gamla goda tider.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/5b1c3cb26b923972686047910ecd1c31.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/1ca31d12dc90931b674c6a86a4ea23bd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOch som ni ser, nu inlinar kompilatorn gladeligen v\u00e5r funktion! I slut\u00e4ndan lyckas vi spara omkring 2 mikrosekunder. Inte dumt!<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/bdd6735d16082573e600bffe2cdd5662.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDet andra flaskhalsen \u00e4r inte sv\u00e5rt att se om man noggrant tittar p\u00e5 assemblerutdata. Kompilatorn har lagt till en gr\u00e4nskontroll f\u00f6r skivan direkt inuti v\u00e5r mest frekventa loop. Problemet \u00e4r att Go \u00e4r ett s\u00e4kert spr\u00e5k, och kompilatorn \u00e4r orolig f\u00f6r att mina tre argument (tre skivor) har olika storlekar. Det skulle annars teoretiskt kunna leda till s\u00e5 kallad buffert\u00f6verskridning.<\/p>\n<p>L\u00e5t oss lugna kompilatorn genom att visa att alla slice har samma storlek. Vi kan g\u00f6ra detta genom att l\u00e4gga till en enkel kontroll i b\u00f6rjan av v\u00e5r funktion.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/59b4ce687a11dd653e9f12fc3130d89a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nN\u00e4r kompilatorn ser detta hoppar den glatt \u00f6ver kontrollen och vi sparar ytterligare 500 nanosekunder.<\/p>\n<h2>Stora batchar<\/h2>\n<p>\nOkej, vi har lyckats pressa ut n\u00e5gon prestanda fr\u00e5n v\u00e5r enkla implementering, men detta resultat \u00e4r faktiskt mycket s\u00e4mre \u00e4n vad som \u00e4r m\u00f6jligt med den aktuella h\u00e5rdvaran.<\/p>\n<p>Allt vi g\u00f6r \u00e4r grundl\u00e4ggande bitoperationer, och v\u00e5ra processorer utf\u00f6r dem mycket effektivt. Men tyv\u00e4rr \"matade\" vi v\u00e5r processor med v\u00e4ldigt sm\u00e5 jobb. V\u00e5ra funktioner utf\u00f6r operationer byte f\u00f6r byte. Vi kan enkelt finjustera v\u00e5r kod s\u00e5 att den arbetar med 8-byte tillskott genom att anv\u00e4nda UInt64 slices.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/8d1b60ba4b7046c836601631cadd0b6a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSom ni ser har denna lilla \u00e4ndring \u00f6kat hastigheten p\u00e5 v\u00e5rt program \u00e5tta g\u00e5nger genom att \u00f6ka batchstorleken \u00e5tta g\u00e5nger. Vinsten kan s\u00e4gas vara linj\u00e4r.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/0fc663412d04dd38b927de5c8776f69d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Assemblerimplementation<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/b3ef133167b89da983356b1c7389aecd.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMen det \u00e4r inte slutet. V\u00e5ra processorer kan arbeta med block p\u00e5 16, 32 och till och med 64 byte. S\u00e5dana \"bredare\" operationer kallas single instruction multiple data (SIMD; en instruktion, flera data), och processen att omvandla koden s\u00e5 att den anv\u00e4nder dessa operationer kallas vektorisering.<\/p>\n<p>Tyv\u00e4rr \u00e4r Go-kompilatorn l\u00e5ngt ifr\u00e5n en m\u00e4stare p\u00e5 vektorisering. F\u00f6r tillf\u00e4llet \u00e4r det enda s\u00e4ttet att vektorisera kod i Go att manuellt l\u00e4gga in dataoperationerna med hj\u00e4lp av Go-assembler.<\/p>\n<p><img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/91278be45df67e1f9572d68fab7ebad1.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nGo-assembler \u00e4r ett konstigt djur. Du vet f\u00f6rmodligen att assembler \u00e4r n\u00e5got som \u00e4r starkt kopplat till den datorarkitektur du skriver f\u00f6r, men s\u00e5 \u00e4r det inte i Go. Go-assembler liknar mer IRL (intermediate representation language) eller ett mellanliggande spr\u00e5k: det \u00e4r praktiskt taget plattformsoberoende. Rob Pike hade en utm\u00e4rkt <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=KINIAgRpkDA\">med en presentation<\/a><\/noindex> presentation om detta f\u00f6r n\u00e5gra \u00e5r sedan p\u00e5 GopherCon i Denver.<\/p>\n<p>Ut\u00f6ver detta anv\u00e4nder Go ett ovanligt format, Plan 9, som skiljer sig fr\u00e5n de vedertagna formaten AT&amp;T och Intel.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/526f75eb18edfc2f851f2725e9d6f69e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMan kan med s\u00e4kerhet s\u00e4ga att det inte \u00e4r det roligaste att skriva Go-assembler f\u00f6r hand.<\/p>\n<p>Men lyckligtvis finns det redan tv\u00e5 h\u00f6gpresterande verktyg som hj\u00e4lper oss att skriva Go-assembler: PeachPy och avo. B\u00e5da verktygen genererar Go-assembler fr\u00e5n mer h\u00f6g niv\u00e5 kod skriven i Python och Go respektive.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/b8a7aa2c585b805e9b1f2ada186b84e8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDessa verktyg f\u00f6renklar saker som registerallokering, skrivning av loopar och i allm\u00e4nhet g\u00f6r det enklare att komma in i v\u00e4rlden av assemblerprogrammering i Go.<\/p>\n<p>Vi kommer att anv\u00e4nda avo, s\u00e5 v\u00e5ra program kommer att vara n\u00e4stan vanliga Go-program.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/128e4adef14e5f2cf00fb5b6302ef58e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nS\u00e5 h\u00e4r ser det enklaste exemplet p\u00e5 ett avo-program ut. Vi har en funktion main() som definierar en funktion Add() vars syfte \u00e4r att addera tv\u00e5 tal. H\u00e4r finns hj\u00e4lpfunktioner f\u00f6r att h\u00e4mta parametrar efter namn och f\u00f6r att f\u00e5 ett av de lediga och l\u00e4mpliga processorregistren. Varje processoroperation har en motsvarande funktion i avo, som kan ses i ADDQ. Och slutligen har vi en hj\u00e4lpfunktion f\u00f6r att spara det resulterande v\u00e4rdet.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/01ccaa6aa6d394ef598ea2dbc9257d87.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nGenom att anropa go generate kommer vi att k\u00f6ra programmet p\u00e5 avo, och i slut\u00e4ndan kommer tv\u00e5 filer att genereras:<\/p>\n<ul>\n<li>add.s med den resulterande koden i Go-assembler;\n<\/li>\n<li>stub.go med funktionshuvuden f\u00f6r att f\u00f6rena de tv\u00e5 v\u00e4rldarna: Go och assembler.\n<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/72a9443776ecf45eef6fb97a4e08acba.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nNu n\u00e4r vi har sett vad och hur avo g\u00f6r, l\u00e5t oss titta p\u00e5 v\u00e5ra funktioner. Jag har implementerat b\u00e5de de skal\u00e4ra och vektoriserade (SIMD) versionerna av funktionerna.<\/p>\n<p>L\u00e5t oss f\u00f6rst titta p\u00e5 de skal\u00e4ra versionerna.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/ec31dbb8b97b9d7c1012a120fa18cdaf.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSom i det f\u00f6reg\u00e5ende exemplet ber vi om ett ledigt och korrekt allm\u00e4nt register, vi beh\u00f6ver inte ber\u00e4kna f\u00f6rskjutningar och storlekar f\u00f6r argumenten. Allt detta g\u00f6r avo \u00e5t oss.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/88085e927dd943ea0f808a28fb3ccf9b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nTidigare anv\u00e4nde vi etiketter och goto (eller hopp) f\u00f6r att \u00f6ka prestandan och f\u00f6r att lura Go-kompilatorn, men nu g\u00f6r vi detta fr\u00e5n grunden. Po\u00e4ngen \u00e4r att loopar \u00e4r ett h\u00f6gre begrepp. I assembler har vi endast etiketter och hopp.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/9a4181248eb279d89c1445a820b06649.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDen kvarst\u00e5ende koden b\u00f6r redan vara bekant och f\u00f6rst\u00e5elig. Vi emulerar en loop med etiketter och hopp, tar en liten del av data fr\u00e5n v\u00e5ra tv\u00e5 skivor, kombinerar dem med en bitoperation (AND NOT i detta fall) och l\u00e4gger sedan resultatet i den resulterande skivan. Det \u00e4r allt.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/19275ead27f63092fc6596bed38a8d03.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nS\u00e5 h\u00e4r ser den slutliga koden i assembler ut. Vi beh\u00f6vde inte ber\u00e4kna f\u00f6rskjutningar och storlekar (markerade i gr\u00f6nt) eller h\u00e5lla koll p\u00e5 anv\u00e4nda register (markerade i r\u00f6tt).<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/ed68528a6f852634a5b536670c6315f0.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nOm vi j\u00e4mf\u00f6r prestandan f\u00f6r en implementation i assembler med prestandan f\u00f6r den b\u00e4sta implementationen i Go, kommer vi att se att de \u00e4r likv\u00e4rdiga. Och det \u00e4r f\u00f6rv\u00e4ntat. Vi har ju inte gjort n\u00e5got speciellt \u2013 vi har bara \u00e5terskapat vad Go-kompilatorn skulle g\u00f6ra.<\/p>\n<p>Tyv\u00e4rr kan vi inte f\u00e5 kompilatorn att inlinera v\u00e5ra funktioner skrivna i assembler. Go-kompilatorn har f\u00f6r n\u00e4rvarande inte den m\u00f6jligheten, trots att efterfr\u00e5gan p\u00e5 att l\u00e4gga till det har funnits under ganska l\u00e5ng tid.<\/p>\n<p>Det \u00e4r d\u00e4rf\u00f6r det \u00e4r om\u00f6jligt att f\u00e5 n\u00e5gra f\u00f6rdelar fr\u00e5n sm\u00e5 funktioner i assembler. Vi m\u00e5ste antingen skriva stora funktioner eller anv\u00e4nda det nya paketet math\/bits, eller s\u00e5 m\u00e5ste vi undvika assembler helt.<\/p>\n<p>L\u00e5t oss nu titta p\u00e5 de vektoriserade versionerna av v\u00e5ra funktioner.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/7f67c3cc855908fb47c7900d6e5d7f54.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nF\u00f6r detta exempel har jag valt att anv\u00e4nda AVX2, s\u00e5 vi kommer att anv\u00e4nda operationer som arbetar med 32-byte-block. Koden har en struktur som liknar den skal\u00e4ra varianten: l\u00e4sa in parametrar, be om ett ledigt gemensamt register, och s\u00e5 vidare.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/021e0424a0d733ec7db9edeb98ce1f65.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEn nyhet \u00e4r att bredare vektoroperationer anv\u00e4nder speciella breda register. N\u00e4r det g\u00e4ller 32-byte-block \u00e4r det registrets som har prefixet Y. Det \u00e4r d\u00e4rf\u00f6r du ser funktionen YMM() i koden. Om jag hade anv\u00e4nt AVX-512 med 64-byte-block skulle prefixet vara Z.<\/p>\n<p>En andra nyhet \u00e4r att jag har valt att anv\u00e4nda en optimering som kallas loop unrolling, vilket inneb\u00e4r att jag g\u00f6r \u00e5tta loopoperationer manuellt innan jag hoppar tillbaka till b\u00f6rjan av loopen. Denna optimering minskar antalet f\u00f6rgreningar i koden, och den \u00e4r begr\u00e4nsad av antalet tillg\u00e4ngliga register.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/f54631d9e8c69f6f70ecace3133ae1e8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMen hur \u00e4r det med prestanda? Den \u00e4r fantastisk! Vi har f\u00e5tt en acceleration p\u00e5 cirka sju g\u00e5nger j\u00e4mf\u00f6rt med den b\u00e4sta l\u00f6sningen i Go. Imponerande, eller hur?<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/d7e85c933eecb243cfb49225b4d92c6c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMen \u00e4ven denna implementation skulle potentiellt kunna accelereras ytterligare genom att anv\u00e4nda AVX-512, prefetching eller JIT (just-in-time kompilator) f\u00f6r fr\u00e5geplaneraren. Men det \u00e4r definitivt ett \u00e4mne f\u00f6r ett separat f\u00f6redrag.<\/p>\n<h2>Problem med bitmap-index<\/h2>\n<p>\nNu n\u00e4r vi har g\u00e5tt igenom en enkel implementation av bitmap-index i Go och en mycket mer prestandakraftig i assembler, l\u00e5t oss \u00e4ntligen prata om varf\u00f6r bitmap-index s\u00e5 s\u00e4llan anv\u00e4nds.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/83d36a5c92ba90fd680fe8afb6cfc11f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nI \u00e4ldre vetenskapliga arbeten n\u00e4mns tre problem med bitmap-index, men nyare studier och jag h\u00e4vdar att dessa inte l\u00e4ngre \u00e4r aktuella. Vi ska inte g\u00e5 djupt in p\u00e5 varje problem, men vi kommer att behandla dem ytligt.<\/p>\n<h2>Problemet med h\u00f6g kardinalitet<\/h2>\n<p>\nS\u00e5, vi f\u00e5r veta att bitmap-index endast \u00e4r l\u00e4mpliga f\u00f6r f\u00e4lt med l\u00e5g kardinalitet, det vill s\u00e4ga s\u00e5dana som har f\u00e5 v\u00e4rden (till exempel k\u00f6n eller \u00f6gonf\u00e4rg), och anledningen \u00e4r att den vanliga representationen av s\u00e5dana f\u00e4lt (en bit per v\u00e4rde) vid h\u00f6g kardinalitet skulle ta f\u00f6r mycket plats, och dessutom skulle dessa bitmap-index vara svagt (s\u00e4llan) fyllda.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/0787efc4d2cb4ea4d404ca7888b33697.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/44ab4bc7c25d14fe2f53caf5d9da399d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIbland kan vi anv\u00e4nda en annan representation, till exempel den standard som vi anv\u00e4nder f\u00f6r att representera tal. Men det var verkligen introduktionen av komprimeringsalgoritmer som f\u00f6r\u00e4ndrade allt. Under de senaste decennierna har forskare och forskare kommit p\u00e5 ett stort antal komprimeringsalgoritmer f\u00f6r bitmaps. Deras huvudsakliga f\u00f6rdel \u00e4r att vi inte beh\u00f6ver dekomprimera bitmaps f\u00f6r att utf\u00f6ra bitoperationer \u2014 vi kan utf\u00f6ra bitoperationer direkt p\u00e5 de komprimerade bitmaps.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/ecb54fbf15aa11271bbbab01ecbda880.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nP\u00e5 senare tid har ocks\u00e5 hybrida metoder dykt upp, som till exempel roaring bitmaps. De anv\u00e4nder samtidigt tre olika representationer f\u00f6r bitmaps \u2014 sj\u00e4lva bitmaps, arrayer och s\u00e5 kallade bit runs \u2014 och balanserar mellan dem f\u00f6r att maximera prestanda och minimera minnesanv\u00e4ndning.<\/p>\n<p>Du kan se roaring bitmaps i m\u00e5nga popul\u00e4ra applikationer. Det finns redan ett stort antal implementationer f\u00f6r de mest olika programmeringsspr\u00e5ken, inklusive mer \u00e4n tre implementationer f\u00f6r Go.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/de2adfebc431ff48c996247b453f02ae.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEn annan metod som kan hj\u00e4lpa oss att hantera h\u00f6g kardinalitet kallas gruppering (binning). T\u00e4nk dig att du har ett f\u00e4lt som representerar en persons h\u00f6jd. H\u00f6jd \u00e4r ett flyttal, men vi m\u00e4nniskor t\u00e4nker inte p\u00e5 det p\u00e5 det s\u00e4ttet. F\u00f6r oss spelar det ingen roll mellan en h\u00f6jd p\u00e5 185,2 cm och en p\u00e5 185,3 cm.<\/p>\n<p>Detta inneb\u00e4r att vi kan gruppera liknande v\u00e4rden i grupper inom 1 cm.<\/p>\n<p>Och om vi dessutom vet att mycket f\u00e5 m\u00e4nniskor har en h\u00f6jd l\u00e4gre \u00e4n 50 cm och h\u00f6gre \u00e4n 250 cm, kan vi i princip omvandla ett f\u00e4lt med o\u00e4ndlig kardinalitet till ett f\u00e4lt med kardinalitet p\u00e5 cirka 200 v\u00e4rden.<\/p>\n<p>Sj\u00e4lvklart, om s\u00e5 beh\u00f6vs kan vi g\u00f6ra ytterligare filtrering efter\u00e5t.<\/p>\n<h2>Problemet med h\u00f6g genomstr\u00f6mning<\/h2>\n<p>\nN\u00e4sta problem med bitmap-index \u00e4r att deras uppdatering kan vara v\u00e4ldigt kostsam.<\/p>\n<p>Databaser m\u00e5ste m\u00f6jligg\u00f6ra uppdateringar av data samtidigt som potentiellt hundratals andra f\u00f6rfr\u00e5gningar s\u00f6ker i dessa data. Vi beh\u00f6ver l\u00e5s f\u00f6r att undvika problem med samtidig \u00e5tkomst till data eller andra problem med delad \u00e5tkomst. Och d\u00e4r det finns ett stort l\u00e5s, finns det ett problem med lock contention, d\u00e4r detta l\u00e5s blir en flaskhals.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/0ae1bf925542d286f8b7b245c160a35e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDetta problem kan l\u00f6sas eller kringg\u00e5s genom sharding eller anv\u00e4ndning av versionshanterade index.<\/p>\n<p>Sharding \u00e4r en enkel och v\u00e4lk\u00e4nd teknik. Du kan sharda bitmap-index precis som du shardar andra data. Ist\u00e4llet f\u00f6r ett stort l\u00e5s f\u00e5r du flera sm\u00e5 l\u00e5s och p\u00e5 s\u00e5 s\u00e4tt undviker du lock contention.<\/p>\n<p>Ett andra s\u00e4tt att l\u00f6sa problemet \u00e4r att anv\u00e4nda versionshanterade index. Du kan ha en kopia av indexet som du anv\u00e4nder f\u00f6r s\u00f6kning eller l\u00e4sning, och en f\u00f6r skrivning eller uppdatering. Och med j\u00e4mna mellanrum (till exempel var 100 ms eller 500 ms) duplicerar du dem och byter plats. Naturligtvis \u00e4r denna metod endast till\u00e4mplig n\u00e4r din applikation kan fungera med ett n\u00e5got f\u00f6rdr\u00f6jt s\u00f6kindex.<\/p>\n<p>Dessa tv\u00e5 metoder kan anv\u00e4ndas samtidigt: du kan ha ett shardat versionshanterat index.<\/p>\n<h2>Mer komplexa fr\u00e5gor<\/h2>\n<p>Det sista problemet med bitmap-index \u00e4r att de s\u00e4gs vara d\u00e5ligt l\u00e4mpade f\u00f6r mer komplexa typer av fr\u00e5gor, till exempel fr\u00e5gor \"inom intervall\".<\/p>\n<p>Och faktiskt, om vi t\u00e4nker efter, \u00e4r bitoperationer som AND, OR osv. inte riktigt l\u00e4mpliga f\u00f6r fr\u00e5gor som \"Visa mig hotell med priser fr\u00e5n 200 till 300 dollar per natt\".<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/7bc2e129cad46fb5875c2b3018c39ff7.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEn naiv och mycket oklok l\u00f6sning skulle vara att ta resultaten f\u00f6r varje dollarv\u00e4rde och kombinera dem med en bitoperation OR.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/b9f8fc7945caa1866f8e0cfa8a04bd98.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEn n\u00e5got mer korrekt l\u00f6sning skulle vara att anv\u00e4nda gruppering. Till exempel, i grupper om 50 dollar. Detta skulle snabba upp v\u00e5r process med 50 g\u00e5nger.<\/p>\n<p>Men problemet l\u00f6ses lika enkelt med hj\u00e4lp av en representation som skapats speciellt f\u00f6r denna typ av fr\u00e5gor. Inom vetenskapliga arbeten kallas det range-encoded bitmaps.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/644a420628b21f220a7af1ff15c4031f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nI en s\u00e5dan representation s\u00e4tter vi inte bara en bit f\u00f6r ett visst v\u00e4rde (till exempel 200), utan vi anger det v\u00e4rdet och allt som \u00e4r h\u00f6gre. 200 och h\u00f6gre. Samma sak g\u00e4ller f\u00f6r 300: 300 och h\u00f6gre. Och s\u00e5 vidare.<\/p>\n<p>Genom att anv\u00e4nda denna representation kan vi svara p\u00e5 denna typ av s\u00f6kfr\u00e5ga genom att g\u00e5 igenom indexet endast tv\u00e5 g\u00e5nger. F\u00f6rst f\u00e5r vi en lista med hotell d\u00e4r rummet kostar mindre \u00e4n 300 dollar, och sedan tar vi bort de d\u00e4r rumspriserna \u00e4r l\u00e4gre \u00e4n 199 dollar. Klart.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/cc2bb58d7d7a51495c62ec7da81e2d12.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDu kommer att bli f\u00f6rv\u00e5nad, men \u00e4ven geos\u00f6kningar \u00e4r m\u00f6jliga med hj\u00e4lp av bitmap-index. Tricket \u00e4r att anv\u00e4nda en geopresentation som omger dina koordinater med en geometrisk figur. Till exempel, S2 fr\u00e5n Google. Figuren m\u00e5ste kunna representeras med tre eller fler sk\u00e4rande linjer som kan numreras. P\u00e5 s\u00e5 s\u00e4tt kan vi omvandla v\u00e5r geos\u00f6kning till flera \u201dintervall\u201d-fr\u00e5gor (via dessa numrerade linjer).<\/p>\n<h2>F\u00e4rdiga l\u00f6sningar<\/h2>\n<p>\nJag hoppas att jag har v\u00e4ckt ditt intresse lite och att du nu har ett anv\u00e4ndbart verktyg i din verktygsl\u00e5da. Om du n\u00e5gonsin beh\u00f6ver g\u00f6ra n\u00e5got liknande, vet du vilken v\u00e4g du ska titta.<\/p>\n<p>Men inte alla har tid, t\u00e5lamod och resurser f\u00f6r att skapa bitmap-index fr\u00e5n grunden. S\u00e4rskilt mer avancerade som anv\u00e4nder SIMD, till exempel.<\/p>\n<p>Lyckligtvis finns det flera f\u00e4rdiga l\u00f6sningar som kan hj\u00e4lpa dig.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/817b47cb189a758756b602ec9cf319e1.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Roaring bitmaps<\/h2>\n<p>\nF\u00f6rst finns det det som kallas roaring bitmaps-biblioteket, som jag redan n\u00e4mnt. Det inneh\u00e5ller alla n\u00f6dv\u00e4ndiga containrar och bitoperationer som du beh\u00f6ver f\u00f6r att skapa ett fullst\u00e4ndigt bitmap-index.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/57f61a51485c174666b52dc2063fabe8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nTyv\u00e4rr anv\u00e4nder ingen av Go-implementationerna f\u00f6r n\u00e4rvarande SIMD, vilket inneb\u00e4r att Go-implementationerna \u00e4r mindre effektiva \u00e4n de i C, till exempel.<\/p>\n<h2>Pilosa<\/h2>\n<p>\nEn annan produkt som kan hj\u00e4lpa dig \u00e4r databasen Pilosa, som i grunden bara har bitmap-index. Det \u00e4r en relativt ny l\u00f6sning, men den vinner snabbt hj\u00e4rtan.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/d3870a979e1e73d093fe5d5e9bb71cd8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPilosa anv\u00e4nder roaring bitmaps internt och ger dig m\u00f6jlighet att anv\u00e4nda dem, f\u00f6renklar och f\u00f6rklarar alla de saker jag n\u00e4mnde ovan: gruppering, range-encoded bitmaps, begreppet f\u00e4lt osv.<\/p>\n<p>L\u00e5t oss snabbt titta p\u00e5 ett exempel p\u00e5 hur Pilosa anv\u00e4nds f\u00f6r att svara p\u00e5 en fr\u00e5ga som ni redan k\u00e4nner till.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/dfee7abfd653cc19d9aa8b64c64f3e4e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nExemplet liknar mycket det ni har sett tidigare. Vi skapar en klient till Pilosa-servern, skapar ett index och n\u00f6dv\u00e4ndiga f\u00e4lt, fyller sedan v\u00e5ra f\u00e4lt med slumpm\u00e4ssiga data med sannolikheter och utf\u00f6r slutligen den bekanta f\u00f6rfr\u00e5gan.<\/p>\n<p>Efter detta anv\u00e4nder vi NOT p\u00e5 f\u00e4ltet \"expensive\", sedan korsar vi resultatet (eller AND-ar) med f\u00e4ltet \"terrace\" och f\u00e4ltet \"reservations\". Och till slut f\u00e5r vi det slutgiltiga resultatet.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/8d66c6d68019c2297b6c15b700f06a3a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nJag hoppas verkligen att inom en snar framtid kommer ocks\u00e5 databaser som MySQL och PostgreSQL att f\u00e5 denna nya typ av index \u2014 bitmap-index.<br \/>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/7a8e33d576c7fb6376a173ee038b4206.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Slutsats<\/h2>\n<p>\n<img decoding=\"async\" alt=\"Bitmap-index i Go: s\u00f6kning i vild hastighet\" src=\"\/wp-content\/uploads\/2019\/05\/c62caa9ad6f2d96056c80326f4fa9a0d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nOm du \u00e4nnu inte har somnat, tack. Jag var tvungen att snabbprata om m\u00e5nga \u00e4mnen p\u00e5 grund av tidsbegr\u00e4nsningar, men jag hoppas att presentationen varit nyttig och kanske till och med motiverande.<\/p>\n<p>Det \u00e4r bra att k\u00e4nna till bitmap-index, \u00e4ven om du just nu kanske inte beh\u00f6ver dem. L\u00e5t dem vara ytterligare ett verktyg i din verktygsl\u00e5da.<\/p>\n<p>Vi har sett olika trick f\u00f6r att \u00f6ka prestandan f\u00f6r Go och de saker som Go-kompilatorn fortfarande inte hanterar s\u00e4rskilt bra. Och detta \u00e4r definitivt n\u00e5got varje Go-programmerare b\u00f6r veta.<\/p>\n<p>Det \u00e4r allt jag ville ber\u00e4tta. Tack!<br \/>\n<br \/>K\u00e4lla: <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.4 - 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\/sv\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"sv_SE\" \/>\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\/sv\/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\udd47 Bitmap-index i Go: s\u00f6kning med extrem hastighet | ProHoster","description":"Inledande ord Jag gjorde en presentation om.","canonical_url":"https:\/\/prohoster.info\/sv\/blog\/administrirovanie\/bitmap-indeksy-v-go-poisk-na-dikoj-skorosti","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sv_SE","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\/sv\/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\/sv\/wp-json\/wp\/v2\/posts\/33793","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/comments?post=33793"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/posts\/33793\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/media\/25469"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/media?parent=33793"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/categories?post=33793"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/tags?post=33793"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}