Bitmap-indeksid Go-s: otsimine metsiku kiirusel

Bitmap-indeksid Go-s: otsimine metsiku kiirusel

Sissejuhatav sÔna

Esitasin selle ettekande inglise keeles konverentsil GopherCon Venemaa 2019 Moskvas ja vene keeles kohtumisel Nizhni Novgorodis. RÀÀgin bitmap-indeksist — vĂ€hem levinud, kui B-puu, kuid mitte vĂ€hem huvitav. Jagatud salvestus ettekandest konverentsil inglise keeles ja tekstiline tĂ”lge vene keeles.

KĂ€sitleme, kuidas bitmap-indeks töötab, millal on see parem, millal halvem kui teised indeksid ja millal on see neist oluliselt kiirem; nĂ€eme, millistes populaarsetes andmebaasisĂŒsteemides juba on bitmap-indekseid; proovime kirjutada oma Go-s. Ja „magustoiduks“ kasutame valmis raamatukogusid, et luua oma superkiire spetsialiseeritud andmebaas.

Loodan tÔeliselt, et mu töö leidub teile kasulik ja huvitav. LÀhme!

Sissejuhatus

MĂ€ngi videot

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

Tere kĂ”igile! On kuus Ă”htul, me kĂ”ik oleme ĂŒlivĂ€sinud. SuurepĂ€rane aeg rÀÀkida igavast andmebaasi indeksite teooriast, eks? Ärge muretsege, mul on siin ja seal paar rida algkoodi. 🙂

TÔsiselt rÀÀkides, ettekande on informatsiooni tÀis, kuid meie aega pole palju. Seega alustame.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
TÀna rÀÀgin jÀrgmistest teemadest:

  • mis on indeksid;
  • mis on bitmap-indeks;
  • kus seda kasutatakse ja kus ei kasutata ning miks;
  • lihtne rakendus Go-s ja natuke vĂ”itlust kompilaatoriga;
  • veidi vĂ€hem lihtne, kuid palju tĂ”husam rakendus Go-assembleril;
  • "probleemid" bitmap-indeksitega;
  • olemasolevad rakendused.

Mis siis on indeksid?

Bitmap-indeksid Go-s: otsimine metsiku kiirusel

Indeks on eraldiseisev andmestruktuur, mida hoiame ja uuendame peamise andmekogumi lisana. Seda kasutatakse otsingu kiirendamiseks. Ilma indeksiteta nĂ”uaks otsing andmete tĂ€ielikku lĂ€bimist (protsess, mida nimetatakse full scaniks), ja selle protsessi algoritmiline keerukus on lineaarne. Kuid andmebaasid sisaldavad tavaliselt tohutul hulgal andmeid, ning lineaarne keerukus — see on liiga aeglane. Ideaalis tahaksime saavutada logaritmilise vĂ”i konstantse.

See on tohutu keeruline teema, tĂ€is nĂŒansse ja kompromisse, kuid vaadates aastate jooksul eri andmebaaside arengut ja uurimist, olen valmis vĂ€itma, et andmebaasi indeksite loomiseks on vaid mĂ”ned laialdaselt kasutatavad lĂ€henemisviisid.

Bitmap-indeksid Go-s: otsimine metsiku kiirusel

Esimene lÀhenemine hÔlmab otsingupiirkonna hierarhilist vÀhendamist, jagades otsingupiirkonna vÀiksemateks osadeks.

Tavaliselt teeme seda erinevat tĂŒĂŒpi puude abil. NĂ€iteks vĂ”ib tuua suure kasti materjalidega teie riidekapis, mis sisaldab vĂ€iksemaid kaste, mis on jaotatud erinevate teemade jĂ€rgi. Kui vajate materjale, siis otsite kindlasti materjalide sildiga kastist, mitte kĂŒpsiste sildiga kastist, eks?

Bitmap-indeksid Go-s: otsimine metsiku kiirusel

Teine lĂ€henemine on kohe vajaliku elemendi vĂ”i elementide rĂŒhma eristamine. Teeme seda hash-map'ide vĂ”i pöördindeksite abil. Hash-map'ide kasutamine sarnaneb eelnevale nĂ€itele, ainult et teie kapis on hulk vĂ€ikseid kaste lĂ”plike esemete kogumitega.

