Bitmap-yndeksen yn Go: sykje op wylde snelheid

Bitmap-yndeksen yn Go: sykje op wylde snelheid

ynlieding

Ik joech dit rapport yn it Ingelsk op de GopherCon Ruslân 2019 konferinsje yn Moskou en yn it Russysk op in moeting yn Nizjni Novgorod. Wy prate oer in bitmap-yndeks - minder gewoan as B-beam, mar net minder ynteressant. Diele opname taspraken op de konferinsje yn it Ingelsk en tekst transkripsjes yn it Russysk.

Wy sille sjen nei hoe't in bitmap-yndeks wurket, wannear't it better is, wannear't it slimmer is as oare yndeksen, en yn hokker gefallen is it signifikant flugger as har; Litte wy sjen hokker populêre DBMS's al bitmap-yndeksen hawwe; Litte wy besykje ús eigen te skriuwen yn Go. En "foar dessert" sille wy klearmakke biblioteken brûke om ús eigen supersnelle spesjalisearre database te meitsjen.

Ik hoopje wirklik dat myn wurken nuttich en ynteressant foar jo sille wêze. Go!

Ynlieding


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

Hoi allegearre! It is seis jûns en wy binne allegear superwurch. Geweldige tiid om te praten oer saaie teory fan database-yndeks, krekt? Sit gjin soargen, ik sil hjir en dêr in pear rigels boarnekoade hawwe. 🙂

Alle grappen oan 'e kant, it rapport is propfol ynformaasje, en wy hawwe net folle tiid. Dus litte wy begjinne.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Hjoed sil ik prate oer it folgjende:

  • wat binne yndeksen;
  • wat is in bitmap-yndeks;
  • wêr't it wurdt brûkt en wêr't it NET brûkt wurdt en wêrom;
  • ienfâldige ymplemintaasje yn Go en in bytsje striid mei de gearstaller;
  • wat minder ienfâldich, mar folle mear produktive ymplemintaasje yn Go assembler;
  • "problemen" fan bitmap-yndeksen;
  • besteande ymplemintaasjes.

Dus wat binne yndeksen?

Bitmap-yndeksen yn Go: sykje op wylde snelheid

De yndeks is in aparte gegevensstruktuer dy't wy njonken de haadgegevens ûnderhâlde en bywurkje. It wurdt brûkt om it sykjen te fersnellen. Sûnder yndeksen soe sykjen nedich wêze om de gegevens folslein troch te gean (in proses neamd folsleine scan), en dit proses hat lineêre algoritmyske kompleksiteit. Mar databases befetsje normaal enoarme hoemannichten gegevens en lineêre kompleksiteit is te stadich. Ideal soene wy ​​in logaritmyske of konstante krije.

Dit is in heul kompleks ûnderwerp, fol mei subtiliteiten en ôfwikselingen, mar nei it besjen fan tsientallen jierren fan databaseûntwikkeling en ûndersyk, bin ik ree om te sizzen dat d'r mar in pear breed brûkte oanpak binne foar it meitsjen fan database-yndeksen.

Bitmap-yndeksen yn Go: sykje op wylde snelheid

De earste oanpak is om de sykromte hiërargysk te ferminderjen, de sykromte te dielen yn lytsere dielen.

Wy dogge dit normaal mei ferskate soarten beammen. In foarbyld soe wêze in grutte doaze fan materialen yn jo kast dat befettet lytsere doazen fan materialen ferdield yn ferskate ûnderwerpen. As jo ​​​​materialen nedich binne, sille jo se wierskynlik sykje yn in doaze dy't "Materialen" seit ynstee fan ien dy't "Cookies" seit, krekt?

Bitmap-yndeksen yn Go: sykje op wylde snelheid

De twadde oanpak is om fuortendaliks it winske elemint of groep eleminten te selektearjen. Wy dogge dit yn hash-kaarten of omkearde yndeksen. It brûken fan hash-kaarten is heul gelyk oan it foarige foarbyld, mar ynstee fan in doaze mei doazen, hawwe jo in boskje lytse doazen fan lêste items yn jo kast.

