Bitmap indeksi u Go: pretražujte divljom brzinom

Bitmap indeksi u Go: pretražujte divljom brzinom

uvod

Dao sam ovaj izvještaj na engleskom na konferenciji GopherCon Russia 2019 u Moskvi i na ruskom na sastanku u Nižnjem Novgorodu. Govorimo o bitmap indeksu - manje uobičajenom od B-stabla, ali ne manje zanimljivom. Dijeljenje snimanje govori na konferenciji na engleskom jeziku i transkripti tekstova na ruskom jeziku.

Pogledaćemo kako funkcioniše bitmap indeks, kada je bolji, kada je lošiji od drugih indeksa i u kojim slučajevima je značajno brži od njih; Pogledajmo koji popularni DBMS-ovi već imaju bitmap indekse; Hajde da pokušamo da napišemo svoje u Go. A „za desert“ ćemo koristiti gotove biblioteke za kreiranje vlastite superbrze specijalizirane baze podataka.

Iskreno se nadam da će vam moji radovi biti korisni i zanimljivi. Idi!

Uvod


http://bit.ly/bitmapindexes
https://github.com/mkevac/gopherconrussia2019

Zdravo svima! Šest je uveče i svi smo super umorni. Odlično vrijeme za razgovor o dosadnoj teoriji indeksa baze podataka, zar ne? Ne brinite, tu i tamo ću imati nekoliko redova izvornog koda. 🙂

Šalu na stranu, izvještaj je prepun informacija, a mi nemamo puno vremena. Pa počnimo.
Bitmap indeksi u Go: pretražujte divljom brzinom
Danas ću pričati o sledećem:

  • šta su indeksi;
  • šta je bitmap indeks;
  • gdje se koristi, a gdje se NE koristi i zašto;
  • jednostavna implementacija u Go i mala borba sa kompajlerom;
  • nešto manje jednostavna, ali mnogo produktivnija implementacija u Go asembleru;
  • “problemi” bitmap indeksa;
  • postojeće implementacije.

Dakle, šta su indeksi?

Bitmap indeksi u Go: pretražujte divljom brzinom

Indeks je zasebna struktura podataka koju održavamo i ažuriramo pored glavnih podataka. Koristi se za ubrzanje pretrage. Bez indeksa, pretraživanje bi zahtijevalo kompletan prolazak kroz podatke (proces koji se zove potpuno skeniranje), a ovaj proces ima linearnu algoritamsku složenost. Ali baze podataka obično sadrže ogromne količine podataka i linearna složenost je prespora. U idealnom slučaju, dobili bismo logaritamsku ili konstantnu.

Ovo je izuzetno složena tema, puna suptilnosti i kompromisa, ali nakon što sam sagledao decenije razvoja baze podataka i istraživanja, spreman sam reći da postoji samo nekoliko široko korištenih pristupa kreiranju indeksa baze podataka.

Bitmap indeksi u Go: pretražujte divljom brzinom

Prvi pristup je da se hijerarhijski smanji prostor za pretraživanje, dijeleći prostor za pretraživanje na manje dijelove.

Obično to radimo koristeći različite vrste drveća. Primjer bi bila velika kutija materijala u vašem ormaru koja sadrži manje kutije materijala podijeljene na različite teme. Ako su vam potrebni materijali, vjerovatno ćete ih potražiti u kutiji na kojoj piše "Materijali", a ne u onoj na kojoj piše "Kolačići", zar ne?

Bitmap indeksi u Go: pretražujte divljom brzinom

Drugi pristup je da odmah odaberete željeni element ili grupu elemenata. To radimo u hash mapama ili obrnutim indeksima. Korištenje hash mapa je vrlo slično prethodnom primjeru, ali umjesto kutije kutija, u svom ormaru imate gomilu malih kutija konačnih predmeta.

Bitmap indeksi u Go: pretražujte divljom brzinom

Treći pristup je eliminisanje potrebe za pretraživanjem. To radimo pomoću Bloom filtera ili cuckoo filtera. Prvi daju odgovor odmah, štedeći vas od potrebe za pretraživanjem.