Bitmap-indeksid Go-s: otsimine metsiku kiirusel

Kolmas lÀhenemine on vabaneda otsingu vajadusest. Selle teeme Bloom-filtrite vÔi cuckoo-filtrite abil. Esimesed annavad vastuse kohe, vabastades teid otsimise kohustusest.

Bitmap-indeksid Go-s: otsimine metsiku kiirusel

Viimane lĂ€henemine on tĂ€ielikult kasutada kĂ”iki vĂ”imeid, mida tĂ€napĂ€evane riistvara meile pakub. Just seda teeme bitmap-indeхite abil. Jah, nende kasutamisel tuleb meil mĂ”nikord kogu indeks lĂ€bi kĂ€ia, kuid teeme seda ĂŒlimalt efektiivselt.

Kuidas ma juba ĂŒtlesin, on andmebaasi indeksite teema ulatuslik ja tĂ€is kompromisse. See tĂ€hendab, et mĂ”nikord saame kasutada mitut lĂ€henemist korraga: kui peame otsingut veelgi kiiremaks muutma vĂ”i kui on vaja katab kĂ”iki vĂ”imalikke otsingutĂŒĂŒpe.

TĂ€na rÀÀgin ma kĂ”ige vĂ€hem tuntud lĂ€henemisest - bitmap-indeхitest.

Kes ma olen, et sellest teemast rÀÀkida?

Bitmap-indeksid Go-s: otsimine metsiku kiirusel

Töötan meeskonnajuhina Badoos (vĂ”ib-olla tunnete paremini meie teist toodet - Bumble). Meil on ĂŒle 400 miljoni kasutaja ĂŒle kogu maailma ja palju funktsioone, mis aitavad leida neile parima kaaslase. Teeme seda kohandatud teenuste abil, mis kasutavad sealhulgas ka bitmap-indeхite.

Mis siis on bitmap-indeks?

Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Bitmap-indeksid, nagu nimigi ĂŒtleb, kasutavad bitmape vĂ”i bitsĂŒste, et rakendada otsinguindeksit. KĂ”rgselt vaadatuna koosneb see indeks ĂŒhest vĂ”i mitmest sellisest bitmapist, mis esindavad teatud entiteete (nt inimesi) ja nende omadusi vĂ”i parameetreid (vanus, silmade vĂ€rv jne), ning algoritmist, mis kasutab bititehteid (AND, OR, NOT) otsingu pĂ€ringule vastamiseks.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Meile öeldakse, et bitmap-indeksid sobivad kĂ”ige paremini ja on vĂ€ga tĂ”husad olukordades, kus otsingu kĂ€igus ĂŒhendatakse pĂ€ringud paljude vĂ€hekaariliste veergudega (kujuta ette „silmade vĂ€rv” vĂ”i „pereliikmeid” vĂ”rreldes millegagi nagu „kaugus linna keskpunktist”). Kuid hiljem nĂ€itan ma, et need toimivad suure kaardinaalsusega veergude puhul samuti suurepĂ€raselt.

Vaatame lihtsaimat bitmap-indeksi nÀidet.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Kujutage ette, et meil on nimekiri Moskva restoranidest, millel on binaarsed omadused nagu need:

  • lĂ€hedal metroo (near metro);
  • on privaatne parkla (has private parking);
  • on terrass (has terrace);
  • on vĂ”imalik broneerida laud (accepts reservations);
  • sobib taimetoitlastele (vegan friendly);
  • kallis (expensive).

Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Andke igale restoranile jĂ€rjekorranumber alates 0 ja reserveerime mĂ€lu 6 bitmapi jaoks (ĂŒks igas omaduses). SeejĂ€rel tĂ€idame need bitmaps sĂ”ltuvalt sellest, kas restoran omab antud omadust vĂ”i mitte. Kui restoranil 4 on terrass, siis bit nr 4 bitmapsis „on terrass” seatakse 1 (kui terrassi pole, siis 0).
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
NĂŒĂŒd on meil kĂ”ige lihtsam vĂ”imalik bitmap-indeks, ja me saame seda kasutada kĂŒsimustele vastamiseks, nagu:

  • „NĂ€ita mulle restorane, mis sobivad taimetoitlastele”;
  • „NĂ€ita mulle odavaid restorane terrassiga, kus on vĂ”imalik broneerida laud”.

Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Kuidas? Vaatame. Esimene pĂ€ring on vĂ€ga lihtne. KĂ”ik, mida me vajame, on vĂ”tta bitmap „sobib taimetoitlastele” ja muuta see restoranide nimekirjaks, kelle bitid on seatud.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Teine pÀring on veidi keerulisem. Peame kasutama BIT operatsiooni NOT bitimapis "kallis", et saada odavate restoranide nimekiri, seejÀrel AND-ime selle "saab broneerida" bitimapiga ja AND-ime tulemuse "on terrass" bitimapiga. Tulemuseks olev bitimap sisaldab nimekirja asutustest, mis vastavad kÔigile meie kriteeriumidele. Sel juhul on see ainult restoran "Noorus".
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Siin on palju teooriat, kuid Àrge muretsege, me nÀeme varsti koodi.