Bitmap-yndeksen yn Go: sykje op wylde snelheid

De tredde oanpak is om de needsaak foar sykjen te eliminearjen. Wy dogge dit mei help fan Bloom-filters of koekoeksfilters. De earsten jouwe direkt in antwurd, sadat jo net hoege te sykjen.

Bitmap-yndeksen yn Go: sykje op wylde snelheid

De lêste oanpak is om folslein gebrûk te meitsjen fan alle krêft dy't moderne hardware ús jout. Dit is krekt wat wy dogge yn bitmap-yndeksen. Ja, by it brûken fan se moatte wy soms troch de hiele yndeks gean, mar wy dogge it super effisjint.

Lykas ik sei, is it ûnderwerp fan databankyndeksen grut en fol mei kompromissen. Dit betsjut dat wy soms ferskate oanpakken tagelyk brûke kinne: as wy it sykjen noch flugger meitsje moatte, of as wy alle mooglike syktypen dekke moatte.

Hjoed sil ik prate oer de minst bekende oanpak fan dizze - bitmap-yndeksen.

Wa bin ik om oer dit ûnderwerp te praten?

Bitmap-yndeksen yn Go: sykje op wylde snelheid

Ik wurkje as teamlieder by Badoo (miskien binne jo bekender mei ús oare produkt, Bumble). Wy hawwe al mear as 400 miljoen brûkers oer de hiele wrâld en in protte funksjes dy't de bêste wedstriid foar har selektearje. Wy dogge dit mei help fan oanpaste tsjinsten, ynklusyf bitmap-yndeksen.

Dus wat is in bitmap-yndeks?

Bitmap-yndeksen yn Go: sykje op wylde snelheid
Bitmap-yndeksen, lykas de namme al fermoeden docht, brûke bitmaps of bitsets om in sykyndeks te ymplementearjen. Fanút in fûgelperspektyf bestiet dizze yndeks út ien of mear sokke bitmaps dy't alle entiteiten (lykas minsken) en harren eigenskippen of parameters (leeftyd, eachkleur, ensfh.) fertsjintwurdigje, en in algoritme mei bitoperaasjes (AND, OR, NOT ) om de sykfraach te beantwurdzjen.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Wy wurde ferteld dat bitmap-yndeksen it meast geskikt binne en tige prestearjend binne foar gefallen wêr't sykopdrachten binne dy't fragen kombinearje oer in protte kolommen mei lege kardinaliteit (tink "eachkleur" of "echtlike stân" tsjin sokssawat as "ôfstân fan stedssintrum"). Mar ik sil letter sjen litte dat se ek goed wurkje foar kolommen mei hege kardinaliteit.

Litte wy nei it ienfâldichste foarbyld fan in bitmap-yndeks sjen.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Stel jo foar dat wy in list hawwe fan Moskou restaurants mei binêre eigenskippen lykas dizze:

  • tichtby metro;
  • der is privee parkeare;
  • der is in veranda (hat terras);
  • do kinst reservearje in tafel (akseptearret reservearrings);
  • geskikt foar fegetariërs (veganfreonlik);
  • djoer (djoer).

Bitmap-yndeksen yn Go: sykje op wylde snelheid
Litte wy elk restaurant in folchoardernûmer jaan fanôf 0 en ûnthâlde foar 6 bitmaps (ien foar elke karakteristyk). Wy sille dan dizze bitmaps ynfolje ôfhinklik fan oft it restaurant dit pân hat of net. As restaurant 4 hat in veranda, dan bit No.. 4 yn de "hat in veranda" bitmap wurdt ynsteld op 1 (as der gjin veranda, dan op 0).
Bitmap-yndeksen yn Go: sykje op wylde snelheid
No hawwe wy de ienfâldichste bitmap-yndeks mooglik, en wy kinne it brûke om fragen te beantwurdzjen lykas:

  • "Lit my fegetarysk-friendly restaurants sjen";
  • "Lit my goedkeape restaurants sjen mei in veranda wêr't jo in tafel kinne reservearje."

Bitmap-yndeksen yn Go: sykje op wylde snelheid
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Hoe? Litte wy ris sjen. It earste fersyk is heul ienfâldich. Alles wat wy hoege te dwaan is de "fegetaryske freonlike" bitmap te nimmen en it te feroarjen yn in list mei restaurants wêrfan de bits binne bleatsteld.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Bitmap-yndeksen yn Go: sykje op wylde snelheid
It twadde fersyk is in bytsje yngewikkelder. Wy moatte de NOT bitmap brûke op 'e "djoere" bitmap om in list mei goedkeape restaurants te krijen, dan EN it mei de "kin ik in tafel reservearje" bitmap en EN it resultaat mei de "d'r is in veranda" bitmap. De resultearjende bitmap sil in list mei fêstigings befetsje dy't foldogge oan al ús kritearia. Yn dit foarbyld is dit allinich it restaurant Yunost.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Bitmap-yndeksen yn Go: sykje op wylde snelheid
D'r is in protte teory belutsen, mar meitsje jo gjin soargen, wy sille de koade heul gau sjen.

Wêr wurde bitmap-yndeksen brûkt?

Bitmap-yndeksen yn Go: sykje op wylde snelheid
As jo ​​Google bitmap yndeksearret, sil 90% fan 'e antwurden op ien of oare manier relatearre wurde oan Oracle DB. Mar oare DBMS's stypje wierskynlik ek sa'n cool ding, toch? Net wirklik.

Lit ús gean troch de list fan wichtichste fertochten.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
MySQL stipet noch gjin bitmap-yndeksen, mar d'r is in foarstel dat suggerearret dizze opsje ta te foegjen (https://dev.mysql.com/worklog/task/?id=1524).

PostgreSQL stipet gjin bitmap-yndeksen, mar brûkt ienfâldige bitmaps en bitoperaasjes om sykresultaten te kombinearjen oer meardere oare yndeksen.

Tarantool hat bitset-yndeksen en stipet ienfâldige sykopdrachten op har.

Redis hat ienfâldige bitfjilden (https://redis.io/commands/bitfield) sûnder de mooglikheid om har te sykjen.

MongoDB stipet noch gjin bitmap-yndeksen, mar d'r is ek in foarstel dat suggerearret dat dizze opsje wurdt tafoege https://jira.mongodb.org/browse/SERVER-1723

Elasticsearch brûkt ynterne bitmaps (https://www.elastic.co/blog/frame-of-reference-and-roaring-bitmaps).

Bitmap-yndeksen yn Go: sykje op wylde snelheid

  • Mar der is in nije buorfrou yn ús hûs ferskynde: Pilosa. Dit is in nije net-relasjonele databank skreaun yn Go. It befettet allinich bitmap-yndeksen en basearret alles op har. Wy prate der noch efkes oer.

Implementaasje yn Go

Mar wêrom wurde bitmap-yndeksen sa komselden brûkt? Foardat ik dizze fraach beantwurdzje, wol ik jo graach sjen litte hoe't jo in heul ienfâldige bitmap-yndeks yn Go kinne ymplementearje.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Bitmaps binne yn wêzen gewoan stikken gegevens. Litte wy yn Go byte-slices brûke foar dit.

Wy hawwe ien bitmap foar ien restaurant karakteristyk, en elk bit yn de bitmap jout oan oft in bepaald restaurant hat dizze eigenskip of net.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Wy sille twa helperfunksjes nedich wêze. Ien sil brûkt wurde om ús bitmaps te foljen mei willekeurige gegevens. Random, mar mei in bepaalde kâns dat it restaurant hat elk eigendom. Bygelyks, ik leau dat d'r in pear restaurants yn Moskou binne wêr't jo gjin tafel kinne reservearje, en it liket my dat sawat 20% fan 'e festigingen geskikt binne foar fegetariërs.

De twadde funksje sil de bitmap konvertearje yn in list mei restaurants.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Om de fraach te beantwurdzjen "Lit my goedkeape restaurants sjen dy't in patio hawwe en reservearje kinne," hawwe wy twa bits operaasjes nedich: NOT en AND.

Wy kinne ús koade in bytsje ferienfâldigje troch de kompleksere EN NOT-operator te brûken.

Wy hawwe funksjes foar elk fan dizze operaasjes. Beide geane troch de plakjes, nimme de oerienkommende eleminten fan elk, kombinearje se mei in bytsje operaasje en set it resultaat yn 'e resultearjende plak.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
En no kinne wy ​​ús bitmaps en funksjes brûke om de sykfraach te beantwurdzjen.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Prestaasje is net sa heech, ek al binne de funksjes heul ienfâldich en wy hawwe in protte jild besparre troch gjin nije resultearjende slice werom te jaan elke kear as de funksje waard neamd.

Nei it dwaan fan in bytsje profilearjen mei pprof, fernaam ik dat de Go-kompiler ien heul ienfâldige, mar heul wichtige optimalisaasje mist: funksje-ynlining.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
It feit is dat de Go-kompilator is ferskriklik bang foar loops dy't gean troch plakjes, en categorically wegeret te ynline funksjes dy't befetsje sokke loops.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Mar ik bin net bang en ik kin de gearstaller narje troch goto te brûken ynstee fan in loop, lykas yn 'e goede âlde dagen.

Bitmap-yndeksen yn Go: sykje op wylde snelheid
Bitmap-yndeksen yn Go: sykje op wylde snelheid

En, lykas jo kinne sjen, no sil de kompilator ús funksje lokkich ynline! As resultaat kinne wy ​​​​sawat 2 mikrosekonden besparje. Net min!

Bitmap-yndeksen yn Go: sykje op wylde snelheid

De twadde knelpunt is maklik om te sjen as jo nau sjogge nei de gearstallingsútfier. De gearstaller hat in stikgrinskontrôle tafoege direkt yn ús heulste lus. It feit is dat Go is in feilige taal, de gearstaller is bang dat myn trije arguminten (trije plakjes) binne fan ferskillende grutte. Dan komt der ommers in teoretyske mooglikheid fan it ûntstean fan in saneamde bufferoerlêst.

Litte wy de kompilator gerêststelle troch it sjen te litten dat alle plakjes deselde grutte binne. Wy kinne dit dwaan troch in ienfâldige kontrôle ta te foegjen oan it begjin fan ús funksje.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
As jo ​​​​dit sjogge, slacht de kompilator lokkich de kontrôle oer, en wy besparje úteinlik noch 500 nanosekonden.

Grutte bûter

Okee, it is ús slagge om wat prestaasjes út ús ienfâldige ymplemintaasje te drukken, mar dit resultaat is eins folle slimmer dan mooglik is mei hjoeddeistige hardware.

Alles wat wy dogge is basale bitoperaasjes, en ús processors fiere se heul effisjint út. Mar, spitigernôch, "fiere" wy ús prosessor mei heul lytse stikjes wurk. Us funksjes útfiere operaasjes op in byte-by-byte basis. Wy kinne ús koade heul maklik oanpasse om te wurkjen mei 8-byte-brokken mei UInt64-slices.

Bitmap-yndeksen yn Go: sykje op wylde snelheid

Lykas jo kinne sjen, fersnelle dizze lytse feroaring ús programma acht kear troch de batchgrutte mei acht kear te fergrutsjen. De winst kin sein wurde lineêr.

Bitmap-yndeksen yn Go: sykje op wylde snelheid

Implementaasje yn assembler

Bitmap-yndeksen yn Go: sykje op wylde snelheid
Mar dit is net it ein. Us processors kinne wurkje mei brokken fan 16, 32 en sels 64 bytes. Sokke "brede" operaasjes wurde ien ynstruksje meardere gegevens neamd (SIMD; ien ynstruksje, in protte gegevens), en it proses fan it transformearjen fan koade sadat it sokke operaasjes brûkt wurdt vectorization neamd.

Spitigernôch is de Go-kompiler fier fan poerbêst by vectorization. Op it stuit is de ienige manier om Go-koade te vektorisearjen om dizze operaasjes manuell te nimmen en te setten mei Go assembler.

Bitmap-yndeksen yn Go: sykje op wylde snelheid

Go assembler is in frjemd bist. Jo witte wierskynlik dat assemblagetaal iets is dat heul bûn is oan 'e arsjitektuer fan 'e kompjûter wêrfoar jo skriuwe, mar dat is net it gefal yn Go. Go assembler is mear as in IRL (tuskenfertsjintwurdigingstaal) of tuskentaal: it is praktysk platfoarmûnôfhinklik. Rob Pike joech in poerbêste prestaasje melde oer dit ûnderwerp ferskate jierren lyn by GopherCon yn Denver.

Derneist brûkt Go in ûngewoane Plan 9-formaat, dat ferskilt fan 'e algemien akseptearre AT&T- en Intel-formaten.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
It is feilich om te sizzen dat it skriuwen fan Go assembler mei de hân net it leukste is.

Mar, gelokkich, binne d'r al twa ark op heech nivo dy't ús helpe om Go assembler te skriuwen: PeachPy en avo. Beide nutsbedriuwen generearje Go-assembler fan koade op heger nivo skreaun yn respektivelik Python en Go.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Dizze nutsfoarsjenningen ferienfâldigje dingen lykas registerallokaasje, skriuwloops, en ferienfâldigje oer it algemien it proses om yn 'e wrâld fan assemblageprogrammearring yn Go te kommen.

Wy sille avo brûke, dus ús programma's sille hast gewoane Go-programma's wêze.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Dit is hoe't it ienfâldichste foarbyld fan in avo-programma derút sjocht. Wy hawwe in haadfunksje () dy't yn himsels de funksje Add () definiearret, wêrfan de betsjutting is om twa nûmers ta te foegjen. D'r binne hjir helpfunksjes om parameters by namme te krijen en ien fan 'e fergese en geskikte prosessorregisters te krijen. Eltse prosessor operaasje hat in oerienkommende funksje op avo, lykas sjoen yn ADDQ. Uteinlik sjogge wy in helperfunksje foar it bewarjen fan de resultearjende wearde.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Troch go generearje te roppen, sille wy it programma op avo útfiere en as gefolch wurde twa bestannen generearre:

  • add.s mei de resultearjende koade yn Go assembler;
  • stub.go mei funksje headers te ferbinen de twa wrâlden: Gean en assembler.

Bitmap-yndeksen yn Go: sykje op wylde snelheid
No't wy hawwe sjoen wat avo docht en hoe, litte wy nei ús funksjes sjen. Ik ymplementearre sawol skalêre en vector (SIMD) ferzjes fan de funksjes.

Litte wy earst nei de skalêre ferzjes sjen.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Lykas yn it foarige foarbyld, wy freegje om in fergees en jildich algemien doel register, wy hoege net te berekkenjen offsets en maten foar de arguminten. avo docht dit alles foar ús.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Wy brûkten eartiids labels en goto (of sprongen) om prestaasjes te ferbetterjen en de Go-kompiler te ferrifeljen, mar no dogge wy it fan it begjin ôf. It punt is dat syklusen in konsept op heger nivo binne. Yn assembler hawwe wy allinich labels en sprongen.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
De oerbleaune koade moat al fertroud en begryplik wêze. Wy emulearje in loop mei etiketten en sprongen, nimme in lyts stikje gegevens fan ús twa plakjes, kombinearje se mei in bytsje operaasje (EN NET yn dit gefal) en set it resultaat dan yn 'e resultearjende plak. Alle.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Dit is hoe't de definitive assemblerkoade derút sjocht. Wy hoegden net te berekkenjen offsets en maten (markearre yn grien) of folgje de registers brûkt (markearre yn read).
Bitmap-yndeksen yn Go: sykje op wylde snelheid
As wy de prestaasjes fan 'e ymplemintaasje fan assemblagetaal fergelykje mei de prestaasjes fan' e bêste ymplemintaasje yn Go, sille wy sjen dat it itselde is. En dit wurdt ferwachte. Wy hawwe ommers neat spesjaal dien - wy hawwe gewoan reprodusearre wat in Go-kompiler soe dwaan.

Spitigernôch kinne wy ​​de kompilator net twinge om ús funksjes yn assemblagetaal te ynline. De Go-kompiler hat op it stuit net sa'n funksje, hoewol d'r al in skoft in fersyk is om it ta te foegjen.

Dêrom is it ûnmooglik om te profitearjen fan lytse funksjes yn assemblagetaal. Wy moatte òf grutte funksjes skriuwe, of it nije math/bits-pakket brûke, of de assembler-taal omgean.

Litte wy no sjen nei de fektorferzjes fan ús funksjes.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Foar dit foarbyld haw ik besletten AVX2 te brûken, dus wy sille operaasjes brûke dy't operearje op 32-byte stikken. De struktuer fan 'e koade is heul ferlykber mei de skalêre ferzje: laden fan parameters, freegje om in fergees dielde register, ensfh.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Ien fan 'e ynnovaasjes is dat bredere fektoroperaasjes spesjale brede registers brûke. Yn it gefal fan 32-byte brokken, dit binne registers foarôfgeand mei Y. Dit is wêrom jo sjogge de YMM () funksje yn de koade. As ik AVX-512 brûkte mei 64-bit brokken, soe it foarheaksel Z wêze.

De twadde ynnovaasje is dat ik besleat om in optimalisaasje te brûken neamd loop unrolling, wat betsjut dat jo acht loopoperaasjes manuell dwaan foardat jo nei it begjin fan 'e loop springe. Dizze optimalisaasje ferleget it oantal tûken yn 'e koade, en wurdt beheind troch it oantal fergese registers beskikber.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
No, wat oer prestaasjes? Sy is prachtich! Wy hawwe in snelheid berikt fan sawat sân kear yn ferliking mei de bêste Go-oplossing. Yndrukwekkend, krekt?
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Mar sels dizze ymplemintaasje koe mooglik wurde fersneld troch it brûken fan AVX-512, prefetching of in JIT (just-in-time compiler) foar de query scheduler. Mar dit is grif in ûnderwerp foar in apart rapport.

Problemen mei bitmap-yndeksen

No't wy al sjoen hawwe nei in ienfâldige ymplemintaasje fan in bitmap-yndeks yn Go en in folle mear produktive ien yn assembly-taal, litte wy einlings prate oer wêrom't bitmap-yndeksen sa komselden wurde brûkt.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Aldere papieren neame trije problemen mei bitmap-yndeksen, mar nijere papieren en ik stelle dat se net mear relevant binne. Wy sille net djip yn elk fan dizze problemen dûke, mar sille se oerflakkich besjen.

It probleem fan hege kardinaliteit

Dat, wy wurde ferteld dat bitmap-yndeksen allinich geskikt binne foar fjilden mei lege kardinaliteit, dat is dyjingen dy't in pear wearden hawwe (bygelyks geslacht of eachkleur), en de reden is dat de gewoane fertsjintwurdiging fan sokke fjilden (ien) bit per wearde) yn it gefal fan hege kardinaliteit sil it te folle romte nimme en boppedat sille dizze bitmap-yndeksen min (selden) ynfolle wurde.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Soms kinne wy ​​​​in oare fertsjintwurdiging brûke, lykas de standert dy't wy brûke om nûmers te fertsjintwurdigjen. Mar it wie de komst fan kompresje-algoritmen dy't alles feroare. Yn 'e ôfrûne desennia binne wittenskippers en ûndersikers mei in grut oantal kompresjealgoritmen foar bitmaps kommen. Har wichtichste foardiel is dat it net nedich is om bitmaps te dekomprimearjen om bitoperaasjes út te fieren - wy kinne bitoperaasjes direkt op komprimearre bitmaps útfiere.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Koartlyn binne hybride oanpak begon te ferskinen, lykas roarende bitmaps. Se brûke tagelyk trije ferskillende foarstellings foar bitmaps - bitmaps sels, arrays en saneamde bitruns - en lykwicht tusken harren foar in maksimalisearjeknop prestaasjes en minimalisearje ûnthâld konsumpsje.

Jo kinne roarende bitmaps fine yn 'e populêrste applikaasjes. D'r binne al in grut oantal ymplemintaasjes foar in grut ferskaat oan programmeartalen, ynklusyf mear as trije ymplemintaasjes foar Go.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
In oare oanpak dy't ús kin helpe om te gean mei hege kardinaliteit wurdt binning neamd. Stel jo foar dat jo in fjild hawwe dat de hichte fan in persoan fertsjintwurdiget. Hichte is in driuwend puntnûmer, mar wy minsken tinke der net sa oan. Foar ús is der gjin ferskil tusken hichte 185,2 sm en 185,3 sm.

It docht bliken dat wy ferlykbere wearden kinne groepearje yn groepen binnen 1 sm.

En as wy ek witte dat hiel pear minsken koarter binne as 50 sm en langer as 250 sm, dan kinne wy ​​yn wêzen fan in fjild mei ûneinige kardinaliteit in fjild meitsje mei in kardinaliteit fan sa'n 200 wearden.

Fansels, as it nedich is, kinne wy ​​dêrnei ekstra filtering dwaan.

Problem mei hege bânbreedte

It folgjende probleem mei bitmap-yndeksen is dat it bywurkjen fan har heul djoer kin wêze.

Databanken moatte gegevens bywurkje kinne, wylst mooglik hûnderten oare fragen de gegevens sykje. Wy hawwe slûzen nedich om problemen te foarkommen mei tagelyk gegevenstagong of oare dielenproblemen. En dêr't der is ien grutte slot, der is in probleem - slot stride, doe't dit slot wurdt in knipehals.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Dit probleem kin wurde oplost of omseame troch it brûken fan sharding of it brûken fan ferzjes yndeksen.

Sharding is in ienfâldich en bekend ding. Jo kinne in bitmap-yndeks splitse lykas alle oare gegevens. Yn stee fan ien grutte slûs, do silst krije in boskje lytse slûzen en sa krije rid fan slot stride.

De twadde manier om it probleem op te lossen is it brûken fan ferzjes yndeksen. Jo kinne ien kopy hawwe fan 'e yndeks dy't jo brûke foar sykjen of lêzen, en ien dy't jo brûke foar skriuwen of bywurkjen. En ien kear yn in bepaalde perioade (bygelyks ien kear elke 100 ms of 500 ms) jo duplicate se en ruilje se. Fansels is dizze oanpak allinich fan tapassing yn gefallen wêr't jo applikaasje in wat efterbliuwende sykyndeks kin omgean.

Dizze twa oanpakken kinne tagelyk brûkt wurde: jo kinne in skerpe ferzje hawwe yndeks.

Mear komplekse fragen

It lêste probleem mei bitmap-yndeksen is dat wy wurde ferteld dat se net goed geskikt binne foar mear komplekse soarten fragen, lykas spanfragen.

Yndied, as jo der oer tinke, binne bitoperaasjes lykas AND, OR, ensfh.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
In naïve en heul ûnferstannige oplossing soe wêze om de resultaten foar elke dollarwearde te nimmen en se te kombinearjen mei in bitwize OR-operaasje.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
In wat bettere oplossing soe wêze om groepearring te brûken. Bygelyks, yn groepen fan 50 dollar. Dit soe ús proses mei 50 kear fersnelle.

Mar it probleem wurdt ek maklik oplost troch it brûken fan in werjefte dy't spesifyk makke is foar dit type oanfraach. Yn wittenskiplike papers wurdt it berik-kodearre bitmaps neamd.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Yn dizze foarstelling, wy sette net allinne in bytsje foar guon wearde (Bygelyks, 200), mar set dizze wearde en alles heger. 200 en boppe. Itselde foar 300: 300 en boppe. Ensafuorthinne.

Mei dizze fertsjintwurdiging kinne wy ​​​​dit soarte fan sykfraach beantwurdzje troch de yndeks mar twa kear troch te gean. Earst krije wy in list mei hotels wêr't de keamer minder as $ 300 kostet, en dan sille wy dejingen dêr't de keamerkosten minder as $ 199 binne, fuortsmite. Klear.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Jo sille ferrast wurde, mar sels geoqueries binne mooglik mei help fan bitmap-yndeksen. De trúk is om in geometryske foarstelling te brûken dy't jo koördinearje omgiet mei in geometryske figuer. Bygelyks, S2 fan Google. De figuer moat mooglik wurde fertsjintwurdige yn 'e foarm fan trije of mear krusende linen dy't nûmere wurde kinne. Op dizze manier kinne wy ​​ús geoquery omsette yn ferskate queries "langs de gat" (lâns dizze nûmere rigels).

Ready Solutions

Ik hoopje dat ik jo in bytsje ynteressearje en jo hawwe no in oar nuttich ark yn jo arsenal. As jo ​​oait sa'n ding moatte dwaan, sille jo witte hokker manier jo moatte sjen.

Net elkenien hat lykwols de tiid, geduld of boarnen om bitmap-yndeksen fanôf it begjin te meitsjen. Benammen mear avansearre, mei bygelyks SIMD.

Gelokkich binne d'r ferskate klearmakke oplossingen om jo te helpen.
Bitmap-yndeksen yn Go: sykje op wylde snelheid

Roaring bitmaps

As earste is d'r deselde brûzjende bitmapbibleteek wêr't ik al oer praat. It befettet alle nedige konteners en bitoperaasjes dy't jo nedich binne om in folsleine bitmap-yndeks te meitsjen.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Spitigernôch brûkt op it stuit gjin fan 'e Go-ymplemintaasjes SIMD, wat betsjut dat Go-ymplemintaasjes minder performant binne as bygelyks C-ymplemintaasjes.

Pilosa

In oar produkt dat jo kin helpe is de Pilosa DBMS, dy't eins allinich bitmap-yndeksen hat. Dit is in relatyf nije oplossing, mar it wint herten mei grutte snelheid.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Pilosa brûkt roaring bitmaps yntern en jout jo de mooglikheid om te brûken se, simplifies en ferklearret alle dingen ik praat oer hjirboppe: groepearring, berik-kodearre bitmaps, it konsept fan in fjild, etc.

Litte wy efkes sjen nei in foarbyld fan it brûken fan Pilosa om in fraach te beantwurdzjen wêrmei jo al bekend binne.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
It foarbyld is heul gelyk oan wat jo earder sjoen hawwe. Wy meitsje in kliïnt oan 'e Pilosa-tsjinner, meitsje in yndeks en de nedige fjilden, folje dan ús fjilden mei willekeurige gegevens mei kânsen en, úteinlik, útfiere de bekende query.

Dêrnei brûke wy NOT op it "djoere" fjild, dan krúst it resultaat (of EN it) mei it "terras" fjild en mei it "reservations" fjild. En as lêste krije wy it einresultaat.
Bitmap-yndeksen yn Go: sykje op wylde snelheid
Ik hoopje wirklik dat yn 'e oerienkommende takomst dit nije type yndeks ek sil ferskine yn DBMS's lykas MySQL en PostgreSQL - bitmap-yndeksen.
Bitmap-yndeksen yn Go: sykje op wylde snelheid

konklúzje

Bitmap-yndeksen yn Go: sykje op wylde snelheid
As jo ​​​​noch net yn 'e sliep fallen binne, tankewol. Ik moast in protte ûnderwerpen koart oanreitsje fanwegen beheinde tiid, mar ik hoopje dat it praat nuttich en miskien sels motivearjend wie.

Bitmap-yndeksen binne goed om oer te witten, sels as jo se no net nedich binne. Lit se in oar ark wêze yn jo toolbox.

Wy hawwe sjoen nei ferskate prestaasjetricks foar Go en dingen dy't de Go-kompiler noch net heul goed behannelet. Mar dit is absolút nuttich foar elke Go-programmeur om te witten.

Dat woe ik dy mar sizze. Dankewol!

Boarne: www.habr.com

Add a comment