Bitmap indeksi u Go: pretražujte divljom brzinom

Posljednji pristup je da u potpunosti iskoristimo svu snagu koju nam daje moderni hardver. To je upravo ono što radimo u bitmap indeksima. Da, kada ih koristimo ponekad moramo proći kroz cijeli indeks, ali mi to radimo super efikasno.

Kao što sam rekao, tema indeksa baza podataka je ogromna i puna kompromisa. To znači da ponekad možemo koristiti nekoliko pristupa istovremeno: ako želimo još više ubrzati pretragu ili ako trebamo pokriti sve moguće vrste pretraživanja.

Danas ću govoriti o najmanje poznatom pristupu od ovih - bitmap indeksima.

Ko sam ja da govorim o ovoj temi?

Bitmap indeksi u Go: pretražujte divljom brzinom

Radim kao timski vođa u Badoou (možda ste bolje upoznati s našim drugim proizvodom, Bumble). Već imamo više od 400 miliona korisnika širom svijeta i mnoge funkcije koje biraju najbolje za njih. To radimo koristeći prilagođene usluge, uključujući bitmap indekse.

Dakle, šta je bitmap indeks?

Bitmap indeksi u Go: pretražujte divljom brzinom
Bitmap indeksi, kao što ime sugerira, koriste bitmape ili bitsetove za implementaciju indeksa pretraživanja. Iz ptičje perspektive, ovaj indeks se sastoji od jedne ili više takvih bitmapa koje predstavljaju bilo koji entitet (kao što su ljudi) i njihova svojstva ili parametre (starost, boja očiju, itd.), i algoritma koji koristi bitne operacije (I, ILI, NOT ) da odgovorite na upit za pretragu.
Bitmap indeksi u Go: pretražujte divljom brzinom
Rečeno nam je da su bitmap indeksi najprikladniji i vrlo efikasni za slučajeve u kojima postoje pretrage koje kombinuju upite u mnogim kolonama niske kardinalnosti (mislite na "boju očiju" ili "bračni status" u odnosu na nešto poput "udaljenost od centra grada"). Ali kasnije ću pokazati da dobro funkcioniraju i za stupce visoke kardinalnosti.

Pogledajmo najjednostavniji primjer bitmap indeksa.
Bitmap indeksi u Go: pretražujte divljom brzinom
Zamislite da imamo listu moskovskih restorana sa binarnim svojstvima poput ovih:

  • blizu metroa;
  • postoji privatni parking;
  • ima veranda (ima terasu);
  • možete rezervisati sto (prihvata rezervacije);
  • pogodno za vegetarijance (prilagođeno veganima);
  • skupo (skupo).

Bitmap indeksi u Go: pretražujte divljom brzinom
Dajmo svakom restoranu redni broj koji počinje od 0 i dodijelimo memoriju za 6 bitmapa (po jednu za svaku karakteristiku). Zatim ćemo popuniti ove bitmape ovisno o tome ima li restoran ovo svojstvo ili ne. Ako restoran 4 ima verandu, tada će bit br. 4 u bitmapu „ima verandu“ biti postavljen na 1 (ako nema verande, onda na 0).
Bitmap indeksi u Go: pretražujte divljom brzinom
Sada imamo najjednostavniji mogući bitmap indeks i možemo ga koristiti da odgovorimo na upite kao što su:

  • “Pokaži mi restorane prilagođene vegetarijancima”;
  • “Pokažite mi jeftine restorane sa verandom na kojima možete rezervisati sto.”

Bitmap indeksi u Go: pretražujte divljom brzinom
Bitmap indeksi u Go: pretražujte divljom brzinom
Kako? Hajde da pogledamo. Prvi zahtjev je vrlo jednostavan. Sve što treba da uradimo je da uzmemo bitmapu „prilagođenu vegetarijancima“ i pretvorimo je u listu restorana čiji su delovi izloženi.
Bitmap indeksi u Go: pretražujte divljom brzinom
Bitmap indeksi u Go: pretražujte divljom brzinom
Drugi zahtjev je malo komplikovaniji. Trebamo koristiti NOT bitmap na "skupoj" bitmapi da dobijemo listu jeftinih restorana, zatim I to sa bitmapom "mogu li rezervirati sto" i I rezultat sa bitmapom "postoji veranda". Dobivena bitmapa će sadržavati listu ustanova koje ispunjavaju sve naše kriterije. U ovom primjeru ovo je samo restoran Yunost.
Bitmap indeksi u Go: pretražujte divljom brzinom
Bitmap indeksi u Go: pretražujte divljom brzinom
Mnogo je teorije uključeno, ali ne brinite, vrlo brzo ćemo vidjeti kod.

Gdje se koriste bitmap indeksi?

Bitmap indeksi u Go: pretražujte divljom brzinom
Ako Google indeksirate bitmap, 90% odgovora će se na ovaj ili onaj način odnositi na Oracle DB. Ali i drugi DBMS-ovi vjerovatno podržavaju tako kul stvar, zar ne? Ne baš.

Idemo kroz listu glavnih osumnjičenih.
Bitmap indeksi u Go: pretražujte divljom brzinom
MySQL još ne podržava bitmap indekse, ali postoji Prijedlog koji predlaže dodavanje ove opcije (https://dev.mysql.com/worklog/task/?id=1524).

PostgreSQL ne podržava bitmap indekse, ali koristi jednostavne bitmape i bitne operacije da kombinuje rezultate pretraživanja u više drugih indeksa.

Tarantool ima bitset indekse i podržava jednostavne pretrage na njima.

Redis ima jednostavna bitna polja (https://redis.io/commands/bitfield) bez mogućnosti da ih traže.

MongoDB još ne podržava bitmap indekse, ali postoji i Prijedlog koji predlaže da se ova opcija doda https://jira.mongodb.org/browse/SERVER-1723

Elasticsearch interno koristi bitmape (https://www.elastic.co/blog/frame-of-reference-and-roaring-bitmaps).

Bitmap indeksi u Go: pretražujte divljom brzinom

  • Ali u našoj kući se pojavila nova komšinica: Pilosa. Ovo je nova nerelaciona baza podataka napisana u Go. Sadrži samo bitmap indekse i bazira sve na njima. Pričaćemo o tome malo kasnije.

Implementacija u Go

Ali zašto se bitmap indeksi tako rijetko koriste? Prije nego što odgovorim na ovo pitanje, htio bih vam pokazati kako implementirati vrlo jednostavan bitmap indeks u Go.
Bitmap indeksi u Go: pretražujte divljom brzinom
Bitmape su u suštini samo delovi podataka. U Go, koristimo rezove bajtova za ovo.

Imamo jednu bitmapu za jednu karakteristiku restorana, a svaki bit u bitmapi pokazuje da li određeni restoran ima ovo svojstvo ili ne.
Bitmap indeksi u Go: pretražujte divljom brzinom
Trebat će nam dvije pomoćne funkcije. Jedan će se koristiti za popunjavanje naših bitmapa nasumičnim podacima. Nasumično, ali sa određenom vjerovatnoćom da restoran ima svaki posjed. Na primjer, vjerujem da je u Moskvi vrlo malo restorana u kojima ne možete rezervisati sto, a čini mi se da je oko 20% objekata pogodno za vegetarijance.

Druga funkcija će pretvoriti bitmap u listu restorana.
Bitmap indeksi u Go: pretražujte divljom brzinom
Bitmap indeksi u Go: pretražujte divljom brzinom
Da bismo odgovorili na upit "Pokaži mi jeftine restorane koji imaju terasu i mogu rezervirati", potrebne su nam dvije bitne operacije: NOT i AND.

Možemo malo pojednostaviti naš kod koristeći složeniji operator I NOT.

Imamo funkcije za svaku od ovih operacija. I jedan i drugi prolaze kroz kriške, uzimaju odgovarajuće elemente iz svake, kombinuju ih malom operacijom i stavljaju rezultat u rezultujući rez.
Bitmap indeksi u Go: pretražujte divljom brzinom
I sada možemo koristiti naše bitmape i funkcije da odgovorimo na upit za pretraživanje.
Bitmap indeksi u Go: pretražujte divljom brzinom
Performanse nisu tako visoke, iako su funkcije vrlo jednostavne i uštedjeli smo mnogo novca tako što nismo vraćali novi rezultujući dio svaki put kada je funkcija pozvana.

Nakon što sam uradio malo profiliranja sa pprof-om, primijetio sam da Go kompajleru nedostaje jedna vrlo jednostavna, ali vrlo važna optimizacija: umetanje funkcija.
Bitmap indeksi u Go: pretražujte divljom brzinom
Činjenica je da se Go kompajler užasno boji petlji koje prolaze kroz rezove i kategorički odbija da ugradi funkcije koje sadrže takve petlje.
Bitmap indeksi u Go: pretražujte divljom brzinom
Ali ne bojim se i mogu prevariti kompajler koristeći goto umjesto petlje, kao u dobra stara vremena.

Bitmap indeksi u Go: pretražujte divljom brzinom
Bitmap indeksi u Go: pretražujte divljom brzinom

I, kao što vidite, sada će kompajler rado ugraditi našu funkciju! Kao rezultat, uspijevamo uštedjeti oko 2 mikrosekunde. Nije loše!

Bitmap indeksi u Go: pretražujte divljom brzinom

Drugo usko grlo je lako uočiti ako pažljivo pogledate izlaz sklopa. Kompajler je dodao provjeru granice isječaka upravo unutar naše najtoplije petlje. Činjenica je da je Go siguran jezik, kompajler se boji da su moja tri argumenta (tri sreza) različite veličine. Na kraju krajeva, tada će postojati teoretska mogućnost pojave takozvanog prekoračenja bafera.

Uvjerimo kompajler tako što ćemo mu pokazati da su svi rezovi iste veličine. To možemo učiniti dodavanjem jednostavne provjere na početak naše funkcije.
Bitmap indeksi u Go: pretražujte divljom brzinom
Vidjevši ovo, kompajler sretno preskoči provjeru i na kraju uštedimo još 500 nanosekundi.

Big butches

U redu, uspjeli smo da izvučemo neke performanse iz naše jednostavne implementacije, ali ovaj rezultat je zapravo mnogo lošiji nego što je to moguće sa trenutnim hardverom.

Sve što radimo su osnovne bitne operacije, a naši procesori ih izvode vrlo efikasno. Ali, nažalost, naš procesor “hranimo” vrlo malim poslom. Naše funkcije izvode operacije na bazi bajt po bajt. Možemo vrlo lako podesiti naš kod za rad sa 8-bajtnim dijelovima koristeći UInt64 rezove.

Bitmap indeksi u Go: pretražujte divljom brzinom

Kao što vidite, ova mala promjena je ubrzala naš program osam puta povećanjem veličine serije za osam puta. Može se reći da je dobitak linearan.

Bitmap indeksi u Go: pretražujte divljom brzinom

Implementacija u asembleru

Bitmap indeksi u Go: pretražujte divljom brzinom
Ali ovo nije kraj. Naši procesori mogu raditi s komadima od 16, 32 pa čak i 64 bajta. Takve “široke” operacije se nazivaju jedna instrukcija višestruki podaci (SIMD; jedna instrukcija, mnogo podataka), a proces transformacije koda tako da koristi takve operacije naziva se vektorizacija.

Nažalost, Go kompajler je daleko od odličnog u vektorizaciji. Trenutno, jedini način da se vektorizuje Go kod je da uzmete i postavite ove operacije ručno koristeći Go asembler.

Bitmap indeksi u Go: pretražujte divljom brzinom

Go asembler je čudna zvijer. Verovatno znate da je asemblerski jezik nešto što je u velikoj meri povezano sa arhitekturom računara za koji pišete, ali to nije slučaj u Go. Go asembler je više kao IRL (srednji jezik predstavljanja) ili srednji jezik: praktično je nezavisan od platforme. Rob Pike je dao odličnu predstavu izvještaj na ovu temu prije nekoliko godina na GopherConu u Denveru.

Osim toga, Go koristi neobičan format Plan 9, koji se razlikuje od općenito prihvaćenih AT&T i Intel formata.
Bitmap indeksi u Go: pretražujte divljom brzinom
Može se reći da ručno pisanje Go asemblera nije najzabavnije.

Ali, na sreću, već postoje dva alata visokog nivoa koji nam pomažu da napišemo Go asembler: PeachPy i avo. Oba uslužna programa generišu Go asembler iz koda višeg nivoa napisanog u Python-u i Go-u.
Bitmap indeksi u Go: pretražujte divljom brzinom
Ovi uslužni programi pojednostavljuju stvari poput dodjele registara, pisanja petlji i općenito pojednostavljuju proces ulaska u svijet programiranja sklopova u Go.

Koristićemo avo, tako da će naši programi biti skoro redovni Go programi.
Bitmap indeksi u Go: pretražujte divljom brzinom
Ovako izgleda najjednostavniji primjer avo programa. Imamo funkciju main() koja unutar sebe definira funkciju Add(), čije je značenje zbrajanje dva broja. Ovdje postoje pomoćne funkcije za dobivanje parametara po imenu i dobivanje jednog od besplatnih i odgovarajućih registara procesora. Svaka operacija procesora ima odgovarajuću funkciju na avo, kao što se vidi u ADDQ. Konačno, vidimo pomoćnu funkciju za pohranjivanje rezultirajuće vrijednosti.
Bitmap indeksi u Go: pretražujte divljom brzinom
Pozivanjem go generate, mi ćemo izvršiti program na avo i kao rezultat će biti generisana dva fajla:

  • add.s sa rezultujućim kodom u Go asembleru;
  • stub.go sa zaglavljima funkcija za povezivanje dva svijeta: Go i asembler.

Bitmap indeksi u Go: pretražujte divljom brzinom
Sada kada smo vidjeli šta avo radi i kako, pogledajmo naše funkcije. Implementirao sam i skalarnu i vektorsku (SIMD) verziju funkcija.

Pogledajmo prvo skalarne verzije.
Bitmap indeksi u Go: pretražujte divljom brzinom
Kao iu prethodnom primjeru, tražimo besplatan i važeći registar opće namjene, ne moramo izračunavati pomake i veličine za argumente. avo sve ovo radi za nas.
Bitmap indeksi u Go: pretražujte divljom brzinom
Ranije smo koristili oznake i goto (ili skokove) da poboljšamo performanse i prevarimo Go kompajler, ali sada to radimo od početka. Poenta je da su ciklusi koncept višeg nivoa. U asembleru imamo samo oznake i skokove.
Bitmap indeksi u Go: pretražujte divljom brzinom
Preostali kod bi već trebao biti poznat i razumljiv. Mi emuliramo petlju s oznakama i skokovima, uzimamo mali dio podataka iz naša dva odsječka, kombiniramo ih s malom operacijom (A NE u ovom slučaju) i zatim stavljamo rezultat u rezultujući rez. Sve.
Bitmap indeksi u Go: pretražujte divljom brzinom
Ovako izgleda konačni asemblerski kod. Nismo morali da izračunavamo pomake i veličine (označeno zelenom bojom) niti da pratimo korišćene registre (označeno crvenom bojom).
Bitmap indeksi u Go: pretražujte divljom brzinom
Ako uporedimo performanse implementacije asemblerskog jezika sa performansama najbolje implementacije u Go-u, videćemo da je to isto. I to je očekivano. Na kraju krajeva, nismo uradili ništa posebno – samo smo reprodukovali ono što bi Go kompajler uradio.

Nažalost, ne možemo natjerati kompajler da ugradi naše funkcije napisane u asemblerskom jeziku. Go kompajler trenutno nema takvu mogućnost, iako postoji zahtjev za dodavanjem već duže vrijeme.

Zbog toga je nemoguće izvući bilo kakvu korist od malih funkcija u asemblerskom jeziku. Moramo ili napisati velike funkcije, ili koristiti novi paket matematike/bitova, ili zaobići asemblerski jezik.

Pogledajmo sada vektorske verzije naših funkcija.
Bitmap indeksi u Go: pretražujte divljom brzinom
Za ovaj primjer, odlučio sam koristiti AVX2, tako da ćemo koristiti operacije koje rade na 32-bajtnim komadima. Struktura koda je vrlo slična skalarnoj verziji: učitavanje parametara, traženje besplatnog zajedničkog registra, itd.
Bitmap indeksi u Go: pretražujte divljom brzinom
Jedna od inovacija je da šire vektorske operacije koriste posebne široke registre. U slučaju 32-bajtnih komada, ovo su registri sa prefiksom Y. Zbog toga vidite funkciju YMM() u kodu. Da koristim AVX-512 sa 64-bitnim dijelovima, prefiks bi bio Z.

Druga inovacija je ta što sam odlučio da koristim optimizaciju koja se zove odmotavanje petlje, što znači da izvršim osam operacija petlje ručno prije nego što skočim na početak petlje. Ova optimizacija smanjuje broj grana u kodu i ograničena je brojem dostupnih slobodnih registara.
Bitmap indeksi u Go: pretražujte divljom brzinom
Pa, šta je sa performansama? Ona je prelijepa! Ostvarili smo ubrzanje od oko sedam puta u odnosu na najbolje Go rješenje. Impresivno, zar ne?
Bitmap indeksi u Go: pretražujte divljom brzinom
Ali čak se i ova implementacija potencijalno može ubrzati korištenjem AVX-512, prethodnog dohvaćanja ili JIT-a (baš na vrijeme kompajler) za planer upita. Ali ovo je svakako tema za poseban izvještaj.

Problemi sa bitmap indeksima

Sada kada smo već pogledali jednostavnu implementaciju bitmap indeksa u Go i mnogo produktivniju u asemblerskom jeziku, hajde da konačno razgovaramo o tome zašto se bitmap indeksi tako retko koriste.
Bitmap indeksi u Go: pretražujte divljom brzinom
Stariji radovi spominju tri problema sa bitmap indeksima, ali noviji radovi i ja tvrdim da oni više nisu relevantni. Nećemo se udubljivati ​​u svaki od ovih problema, već ćemo ih sagledati površno.

Problem visoke kardinalnosti

Dakle, rečeno nam je da su bitmap indeksi prikladni samo za polja sa niskom kardinalnošću, odnosno ona koja imaju malo vrijednosti (na primjer, spol ili boju očiju), a razlog je što uobičajeno predstavljanje takvih polja (jedan bit po vrijednosti) u slučaju visoke kardinalnosti, zauzet će previše prostora i, osim toga, ovi bitmap indeksi će biti loše (rijetko) popunjeni.
Bitmap indeksi u Go: pretražujte divljom brzinom
Bitmap indeksi u Go: pretražujte divljom brzinom
Ponekad možemo koristiti drugačiji prikaz, kao što je standardni koji koristimo za predstavljanje brojeva. Ali upravo je pojava algoritama za kompresiju promijenila sve. Tokom proteklih decenija, naučnici i istraživači su došli do velikog broja algoritama kompresije za bitmape. Njihova glavna prednost je u tome što nema potrebe za dekompresijom bitmapa za izvođenje bitnih operacija – možemo izvoditi bitne operacije direktno na komprimiranim bitmapama.
Bitmap indeksi u Go: pretražujte divljom brzinom
Nedavno su se počeli pojavljivati ​​hibridni pristupi, kao što su bučne bitmape. Oni istovremeno koriste tri različita prikaza za bitmape - same bitmape, nizove i takozvane bitove - i balansiraju između njih kako bi maksimizirali performanse i minimizirali potrošnju memorije.

U najpopularnijim aplikacijama možete pronaći bučne bitmape. Već postoji ogroman broj implementacija za širok spektar programskih jezika, uključujući više od tri implementacije za Go.
Bitmap indeksi u Go: pretražujte divljom brzinom
Drugi pristup koji nam može pomoći da se nosimo s visokom kardinalnošću naziva se binning. Zamislite da imate polje koje predstavlja visinu osobe. Visina je broj u pokretnom zarezu, ali mi ljudi o tome ne razmišljamo na taj način. Za nas ne postoji razlika između visine 185,2 cm i 185,3 cm.

Ispostavilo se da slične vrijednosti možemo grupirati u grupe unutar 1 cm.

A ako također znamo da je vrlo malo ljudi nižih od 50 cm i viših od 250 cm, onda u suštini možemo pretvoriti polje beskonačne kardinalnosti u polje sa kardinalnošću od oko 200 vrijednosti.

Naravno, po potrebi možemo naknadno izvršiti dodatno filtriranje.

Problem visoke propusnosti

Sljedeći problem sa bitmap indeksima je taj što njihovo ažuriranje može biti veoma skupo.

Baze podataka moraju biti u mogućnosti ažurirati podatke dok potencijalno stotine drugih upita pretražuju podatke. Potrebne su nam brave kako bismo izbjegli probleme s istovremenim pristupom podacima ili druge probleme dijeljenja. A tamo gdje postoji jedna velika brava, postoji problem - sukob brave, kada ova brava postane usko grlo.
Bitmap indeksi u Go: pretražujte divljom brzinom
Ovaj problem se može riješiti ili zaobići korištenjem dijeljenja ili korištenjem verzioniranih indeksa.

Sharding je jednostavna i dobro poznata stvar. Možete podijeliti bitmap indeks kao i sve druge podatke. Umjesto jedne velike brave, dobit ćete gomilu malih brava i tako se riješiti svađe oko zaključavanja.

Drugi način rješavanja problema je korištenje verzioniranih indeksa. Možete imati jednu kopiju indeksa koju koristite za pretraživanje ili čitanje i jednu koju koristite za pisanje ili ažuriranje. I jednom u određenom vremenskom periodu (na primjer, jednom svakih 100 ms ili 500 ms) vi ih duplirate i zamijenite. Naravno, ovaj pristup je primenljiv samo u slučajevima kada vaša aplikacija može da obradi indeks pretraživanja koji malo zaostaje.

Ova dva pristupa se mogu koristiti istovremeno: možete imati razdijeljeni verzionirani indeks.

Složeniji upiti

Konačni problem sa bitmap indeksima je taj što nam je rečeno da nisu dobro prikladni za složenije tipove upita, kao što su span upiti.

Zaista, ako razmislite o tome, bitne operacije poput AND, OR itd. nisu baš prikladne za upite a la „Pokažite mi hotele sa cijenama soba od 200 do 300 dolara po noći.“
Bitmap indeksi u Go: pretražujte divljom brzinom
Naivno i vrlo nerazumno rješenje bilo bi uzeti rezultate za svaku vrijednost u dolarima i kombinirati ih s operacijom ILI po bitovima.
Bitmap indeksi u Go: pretražujte divljom brzinom
Malo bolje rješenje bi bilo korištenje grupiranja. Na primjer, u grupama od 50 dolara. Ovo bi ubrzalo naš proces za 50 puta.

Ali problem se također lako rješava korištenjem pogleda kreiranog posebno za ovu vrstu zahtjeva. U naučnim radovima to se naziva bitmapama kodiranih rasponom.
Bitmap indeksi u Go: pretražujte divljom brzinom
U ovom prikazu ne postavljamo samo jedan bit za neku vrijednost (na primjer, 200), već postavljamo ovu vrijednost i sve više. 200 i više. Isto za 300: 300 i više. I tako dalje.

Koristeći ovu reprezentaciju, možemo odgovoriti na ovu vrstu upita pretraživanja prelazeći indeks samo dva puta. Prvo ćemo dobiti listu hotela u kojima soba košta manje ili $300, a zatim ćemo ukloniti one u kojima je cijena sobe manja ili $199. Spreman.
Bitmap indeksi u Go: pretražujte divljom brzinom
Bićete iznenađeni, ali čak su i geoupiti mogući pomoću bitmap indeksa. Trik je u korištenju geometrijskog prikaza koji okružuje vašu koordinatu geometrijskom figurom. Na primjer, S2 od Google-a. Slika bi trebala biti moguće predstaviti u obliku tri ili više linija koje se ukrštaju koje se mogu numerisati. Na ovaj način možemo pretvoriti naš geoupit u nekoliko upita „duž procjepa“ (duž ovih numeriranih linija).

Ready Solutions

Nadam se da sam vas malo zainteresovao i da sada imate još jedno korisno sredstvo u svom arsenalu. Ako ikada zatrebate da uradite ovako nešto, znaćete na koji način da gledate.

Međutim, nemaju svi vremena, strpljenja ili resursa da kreiraju bitmap indekse od nule. Pogotovo naprednije, koristeći SIMD, na primjer.

Srećom, postoji nekoliko gotovih rješenja koja će vam pomoći.
Bitmap indeksi u Go: pretražujte divljom brzinom

Roaring bitmap

Prvo, tu je ista ona bujna biblioteka bitmapa o kojoj sam već govorio. Sadrži sve potrebne kontejnere i bitne operacije koje će vam trebati da napravite punopravni bitmap indeks.
Bitmap indeksi u Go: pretražujte divljom brzinom
Nažalost, u ovom trenutku, nijedna od implementacija Go ne koristi SIMD, što znači da su Go implementacije manje efikasne od C implementacija, na primjer.

Pilosa

Još jedan proizvod koji vam može pomoći je Pilosa DBMS, koji, u stvari, ima samo bitmap indekse. Ovo je relativno novo rješenje, ali osvaja srca velikom brzinom.
Bitmap indeksi u Go: pretražujte divljom brzinom
Pilosa interno koristi bujne bitmape i daje vam mogućnost da ih koristite, pojednostavljuje i objašnjava sve stvari o kojima sam govorio gore: grupiranje, bitmape kodirane u rasponu, koncept polja, itd.

Pogledajmo na brzinu primjer korištenja Pilosa za odgovor na pitanje koje vam je već poznato.
Bitmap indeksi u Go: pretražujte divljom brzinom
Primjer je vrlo sličan onome što ste vidjeli prije. Kreiramo klijenta za Pilosa server, kreiramo indeks i potrebna polja, zatim popunjavamo naša polja slučajnim podacima sa vjerovatnoćama i, na kraju, izvršavamo poznati upit.

Nakon toga koristimo NE na polju "skupo", a zatim siječemo rezultat (ili I to) sa poljem "terasa" i poljem "rezervacije". I konačno, dobijamo konačni rezultat.
Bitmap indeksi u Go: pretražujte divljom brzinom
Zaista se nadam da će se u doglednoj budućnosti ovaj novi tip indeksa pojaviti i u DBMS-ovima poput MySQL i PostgreSQL - bitmap indeksi.
Bitmap indeksi u Go: pretražujte divljom brzinom

zaključak

Bitmap indeksi u Go: pretražujte divljom brzinom
Ako još niste zaspali, hvala. Morao sam se ukratko dotaknuti mnogih tema zbog ograničenog vremena, ali nadam se da je razgovor bio koristan, a možda čak i motivirajući.

Bitmap indekse je dobro znati, čak i ako vam trenutno ne trebaju. Neka budu još jedan alat u vašoj kutiji sa alatima.

Pogledali smo razne trikove performansi za Go i stvari sa kojima Go kompajler još ne radi najbolje. Ali ovo je apsolutno korisno za svakog Go programera da zna.

To je sve što sam ti htio reći. Hvala ti!

izvor: www.habr.com

Dodajte komentar