Kus kasutatakse bitmap-indekseid?

Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Kui te "googeldaksite" bitmap-indekseid, siis 90% vastustest oleksid vahetult seotud Oracle DB-ga. Kuid teised andmebaasid toetavad kindlasti ka sellist Àgedat funktsiooni, eks?

Vaatame ĂŒle peamised kahtlusalused.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
MySQL ei toeta veel bitmap-indekseid, kuid on olemas ettepanek selle funktsiooni lisamiseks (https://dev.mysql.com/worklog/task/?id=1524).

PostgreSQL ei toeta bitmap-indekseid, kuid kasutab lihtsaid bitimappe ja bitoperatsioone mitmete teiste indeksite otsingutulemuste ĂŒhendamiseks.

Tarantoolil on bitset-indeksid, mis toetavad lihtsat otsingut nende kaudu.

Redis'il on lihtsad bitivÀljad (https://redis.io/commands/bitfield) ilma vÔimaluseta nende kaudu otsida.

MongoDB ei toeta veel bitmap-indekseid, kuid ka selle jaoks on olemas ettepanek selle funktsiooni lisamiseks. https://jira.mongodb.org/browse/SERVER-1723

Elasticsearch kasutab bitimappe sees. (https://www.elastic.co/blog/frame-of-reference-and-roaring-bitmaps).

Bitmap-indeksid Go-s: otsimine metsiku kiirusel

  • Kuid meie majas on uus naaber: Pilosa. See on uus mitte-relationaalne andmebaas, mis on kirjutatud Go keeles. See sisaldab ainult bitmap-indekseid ja pĂ”hineb tĂ€ielikult nende peal. RÀÀgime temast hiljem.

TĂ€itmine Go keeles

Aga miks bitmap-indekseid nii harva kasutatakse? Enne sellele kĂŒsimusele vastamist tahaksin nĂ€idata teile vĂ€ga lihtsa bitmap-indeksi rakendust Go keeles.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Bitimapid koosnevad tegelikult lihtsalt andmeplokkidest. Go-s kasutame selleks baitide slice'e.

Meil on ĂŒks bitimap ĂŒhe restorani omaduse jaoks, ja iga bit bitimapis nĂ€itab, kas konkreetses restoranis on see omadus vĂ”i mitte.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Me vajame kahte abifunktsiooni. Üks neist kasutatakse meie bitmapside tĂ€itmiseks juhuslike andmetega. Juhuslike, kuid teatud tĂ”enĂ€osusega, et restoranil on iga omadus. NĂ€iteks arvan, et Moskvas on vĂ€ga vĂ€he restorane, kus ei saa lauda broneerida, ja mulle tundub, et umbes 20% asutustest sobivad taimetoitlastele.

Teine funktsioon muundab bitmapi restoranide nimekirjaks.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Et vastata pÀringule "NÀita mulle odavaid restorane, kus on terrass ja kus saab lauda broneerida", vajame kahte bititegevust: NOT ja AND.

Saame meie koodi veidi lihtsustada, kasutades keerukamat operaatori AND NOT.

Meil on igasuguste nende tegevuste jaoks funktsioonid. MĂ”lemad lĂ€bivad viipeid, vĂ”tavad vastavad elemendid igaĂŒhes ning ĂŒhendavad need bititegevuse abil ja panevad tulemuse tulemuslikku viipesse.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Ja nĂŒĂŒd saame kasutada meie bitmapsid ja funktsioone, et vastata otsingupĂ€ringule.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
JÔudlus ei ole nii kÔrge, isegi hoolimata sellest, et funktsioonid on vÀga lihtsad ja me oleme oluliselt kokku hoidnud, kuna ei tagastanud igal funktsiooni kutsumisel uut tulemuslikku viipi.

PĂ€rast mĂ”ningast profilimist pprof-iga mĂ€rkasin, et Go kompilaator jĂ€ttis ĂŒhe vĂ€ga lihtsa, kuid ÀÀrmiselt olulise optimeerimise vahele: funktsiooni inlining.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Fakt on selles, et Go kompilaator kardab kohutavalt viipeid, mis lÀbivad viipeid, ja keelab kategooriliselt inlining funktsioonide jaoks, mis sisaldavad selliseid silke.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Aga mina ei karda ja saan petta kompilaatorit, kasutades goto silmuse asemel, nagu vanad head ajad.

Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Bitmap-indeksid Go-s: otsimine metsiku kiirusel

Ja nagu nĂ€ete, kompilaator on nĂŒĂŒd rÔÔmuga inlining meie funktsiooni! LĂ”puks Ă”nnestub meil kokku hoida umbes 2 mikrosekundit. Pole paha!

Bitmap-indeksid Go-s: otsimine metsiku kiirusel

Teine kitsaskoht on lihtne nĂ€ha, kui vaatate assembleri vĂ€ljundit hoolikalt. Kompilaator lisas meie kĂ”ige kuumema silmuse sisse viipi piiride kontrolli. Fakt on selles, et Go on turvaline keel, kompilaator kardab, et minu kolm argumenti (kolm viipi) on erineva suurusega. Siis vĂ”ib teoreetiliselt tekkida niinimetatud puhveri ĂŒlevool (buffer overflow).

LÀhme rahustame kompilatsiooniprogrammi, nÀidates talle, et kÔikide lÔikude suurused on samad. Saame seda teha, lisades meie funktsiooni algusesse lihtsa kontrolli.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Seda nÀhes suudab kompilatsiooniprogramm rÔÔmuga kontrolli mööda lasta ning me sÀÀstame lÔpuks veel 500 nanosekundit.

Suured partiid

Olgu, oleme suutnud meie lihtsast rakendusest mingitki jÔudlust vÀlja pigistada, kuid see tulemus on tegelikult palju halvem, kui praeguse riistvara puhul vÔimalik oleks.

KĂ”ik, mida me teeme, on pĂ”hised bititegevused ning meie protsessorid tĂ€idavad neid vĂ€ga tĂ”husalt. Kuid kahjuks „toidame” oma protsessorit vĂ€ga vĂ€ikeste tööosadega. Meie funktsioonid teostavad toimingud baitide kaupa. Saame koodi vĂ€ga lihtsalt timmida, et see töötaks 8-baidiste tĂŒkkidega, kasutades UInt64 lĂ”ike.

Bitmap-indeksid Go-s: otsimine metsiku kiirusel

Nagu nÀete, kiirendas see vÀike muudatus meie programmi kaheksa korda, suurendades partiid kaheksa korda. Kasutame, vÔib öelda, lineaarset kasu.

Bitmap-indeksid Go-s: otsimine metsiku kiirusel

Assemblerskeemide rakendamine

Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Aga see pole veel lĂ”pp. Meie protsessorid saavad töötada 16, 32 ja isegi 64 baitiste tĂŒkkidega. Selliseid „laiade” toimingute nimetatakse single instruction multiple data (SIMD; ĂŒks kĂ€sk, palju andmeid), ja protsessi, millega kodeerimist selliselt muudetakse, et see kasutaks selliseid toiminguid, nimetatakse vektoriseerimiseks.

Kahjuks ei ole Go kompilaator vektoriseerimises just kiitust vÀÀrt. Praeguseks on ainus viis Go koodi vektoriseerimiseks luua ja sisestada andmed kÀsitsi Go assembleriga.

Bitmap-indeksid Go-s: otsimine metsiku kiirusel

Go assembler on kummaline olend. Teate kindlasti, et assembler on midagi, mis on tugevalt seotud arvuti arhitektuuriga, mille jaoks te kirjutate, kuid Go puhul pole see nii. Go assembler sarnaneb rohkem IRL (intermediate representation language) vÔi vahekeelele: see on praktiliselt platvormidevaheline. Rob Pike tegi sellel teemal suurepÀrase ettekanne esituse mÔned aastat tagasi GopherConil Denveris.

Lisaks sellele kasutab Go ebatavalist Plan 9 formaati, mis erineb ĂŒldtunnustatud AT&T ja Intel formaatidest.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Saab kindlalt öelda, et Go assembleri kÀsitsi kirjutamine ei ole just kÔige lÔbusam tegevus.

Aga Ônneks on olemas juba kaks kÔrgema taseme tööriista, mis aitavad meid Go assembleri kirjutamisel: PeachPy ja avo. MÔlemad tööriistad genereerivad Go assemblerit kÔrgema taseme koodist, mis on kirjutatud vastavalt Pythonis ja Go-s.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Need this utilities simplifies tasks like register allocation, writing loops, and overall simplifies the entry into the world of assembly programming in Go.

We'll be using avo, so our programs will be almost typical Go programs.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Here's what the simplest example of an avo program looks like. We have a main() function that defines an Add() function inside it, which is responsible for adding two numbers. There are helper functions to get parameters by name and to acquire one of the free and suitable CPU registers. Each CPU operation has a corresponding function in avo, as seen with ADDQ. Finally, we see a helper function to store the resulting value.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
By calling go generate, we will execute the program on avo and ultimately two files will be generated:

  • add.s with the resulting code in Go assembly;
  • stub.go with function headers to link the two worlds: Go and assembly.

Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Now that we've seen what avo does and how it works, let's take a look at our functions. I have implemented both scalar and vector (SIMD) versions of the functions.

First, let's look at the scalar versions.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
As in the previous example, we request a free and appropriate general-purpose register, and we don’t need to compute offsets and sizes for the arguments. All of that is handled by avo for us.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Previously we used labels and goto (or jumps) to boost performance and trick the Go compiler, but now we do it from the get-go. The thing is, loops are a higher-level concept. In assembly, we only have labels and jumps.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
The remaining code should already be familiar and clear. We emulate a loop with labels and jumps, take a small part of data from our two slices, combine them using a bitwise operation (AND NOT in this case) and then place the result in the resulting slice. That's it.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Here’s what the final code in assembly looks like. We didn't need to calculate offsets and sizes (highlighted in green) or track the used registers (highlighted in red).
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Kui vĂ”rrelda assembleri rakenduse jĂ”udlust parima Go rakenduse jĂ”udlusega, siis nĂ€eme, et need on samad. Ja see on ootuspĂ€rane. Me ei teinud midagi erilist — me lihtsalt taasesitasime seda, mida teeks Go kompilaator.

Kahjuks ei saa me sundida kompilaatorit inline'ima meie assembleris kirjutatud funktsioone. Go kompilaatoril puudub praegu see vĂ”imalus, kuigi palve selle lisamiseks on eksisteerinud juba ĂŒsna kaua.

SeetÔttu ei suuda me saada mingit kasu vÀikestest funktsioonidest assembleris. Peame kas kirjutama suuri funktsioone, kasutama uut math/bits paketti vÔi vÀltima assemblerit.

Vaadakem nĂŒĂŒd meie funktsioonide vektorkoopiaid.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
KĂ€esolevas nĂ€ites otsustasin rakendada AVX2, seega kasutame 32-bitiste tĂŒkkidega töötavaid operatsioone. Koodistruktuur on vĂ€ga sarnane skalaari variandile: parameetrite laadimine, palve anda meile tasuta ĂŒldregister jne.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Üks uuendus on seotud sellega, et laiemad vektorioperatsioonid kasutavad spetsiaalseid laiu registreid. 32-bitiste tĂŒkkide puhul on need registrid, mille eelotsik on Y. Just seetĂ”ttu nĂ€ete koodis funktsiooni YMM(). Kui oleksin kasutanud AVX-512 64-bitiste tĂŒkkidega, siis oleks eelotsik Z.

Teine uuendus tuleneb sellest, et otsustasin kasutada optimeerimist, mida nimetatakse tsĂŒkli lahtimurdmiseks (loop unrolling), see tĂ€hendab, et tegin kaheksa tsĂŒkli operatsiooni kĂ€sitsi, enne kui hĂŒppasin tsĂŒkli algusesse. See optimeerimine vĂ€hendab koodis harude (branch) arvu ning on piiratud vaba registreid, mis on saadaval.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Aga kuidas on jÔudlusega? See on suurepÀrane! Saime kiiruskasvu ligikaudu seitsme vÔrra vÔrreldes parima lahendusega Go-s. Muljetavaldav, kas pole?
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Aga isegi seda rakendust oleks potentsiaalselt vÔimalik kiirendada, kasutades AVX-512, prefetƥimist vÔi JIT (just-in-time compiler) pÀringute planeerimise jaoks. Kuid see on juba tÀiesti eraldi ettekande teema.

Bitmap-indeksite probleemid

NĂŒĂŒd, kui oleme vaadanud Go lihtsat bitmap-indeksi rakendust ja palju efektiivsemat assembleris, rÀÀgime lĂ”puks sellest, miks bitmap-indeksid on nii harva kasutusel.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Vanades teadusartiklites mainitakse bitmap-indeksite kolme probleemi, kuid uuemad teadusartiklid ja mina vĂ€idame, et need on juba aegunud. Ärme sĂŒvene sĂŒgavale igasse neist probleemidest, vaid kĂ€sitleme neid pinnapealselt.

Suure kardinaalsuse probleem

Nii ĂŒtlevad meile, et bitmap-indeksid sobivad ainult vĂ€ikese kardinaalsusega vĂ€ljadele, st vĂ€ljadele, millel on vĂ€he vÀÀrtusi (nt sugu vĂ”i silmade vĂ€rv), ja pĂ”hjus on see, et tavaline esitus nende vĂ€ljade puhul (ĂŒks bitt vÀÀrtuse kohta) suurte kardinaalsuste korral koosneb liiga suurest mahust ning pealegi on need bitmap-indeksid halvasti (harva) tĂ€idetud.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
MĂ”nikord vĂ”ime kasutada teistsugust esitust, nĂ€iteks standardset, mida me kasutame arvude esitlemiseks. Kuid alles tihendamisalgoritmide ilmumine muutis kĂ”ike. Viimase paarikĂŒmne aasta jooksul on teadlased ja uurijad vĂ€lja mĂ”elnud palju tihendamisalgoritme bitmapide jaoks. Nende peamine eelis on see, et bitmapide dekopeerimine pole bititegevuste lĂ€biviimiseks vajalik – me saame teostada bititegevusi otse tihendatud bitmapide peal.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Viimasel ajal on hakanud ilmuma ka hĂŒbriidmeetodeid, nagu nĂ€iteks roaring bitmapid. Need kasutavad samaaegselt kolme erinevat esitusviisi bitmapide jaoks – otseselt bitmapid, massiivid ja nn bitituksid – ja tasakaalustavad nende vahel, et maksimeerida jĂ”udlust ja minimeerida mĂ€lutarvet.

Saate kohtuda roaring bitmapidega kÔige populaarsemates rakendustes. Juba on olemas tohutult palju teostusi erinevates programmeerimiskeeltes, sealhulgas rohkem kui kolm teostust Go jaoks.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Veel ĂŒks lĂ€henemine, mis vĂ”ib aidata meil toime tulla suure kardinaalsusega, nimetatakse rĂŒhmitamiseks (binning). Kujutage ette, et teil on vĂ€li, mis esindab inimese pikkust. Pikkus on ujuvpunktiga arv, kuid meie, inimesed, ei mĂ”tle sellele niimoodi. Meie jaoks pole vahet 185,2 cm ja 185,3 cm pikkuse vahel.

Sellega saame sarnased vÀÀrtused rĂŒhmitada rĂŒhmadesse, mille vahemik on 1 cm.

Ja kui me teame, et vĂ€ga vĂ€hesel inimesel on pikkus alla 50 cm vĂ”i ĂŒle 250 cm, siis saame pĂ”himĂ”tteliselt muuta vĂ€ljad, millel on lĂ”pmatu kardinaalsus, vĂ€ljadeks, mille kardinaalsus on umbes 200 vÀÀrtust.

Muidugi, vajadusel saame teha tÀiendavat filtreerimist ka hiljem.

Suur lÀbilaskevÔime probleem

JÀrgmine probleem bitmap-indeksite puhul on see, et nende uuendamine vÔib olla vÀga kulukas.

Andmebaasid peavad vĂ”imaldama andmete vĂ€rskendamist hetkel, kui potentsiaalselt sada muud pĂ€ringut otsivad neid andmeid. Me vajame lukke, et vĂ€ltida andmete ĂŒheaegse juurdepÀÀsu probleeme vĂ”i muid jagatud juurdepÀÀsu probleeme. Ja seal, kus on ĂŒks suur lukustus, tekib probleem — lukustuskonkurents, kui see lukustus muutub kitsaskohaks.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Seda probleemi saab lahendada vÔi vÀltida andmete ƥardimise vÔi versiooniindeksite kasutamise kaudu.

Ć ardimine on lihtne ja teadaolev mĂ”isted. Saate ĆĄardida bitmap-indeksi nii, nagu ĆĄardite kĂ”iki teisigi andmeid. Ühe suure lukustuse asemel saate hulga vĂ€ikeseid lukustusi ja seega vĂ€ltida lukustuskonkurentsi.

Teine viis probleemi lahendamiseks on versiooniga indeksite kasutamine. Te vĂ”ite omada ĂŒhte indeksikoorust, mida kasutate otsimiseks vĂ”i lugemiseks, ja ĂŒhte – kirjutamiseks vĂ”i uuendamiseks. Ja igal teatud ajavahemikul (nĂ€iteks iga 100 ms vĂ”i 500 ms) teete nende koopiad ja vahetate neid. Loomulikult on see lĂ€henemine rakendatav ainult siis, kui teie rakendus suudab töötada pisut hilinenud otsingute indeksiga.

Nende kahte lÀhenemist saab kasutada samaaegselt: teil vÔib olla ƥarditud versiooniga indeks.

TÀpsemad pÀringud

Viimane probleem bitmap-indeksite puhul on see, et nagu meile öeldakse, sobivad need halvasti keerukamate pĂ€ringutĂŒĂŒpide jaoks, nĂ€iteks „vahemiku” pĂ€ringud.

TĂ”epoolest, kui sellele mĂ”elda, ei sobi bitilised operatsioonid nagu AND, OR jne vĂ€ga hĂ€sti pĂ€ringute jaoks, nagu „NĂ€ita mulle hotelle, mille toa hind on vahemikus 200 kuni 300 dollarit öö kohta.”
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Naive ja vÀga mÔttetu lahendus oleks vÔtta tulemused iga dollari vÀÀrtuse jaoks ja liita need bitiliselt operatsiooniga OR.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Veidi paremini lahenduseks oleks rĂŒhmitamine. NĂ€iteks 50 dollari kaupa. See kiirendaks meie protsessi 50 korda.

Aga probleem lahendatakse lihtsalt esitusviisi kasutamisega, mis on loodud spetsiaalselt selliste pÀringute jaoks. Teadustöös nimetatakse seda vahemiku kodeeritud bitmapideks.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Sellises esitusviisis me ei tĂ€hista lihtsalt ĂŒhte bitti mĂ”ne vÀÀrtuse jaoks (nĂ€iteks 200), vaid tĂ€histame seda vÀÀrtust ja kĂ”ike, mis on kĂ”rgem. 200 ja kĂ”rgem. Sama kehtib 300 kohta: 300 ja kĂ”rgem. Ja nii edasi.

Seda esitusviisi kasutades saame vastata sellisele otsingupÀringule, lÀbides indeksi vaid kaks korda. Esiteks saame hotellide nimekirja, kus hind on alla 300 dollari, ja seejÀrel eemaldame need, kus hind on alla 199 dollari. Valmis.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Te ĂŒllatute, kuid isegi geopĂ€ringud on vĂ”imalikud bitmap-indeksite kasutamisega. Nipp on kasutada geoesitust, mis ĂŒmbritseb teie koordinaati geomeetrilise kujundiga. NĂ€iteks Google'i S2. Kujund tuleb olla vĂ”imalik esitada kolmest vĂ”i enamast ĂŒksteisega ristuvatest joonest, mida saab nummerdada. Nii saame meie geopĂ€ringu muuta mitmeks „vahepealseks“ pĂ€ringuks (leitud numeeritud joonte jĂ€rgi).

Valmis lahendused

Loodan, et ma pakkusin teile veidi huvi ja teil on nĂŒĂŒd uus kasulik tööriist oma arsenalis. Kui kunagi tekib vajadus midagi sellist teha, teate, millise suuna poole vaadata.

Kuid mitte kÔigil ei ole aega, kannatlikkust ja ressursse bitmap-indeksite loomiseks nullist. Eriti edasijÔudnud, mis kasutavad nÀiteks SIMD-d.

Õnneks on olemas mitmeid valmislahendusi, mis aitavad teid.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel

Roaring bitmaapid

Esiteks on see roaring bitmaps teek, millest olen juba rÀÀkinud. See sisaldab kÔiki vajalikke konteinerite ja bititegevuste komplekse, mida vajate tÀieliku bitmap-indeksi loomiseks.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Kahjuks ei kasuta praegu ĂŒkski Go teostus SIMD-d, mistĂ”ttu on Go teostused vĂ€hem jĂ”udlikud, vĂ”rreldes nĂ€iteks C-teostustega.

Pilosa

Teine toode, mis vĂ”ib teid aidata, on andmebaas Pilosa, millel on sisuliselt ainult bitmap-indeksid. See on suhteliselt uus lahendus, kuid see vĂ”idab sĂŒdameid tohutu kiirus.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Pilosa kasutab endas roaring bitmaapeid ja annab teile vĂ”imaluse neid kasutada, lihtsustades ja seletades kĂ”iki neid asju, millest ma eespool rÀÀkisin: rĂŒhmitamine, vahemiku kodeeritud bitmaps, vĂ€lja mĂ”isted jne.

Vaadake kiire ĂŒle Pilosa kasutamise nĂ€ide, et vastata kĂŒsimusele, mis on teile juba tuttav.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
NÀide sarnaneb vÀga sellele, mida olete varem nÀinud. Loome kliendi Pilosa serverisse, loome indeksit ja vajalikud vÀljad, seejÀrel tÀidame oma vÀljad juhuslike andmetega tÔenÀosustega ja lÔpuks teeme tuttava pÀringu.

PÀrast seda kasutame NOT vÀljal "expensive", seejÀrel ristame tulemuse (vÔi AND-ime) vÀlja "terrace" ja vÀlja "reservations". Ja lÔpuks saame lÔpptulemuse.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Loodan siiralt, et peagi ilmuvad sellised uued indeksitĂŒĂŒbid nagu bitmap-indeksid ka andmebaasidesse nagu MySQL ja PostgreSQL.
Bitmap-indeksid Go-s: otsimine metsiku kiirusel

KokkuvÔte

Bitmap-indeksid Go-s: otsimine metsiku kiirusel
Kui te pole veel magama jÀÀnud, siis aitĂ€h. Peasin kĂ€sitlema paljusid teemasid lĂŒhidalt piiratud aja tĂ”ttu, kuid loodan, et ettekande sisu oli kasulik ja vĂ”ib-olla isegi motiveeriv.

Bitmap-indeksite olemasolust tasub teada isegi siis, kui need ei ole praegu teile vajalikud. Las need olla veel ĂŒks tööriist teie tööriistakastis.

Vaatasime erinevaid nippe Go jÔudluse parandamiseks ja neid asju, millega Go kompilaator praegu eriti hÀsti toime ei tule. See on tÔeliselt kasulik teadmine iga Go programmeerija jaoks.

See on kÔik, mida soovisin jagada. AitÀh!

Allikas: habr.com

Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster